diff --git a/src/wormhole/test/test_transit.py b/src/wormhole/test/test_transit.py index dee0e63..62848b4 100644 --- a/src/wormhole/test/test_transit.py +++ b/src/wormhole/test/test_transit.py @@ -1374,6 +1374,56 @@ class Transit(unittest.TestCase): self._waiters[0].callback("winner") self.assertEqual(results, ["winner"]) + @inlineCallbacks + def test_priorities(self): + clock = task.Clock() + s = transit.TransitSender("", reactor=clock, no_listen=True) + s.set_transit_key(b"key") + hints = yield s.get_connection_hints() + del hints + s.add_connection_hints([ + {"type": "relay-v1", + "hints": [{"type": "direct-tcp-v1", + "hostname": "relay", "port": 1234}]}, + {"type": "direct-tcp-v1", + "hostname": "direct", "port": 1234}, + {"type": "relay-v1", + "hints": [{"type": "direct-tcp-v1", "priority": 2.0, + "hostname": "relay2", "port": 1234}, + {"type": "direct-tcp-v1", "priority": 3.0, + "hostname": "relay3", "port": 1234}]}, + {"type": "relay-v1", + "hints": [{"type": "direct-tcp-v1", "priority": 2.0, + "hostname": "relay4", "port": 1234}]}, + ]) + s._endpoint_from_hint_obj = self._endpoint_from_hint_obj + s._start_connector = self._start_connector + + d = s.connect() + results = [] + d.addBoth(results.append) + self.assertEqual(results, []) + # direct connector should be used first, then the priority=3.0 relay, + # then the two 2.0 relays, then the (default) 0.0 relay + + self.assertEqual(self._connectors, ["direct"]) + + clock.advance(s.RELAY_DELAY + 1.0) + self.assertEqual(self._connectors, ["direct", "relay3"]) + + clock.advance(s.RELAY_DELAY) + self.assertIn(self._connectors, + (["direct", "relay3", "relay2", "relay4"], + ["direct", "relay3", "relay4", "relay2"])) + + clock.advance(s.RELAY_DELAY) + self.assertIn(self._connectors, + (["direct", "relay3", "relay2", "relay4", "relay"], + ["direct", "relay3", "relay4", "relay2", "relay"])) + + self._waiters[0].callback("winner") + self.assertEqual(results, ["winner"]) + @inlineCallbacks def test_no_direct_hints(self): clock = task.Clock() diff --git a/src/wormhole/transit.py b/src/wormhole/transit.py index 20b8d88..4aa5972 100644 --- a/src/wormhole/transit.py +++ b/src/wormhole/transit.py @@ -821,8 +821,17 @@ class Common: # resolve quickly. Many direct hints will be to unused local-network # IP addresses, which won't answer, and would take the full TCP # timeout (30s or more) to fail. + + prioritized_relays = {} for rh in self._our_relay_hints: for hint_obj in rh.hints: + priority = hint_obj.priority + if priority not in prioritized_relays: + prioritized_relays[priority] = set() + prioritized_relays[priority].add(hint_obj) + + for priority in sorted(prioritized_relays, reverse=True): + for hint_obj in prioritized_relays[priority]: ep = self._endpoint_from_hint_obj(hint_obj) if not ep: continue @@ -831,6 +840,7 @@ class Common: self._start_connector, ep, description, is_relay=True) contenders.append(d) + relay_delay += self.RELAY_DELAY if not contenders: raise TransitError("No contenders for connection")