async def _should_drop_peer(self, peer): peer.try_count += 1 is_good = False for kind, port, family in peer.connection_tuples(): peer.last_try = time.time() kwargs = {'family': family} if kind == 'SSL': kwargs['ssl'] = ssl.SSLContext(ssl.PROTOCOL_TLS) host = self.env.cs_host(for_rpc=False) if isinstance(host, list): host = host[0] if self.env.force_proxy or peer.is_tor: if not self.proxy: return kwargs['proxy'] = self.proxy kwargs['resolve'] = not peer.is_tor elif host: # Use our listening Host/IP for outgoing non-proxy # connections so our peers see the correct source. kwargs['local_addr'] = (host, None) peer_text = f'[{peer}:{port} {kind}]' try: async with timeout_after(120 if peer.is_tor else 30): async with Connector(PeerSession, peer.host, port, **kwargs) as session: await self._verify_peer(session, peer) is_good = True break except BadPeerError as e: self.logger.error(f'{peer_text} marking bad: ({e})') peer.mark_bad() break except RPCError as e: self.logger.error(f'{peer_text} RPC error: {e.message} ' f'({e.code})') except (OSError, SOCKSError, ConnectionError, TaskTimeout) as e: self.logger.info(f'{peer_text} {e}') if is_good: now = time.time() elapsed = now - peer.last_try self.logger.info(f'{peer_text} verified in {elapsed:.1f}s') 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). matches = peer.matches(self.peers) for match in matches: if match.ip_address: if len(matches) > 1: self.peers.remove(match) # Force the peer's monitoring task to exit match.retry_event.set() elif peer.host in match.features['hosts']: match.update_features_from_peer(peer) # Trim this data structure self.recent_peer_adds = {k: v for k, v in self.recent_peer_adds.items() if v + PEER_ADD_PAUSE < now} else: # Forget the peer if long-term unreachable if peer.last_good and not peer.bad: try_limit = 10 else: try_limit = 3 if peer.try_count >= try_limit: desc = 'bad' if peer.bad else 'unreachable' self.logger.info(f'forgetting {desc} peer: {peer}') return True return False
async def create_connection(self): connector = Connector(lambda: self, *self.server) await connector.create_connection()