diff --git a/lib/peer.py b/lib/peer.py index d011300..83d6334 100644 --- a/lib/peer.py +++ b/lib/peer.py @@ -38,13 +38,13 @@ class Peer(object): ATTRS = ('host', 'features', # metadata 'source', 'ip_addr', 'good_ports', - 'last_connect', 'last_try', 'try_count') + 'last_good', 'last_try', 'try_count') FEATURES = ('pruning', 'server_version', 'protocol_min', 'protocol_max') # This should be set by the application DEFAULT_PORTS = {} def __init__(self, host, features, source='unknown', ip_addr=None, - good_ports=[], last_connect=0, last_try=0, try_count=0): + good_ports=[], last_good=0, last_try=0, try_count=0): '''Create a peer given a host name (or IP address as a string), a dictionary of features, and a record of the source.''' assert isinstance(host, str) @@ -59,7 +59,11 @@ class Peer(object): self.source = source self.ip_addr = ip_addr self.good_ports = good_ports.copy() - self.last_connect = last_connect + # last_good represents the last connection that was + # successful *and* successfully verified, at which point + # try_count is set to 0. Failure to connect or failure to + # verify increment the try_count. + self.last_good = last_good self.last_try = last_try self.try_count = try_count # Transient, non-persisted metadata diff --git a/server/controller.py b/server/controller.py index 3bd8264..783353a 100644 --- a/server/controller.py +++ b/server/controller.py @@ -500,7 +500,7 @@ class Controller(util.LoggedClass): fmt = ('{:<30} {:<6} {:>5} {:>5} {:<17} {:>3} ' '{:>3} {:>8} {:>11} {:>11} {:>5} {:>20} {:<15}') yield fmt.format('Host', 'Status', 'TCP', 'SSL', 'Server', 'Min', - 'Max', 'Pruning', 'Last Conn', 'Last Try', + 'Max', 'Pruning', 'Last Good', 'Last Try', 'Tries', 'Source', 'IP Address') for item in data: features = item['features'] @@ -514,7 +514,7 @@ class Controller(util.LoggedClass): features['protocol_min'], features['protocol_max'], features['pruning'] or '', - time_fmt(item['last_connect']), + time_fmt(item['last_good']), time_fmt(item['last_try']), item['try_count'], item['source'][:20], diff --git a/server/peers.py b/server/peers.py index 5b85c92..1e95956 100644 --- a/server/peers.py +++ b/server/peers.py @@ -193,7 +193,6 @@ class PeerSession(JSONSession): self.shutdown_connection() def shutdown_connection(self): - self.peer.last_connect = time.time() is_good = not (self.failed or self.bad) self.peer_mgr.set_verification_status(self.peer, self.kind, is_good) self.close_connection() @@ -249,9 +248,9 @@ class PeerManager(util.LoggedClass): for peer in self.peers: if peer.bad: peer.status = PEER_BAD - elif peer.last_connect > cutoff: + elif peer.last_good > cutoff: peer.status = PEER_GOOD - elif peer.last_connect: + elif peer.last_good: peer.status = PEER_STALE else: peer.status = PEER_NEVER @@ -267,7 +266,7 @@ class PeerManager(util.LoggedClass): return data def peer_key(peer): - return (peer.bad, -peer.last_connect) + return (peer.bad, -peer.last_good) return [peer_data(peer) for peer in sorted(self.peers, key=peer_key)] @@ -358,13 +357,13 @@ class PeerManager(util.LoggedClass): ''' cutoff = time.time() - STALE_SECS recent = [peer for peer in self.peers - if peer.last_connect > cutoff and + if peer.last_good > cutoff and not peer.bad and peer.is_public] onion_peers = [] # Always report ourselves if valid (even if not public) peers = set(myself for myself in self.myselves - if myself.last_connect > cutoff) + if myself.last_good > cutoff) # Bucket the clearnet peers and select up to two from each buckets = defaultdict(list) @@ -409,6 +408,8 @@ class PeerManager(util.LoggedClass): if version == 1: peers = [] for item in items: + if 'last_connect' in item: + item['last_good'] = item.pop('last_connect') try: peers.append(Peer.deserialize(item)) except Exception: @@ -496,7 +497,7 @@ class PeerManager(util.LoggedClass): return True # Retry a good connection if it is about to turn stale if peer.try_count == 0: - return peer.last_connect < nearly_stale_time + return peer.last_good < nearly_stale_time # Retry a failed connection if enough time has passed return peer.last_try < now - WAKEUP_SECS * 2 ** peer.try_count @@ -549,16 +550,18 @@ class PeerManager(util.LoggedClass): def set_verification_status(self, peer, kind, good): '''Called when a verification succeeded or failed.''' + now = time.time() if self.env.force_proxy or peer.is_tor: how = 'via {} over Tor'.format(kind) else: how = 'via {} at {}'.format(kind, peer.ip_addr) status = 'verified' if good else 'failed to verify' - elapsed = time.time() - peer.last_try + elapsed = now - peer.last_try self.log_info('{} {} {} in {:.1f}s'.format(status, peer, how, elapsed)) if good: peer.try_count = 0 + peer.last_good = now peer.source = 'peer' # At most 2 matches if we're a host name, potentially several if # we're an IP address (several instances can share a NAT). @@ -574,7 +577,7 @@ class PeerManager(util.LoggedClass): def maybe_forget_peer(self, peer): '''Forget the peer if appropriate, e.g. long-term unreachable.''' - if peer.last_connect and not peer.bad: + if peer.last_good and not peer.bad: try_limit = 10 else: try_limit = 3