prioritize relay connections

closes #103
This commit is contained in:
Brian Warner 2016-12-30 23:23:06 -05:00
parent 8b864c3eae
commit b2fd899ac9
2 changed files with 60 additions and 0 deletions

View File

@ -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()

View File

@ -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")