couchbase-lite-ios icon indicating copy to clipboard operation
couchbase-lite-ios copied to clipboard

Replicator error when connect a third device using Peer-to-Peer Sync and MultiPeerConnectivity framework.

Open GabrieleNardi opened this issue 4 years ago • 5 comments

Description Hi, I am using the Peer-to-Peer Sync to replicate Db changes among devices. Actually I am able to replicate data between two device, but when I connect a third device the replicator crashes.

Expected behavior Replication among the three or more devices without crashes.

Logs

Connected to session: <MCSession: 0x600002c3c320 MyPeerID = <MCPeerID: 0x600001f20990 DisplayName = iPhone 11> SecurityIdentity = (null) EncryptionPreference = None ConnectedPeers = (
    "<MCPeerID: 0x600001f3c4a0 DisplayName = iPhone 11 Pro>",
    "<MCPeerID: 0x600001f3c9b0 DisplayName = iPhone XS>"
) Delegate = <CouchbaseTest.MultiPeerConnectivityManager: 0x6000036182a0>>
Received: �=Profile�getCheckpoint�client�cp-MH1LMCIi3y1zKPIqxIV5S3TN+SA=�òÃý¬
2020-02-28 12:01:14.808357+0100 CouchbaseTest[75396:2202630] CouchbaseLite Network ERROR: {BLIPIO#3}==> litecore::blip::BLIPIO ->x-msg-endpt:////_blipsync @0x7f8bfeb188b8
2020-02-28 12:01:14.808495+0100 CouchbaseTest[75396:2202630] CouchbaseLite Network ERROR: {BLIPIO#3} Caught exception handling incoming BLIP message: BLIP protocol error: Bad incoming REQ #1 (already finished)
2020-02-28 12:01:14.808616+0100 CouchbaseTest[75396:2202630] CouchbaseLite Database WARNING: Caught unexpected C++ runtime_error("BLIP protocol error: Bad incoming REQ #1 (already finished)")
2020-02-28 12:01:14.808791+0100 CouchbaseTest[75396:2203037] CouchbaseLite Network WARNING: {C4SocketImpl#4}==> litecore::repl::C4SocketImpl x-msg-endpt:////_blipsync @0x7f8bfeb0b8e0
2020-02-28 12:01:14.808887+0100 CouchbaseTest[75396:2203037] CouchbaseLite Network WARNING: {C4SocketImpl#4} WebSocket closed abnormally with status 4002
2020-02-28 12:01:14.809313+0100 CouchbaseTest[75396:2203037] CouchbaseLite Replicator ERROR: {Repl#5}==> litecore::repl::Replicator /Users/gabrielenardi/Library/Developer/CoreSimulator/Devices/D8C68024-9B88-4C6F-94A4-0205CF17F1C3/data/Containers/Data/Application/9BB2A004-D5F6-468C-BD43-141D0AF5B7FC/Library/Application Support/CouchbaseLite/peerToPeerSync.cblite2/ ->x-msg-endpt:////_blipsync @0x7f8c0101c828
2020-02-28 12:01:14.809447+0100 CouchbaseTest[75396:2203037] CouchbaseLite Replicator ERROR: {Repl#5} Got LiteCore error: LiteCore error 10 "BLIP protocol error: Bad incoming REQ #1 (already finished)"
2020-02-28 12:01:14.809620+0100 CouchbaseTest[75396:2203037] CouchbaseLite Replicator ERROR: {Repl#5} Stopping due to fatal error: LiteCore error 10 "BLIP protocol error: Bad incoming REQ #1 (already finished)"

Platform:

  • Device: [iPhone XS, iPhone 11, iPhone 11 Pro]
  • OS: iOS13.3
  • Couchbase Version: CouchbaseLiteSwiftEnterprise 2.7.0

Additional context I got a live query in viewDidLoad who gets all messages stored in my DB. Below the code:

func getAllTextType(callback: @escaping(([DataChatMessage]) -> Void)) {
        
        let query = QueryBuilder.select(SelectResult.all())
            .from(DataSource.database(self.database))
            .where(Expression.property("type")
            .equalTo(Expression.string("text")))
        
        self.token = query.addChangeListener { (query) in
            
            let messages = query.results?.allResults().compactMap(ModelMapper.resultsToDataChatMessage).sorted(by: { $0.creationDate < $1.creationDate })
            messages.flatMap(callback)
        }
    }

GabrieleNardi avatar Feb 28 '20 11:02 GabrieleNardi

That's not a crash. The replicator stopped due to an error in the underlying framing protocol — most likely your P2P code is passing the wrong data.

BLIP protocol error: Bad incoming REQ #1 (already finished)

This error means it received a duplicate message ID. Make sure you're not passing along the same message twice, or passing a message to the wrong replicator instance.

snej avatar Mar 02 '20 18:03 snej

Thank you for the answer.

Im in this situation: Device A (ActivePeer) which start connection with Device B (PassivePeer).

Then how I should insert the third device? Can I directly connect to A? Making Device A being Active or Passive Peer for Device C?

I think the error comes because I'm trying to make a Multipeer chat, and every devices has all the history. So Device B and Device C trying to push to Device A the same messages. Can this cause the error?

Are there some updated examples of a Multipeer push and pull replication? I only found Photo-Drop but the code is obsolete (about 5 years ago).

PS: Can the the target of MessageEndpoint(uid:, target:, protocolType:, delegate:) be [MCPeerID]? Actually I have a single MCPeerID as target but I need the replication among multiple devices. (So I have a [ActivePeerConnection] in VC. The DB is a single instance, but there are many Replicator as connected devices.)

PPS: Have I to connect all device involved in replication before I create the connection by func createConnection(endpoint: MessageEndpoint) -> MessageEndpointConnection? Or I can add device to session even after the createConnection has triggered? Creating more than one Connection.

GabrieleNardi avatar Mar 03 '20 08:03 GabrieleNardi

Then how I should insert the third device? Can I directly connect to A? Making Device A being Active or Passive Peer for Device C?

It could be either ways when device A connects to C. I think the logic could be the same when A connects to B. The setup could be mesh that each device connects to each other or star which one device is a host like a sync server.

I think the error comes because I'm trying to make a Multipeer chat, and every devices has all the history. So Device B and Device C trying to push to Device A the same messages. Can this cause the error?

If it is the same document, there should be an issue. I think the error that you have is causing by sending a message to a wrong peer.

Are there some updated examples of a Multipeer push and pull replication? I only found Photo-Drop but the code is obsolete (about 5 years ago).

The example was based on 1.x solution. I don't think we have an example that uses MC. CC: @rajagp

PS: Can the the target of MessageEndpoint(uid:, target:, protocolType:, delegate:) be [MCPeerID]? Actually I have a single MCPeerID as target but I need the replication among multiple devices. (So I have a [ActivePeerConnection] in VC. The DB is a single instance, but there are many Replicator as connected devices.)

MessageEndpoint represents 1-1 connection between active peer (replicator) and message endpoint listener (like server). MessageEndpoint cannot connect to multiple message endpoint listeners. If you have one device acting like a host or server running message endpoint listener, the other devices will create replicator connecting to the listener.

The DB is a single instance, but there are many Replicator as connected devices.)

I seems like you should have it backward by having a message endpoint listener on one device and the other will have a replicator connecting to the listener.

PPS: Have I to connect all device involved in replication before I create the connection by func createConnection(endpoint: MessageEndpoint) -> MessageEndpointConnection? Or I can add device to session even after the createConnection has triggered? Creating more than one Connection.

The replicator will call createConnection(endpoint: MessageEndpoint) -> MessageEndpointConnection? to create a connection to the message endpoint listener. You cannot share the same connection with multiple peers. If you have multiple replicators, each replicator will create its own MessageEndpointConnection.

pasin avatar Mar 03 '20 18:03 pasin

If it is the same document, there should be an issue. I think the error that you have is causing by sending a message to a wrong peer.

So in my case where the most of documents are the same on all devices (group chat with 20-30 devices), how can I handle the replication among multiple peers?

To avoid the quoted case can I only create a chain of replication A <-> B <-> C... or maybe a star network where the center is passivePeer (server) and the other are activePeers (clients)?

Are there any other options?

GabrieleNardi avatar Mar 04 '20 09:03 GabrieleNardi