pjfanning commented on code in PR #3652:
URL: https://github.com/apache/pekko/pull/3652#discussion_r4358141147


##########
remote/src/test/scala/org/apache/pekko/remote/artery/RemoteConnectionSpec.scala:
##########
@@ -31,14 +36,181 @@ class RemoteConnectionSpec extends 
ArteryMultiNodeSpec("pekko.remote.retry-gate-
 
   "Remoting between systems" should {
 
+    "handle uid collision when connection TO two systems with same uid" in {
+      val localProbe = new TestProbe(localSystem)
+      val localPort = 
RARP(localSystem).provider.getDefaultAddress.getPort().get
+
+      val conflictUid = localSystem.asInstanceOf[ExtendedActorSystem].uid + 1
+      val echoName = "echoA"
+
+      val remotePort1 = freePort()
+      val remoteSystem1 =
+        newRemoteSystem(extraConfig = Some(s"""
+          pekko.test-only-uid = $conflictUid
+          pekko.remote.artery.canonical.port=$remotePort1
+          """))
+      val remote1Probe = new TestProbe(remoteSystem1)
+
+      val remotePort2 = freePort()
+      val remoteSystem2 =
+        newRemoteSystem(extraConfig = Some(s"""
+          // same uid as remoteSystem1
+          pekko.test-only-uid = $conflictUid
+          pekko.remote.artery.canonical.port=$remotePort2
+          """))
+      val remote2Probe = new TestProbe(remoteSystem2)
+
+      localProbe.expectNoMessage(2.seconds)
+      localSystem.actorOf(TestActors.echoActorProps, echoName)
+      remoteSystem1.actorOf(TestActors.echoActorProps, echoName)
+      remoteSystem2.actorOf(TestActors.echoActorProps, echoName)
+
+      val selectionFromLocalToRemote1 =
+        
localSystem.actorSelection(s"pekko://${remoteSystem1.name}@localhost:$remotePort1/user/$echoName")
+      val selectionFromLocalToRemote2 =
+        
localSystem.actorSelection(s"pekko://${remoteSystem2.name}@localhost:$remotePort2/user/$echoName")
+      val selectionFromRemote1ToLocal =
+        
remoteSystem1.actorSelection(s"pekko://${localSystem.name}@localhost:$localPort/user/$echoName")
+      val selectionFromRemote2ToLocal =
+        
remoteSystem2.actorSelection(s"pekko://${localSystem.name}@localhost:$localPort/user/$echoName")
+
+      selectionFromLocalToRemote1.tell("ping1a", localProbe.ref)
+      localProbe.expectMsg(500.millis, "ping1a")
+
+      selectionFromRemote1ToLocal.tell("ping1b", remote1Probe.ref)
+      remote1Probe.expectMsg(500.millis, "ping1b")
+
+      EventFilter[UidCollisionException]().intercept {
+        selectionFromLocalToRemote2.tell("ping2a", localProbe.ref)
+        // doesn't get through
+        localProbe.expectNoMessage()
+      }(localSystem)
+      RARP(localSystem).provider.transport
+        .asInstanceOf[ArteryTransport]
+        .association(RARP(remoteSystem2).provider.getDefaultAddress)
+        .associationState
+        .uniqueRemoteAddressState() shouldBe UidUnknown // handshake not 
completed
+
+      EventFilter[UidCollisionException]().intercept {
+        selectionFromRemote2ToLocal.tell("ping2b", remote2Probe.ref)
+        // doesn't get through in other direction
+        remote2Probe.expectNoMessage()

Review Comment:
   Thanks, I reproduced this: a message from the colliding system reaches the 
receiver's actor, and the reply never returns. I don't think the receiver can 
fix it without either losing the healthy association or changing the wire 
format:
   - The envelope header identifies the sender system only by its uid. The 
decoder resolves that uid to the healthy association (`Codecs.scala`), and 
`InboundHandshake.isKnownOrigin` then accepts the message.
   - Inbound connections are merged (TCP `MergeHub`, or the shared Aeron 
stream) before decoding and `InboundHandshake`, so the receiver can't tell 
which connection a message came from.
   - Quarantining by uid would also cut off the healthy association.
   - The receiver can't tell the colliding peer to stop either: its outbound 
handshake to that peer never completes, so control messages to it are held back.
   
   As you noted, this isn't a regression: before this PR the same collision 
threw an `IllegalArgumentException` at the same point. In this PR, the 
mitigation is the second part, which generates much more unique uids, plus 
rejecting the colliding handshake cleanly. I've opened #3672 for a 
protocol-level fix (e.g. identifying the peer independently of the uid), which 
needs a rolling-upgrade plan. I haven't added a receiver-side non-delivery 
assertion, since it would fail until #3672 is resolved.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to