diff --git a/src/wormhole/test/test_wormhole.py b/src/wormhole/test/test_wormhole.py index a59280a..266bc5f 100644 --- a/src/wormhole/test/test_wormhole.py +++ b/src/wormhole/test/test_wormhole.py @@ -910,6 +910,40 @@ class Wormholes(ServerBase, unittest.TestCase): yield w1.close() yield w2.close() + @inlineCallbacks + def test_rx_dedup(self): + # Future clients will handle losing/reestablishing the Rendezvous + # Server connection by retransmitting messages, which will sometimes + # cause duplicate messages. Make sure this client can tolerate them. + # The first place this would fail was when the second copy of the + # incoming PAKE message was received, which would cause + # SPAKE2.finish() to be called a second time, which throws an error + # (which, being somewhat unexpected, caused a hang rather than a + # clear exception). + with mock.patch("wormhole.wormhole._Wormhole", MessageDoublingReceiver): + w1 = wormhole.wormhole(APPID, self.relayurl, reactor) + w2 = wormhole.wormhole(APPID, self.relayurl, reactor) + w1.set_code("123-purple-elephant") + w2.set_code("123-purple-elephant") + w1.send(b"data1"), w2.send(b"data2") + dl = yield self.doBoth(w1.get(), w2.get()) + (dataX, dataY) = dl + self.assertEqual(dataX, b"data2") + self.assertEqual(dataY, b"data1") + yield w1.close() + yield w2.close() + +class MessageDoublingReceiver(wormhole._Wormhole): + # we could double messages on the sending side, but a future server will + # strip those duplicates, so to really exercise the receiver, we must + # double them on the inbound side instead + #def _msg_send(self, phase, body): + # wormhole._Wormhole._msg_send(self, phase, body) + # self._ws_send_command("add", phase=phase, body=bytes_to_hexstr(body)) + def _event_received_peer_message(self, side, phase, body): + wormhole._Wormhole._event_received_peer_message(self, side, phase, body) + wormhole._Wormhole._event_received_peer_message(self, side, phase, body) + class Errors(ServerBase, unittest.TestCase): @inlineCallbacks def test_codes_1(self): diff --git a/src/wormhole/wormhole.py b/src/wormhole/wormhole.py index 93d95b8..3c0830e 100644 --- a/src/wormhole/wormhole.py +++ b/src/wormhole/wormhole.py @@ -758,10 +758,15 @@ class _Wormhole: if self._closing: log.msg("received peer message while closing '%s'" % phase) + if phase in self._received_messages: + log.msg("ignoring duplicate peer message '%s'" % phase) + return if phase == "pake": + self._received_messages["pake"] = body return self._event_received_pake(body) if phase == "version": + self._received_messages["version"] = body return self._event_received_version(side, body) if re.search(r'^\d+$', phase): return self._event_received_phase_message(side, phase, body)