Copied from https://github.com/couchbase/couchbase-lite-java-ce-root/issues/13 :
A AbstractCBLWebSocket object is constructed with webSocket member var to be null, and it is not set until onOpen event listener is called when websocket handshake finishes (after the tcp connection establishes).
Couchbase lite core handles connection timeout (with a default value of 15), and it will eventually call AbstractCBLWebSocket.requestClose method to close it on timeout is detected.
Look at first several lines of this method, AbstractCBLWebSocket.requestClose, there's a shortcut return if webSocket is null, which is true when connection timeout happens. Okhttp know nothing about the request to close, it will keep trying (and retry) to connect.
And okhttp timeouts are explicitly set to 0 (because core would take charge), so it hangs for a very long time, maybe forever, even if the bad network recovers. Replicator is stuck in "connecting" state if we check from outside (sometimes "busy").
okhttp sometimes decides to stop and raise an exception in time, luckily, onFailure is called and end all this. (So we can know the failure from outside and restart replication)
There's another possibility that handshake finally succeeds after the core decide to close it because of timeout. I'm not sure what will happen then.