def read_peer_id(self, s): self.unauth_peer_id = s self.low_proto_ver, self.cur_proto_ver = get_proto_version_from_peer_id(self.unauth_peer_id) self.sel_proto_ver = select_supported_protoversion(self.low_proto_ver, self.cur_proto_ver) if not self.sel_proto_ver: if DEBUG: print >> sys.stderr, "olconn: We don't support peer's version of the protocol" return None if DEBUG: print >> sys.stderr, 'olconn: Selected protocol version', self.sel_proto_ver if self.cur_proto_ver <= 2: print >> sys.stderr, 'olconn: Kicking ancient peer', `(self.unauth_peer_id)`, self.get_ip() return None self.state = STATE_AUTH_WAIT self.cr = ChallengeResponse(self.handler.get_my_keypair(), self.handler.get_my_peer_id(), self) if self.locally_initiated: self.cr.start_cr(self) return (4, self.read_len)
class OverlayConnection(): def __init__(self, handler, singsock, rawserver, locally_initiated = False, specified_dns = None, ext_handshake = False, options = None): self.handler = handler self.singsock = singsock self.rawserver = rawserver self.buffer = StringIO() self.cb_queue = [] self.auth_permid = None self.unauth_peer_id = None self.auth_peer_id = None self.auth_listen_port = None self.low_proto_ver = 0 self.cur_proto_ver = 0 self.sel_proto_ver = 0 self.options = None self.locally_initiated = locally_initiated self.specified_dns = specified_dns self.last_use = time() self.state = STATE_INITIAL self.write(chr(len(protocol_name)) + protocol_name + option_pattern + overlay_infohash + self.handler.get_my_peer_id()) if ext_handshake: self.state = STATE_HS_PEERID_WAIT self.next_len = 20 self.next_func = self.read_peer_id self.set_options(options) else: self.state = STATE_HS_FULL_WAIT self.next_len = 1 self.next_func = self.read_header_len self.rawserver.add_task(self._olconn_auto_close, EXPIRE_CHECK_INTERVAL) def data_came_in(self, singsock, data): dummy_port = singsock.get_port(True) if DEBUG: print >> sys.stderr, 'olconn: data_came_in', singsock.get_ip(), singsock.get_port() self.handler.measurefunc(len(data)) self.last_use = time() while 1: if self.state == STATE_CLOSED: return i = self.next_len - self.buffer.tell() if i > len(data): self.buffer.write(data) return self.buffer.write(data[:i]) data = data[i:] m = self.buffer.getvalue() self.buffer.reset() self.buffer.truncate() try: if DEBUG: print >> sys.stderr, 'olconn: Trying to read', self.next_len x = self.next_func(m) except: self.next_len, self.next_func = 1, self.read_dead if DEBUG: print_exc() raise if x is None: if DEBUG: print >> sys.stderr, 'olconn: next_func returned None', self.next_func self.close() return self.next_len, self.next_func = x def connection_lost(self, singsock): if DEBUG: print >> sys.stderr, 'olconn: connection_lost', singsock.get_ip(), singsock.get_port(), self.state if self.state != STATE_CLOSED: self.state = STATE_CLOSED self.handler.connection_lost(self) def connection_flushed(self, singsock): pass def send_message(self, message): self.last_use = time() s = tobinary(len(message)) + message self.write(s) def is_locally_initiated(self): return self.locally_initiated def get_ip(self): return self.singsock.get_ip() def get_port(self): return self.singsock.get_port() def is_auth_done(self): return self.auth_permid is not None def get_auth_permid(self): return self.auth_permid def get_auth_listen_port(self): return self.auth_listen_port def get_remote_listen_port(self): if self.is_auth_done(): return self.auth_listen_port elif self.is_locally_initiated(): return self.specified_dns[1] else: return NO_REMOTE_LISTEN_PORT_KNOWN def get_low_proto_ver(self): return self.low_proto_ver def get_cur_proto_ver(self): return self.cur_proto_ver def get_sel_proto_ver(self): return self.sel_proto_ver def queue_callback(self, dns, callback): if callback is not None: self.cb_queue.append(callback) def dequeue_callbacks(self): try: permid = self.get_auth_permid() for callback in self.cb_queue: callback(None, self.specified_dns, permid, self.get_sel_proto_ver()) self.cb_queue = [] except Exception as e: print_exc() def cleanup_callbacks(self, exc): if DEBUG: print >> sys.stderr, 'olconn: cleanup_callbacks: #callbacks is', len(self.cb_queue) try: for callback in self.cb_queue: if DEBUG: print >> sys.stderr, 'olconn: cleanup_callbacks: callback is', callback callback(exc, self.specified_dns, self.get_auth_permid(), 0) except Exception as e: print_exc() def get_unauth_peer_id(self): return self.unauth_peer_id def got_auth_connection(self, singsock, permid, peer_id): self.auth_permid = str(permid) self.auth_peer_id = peer_id self.auth_listen_port = decode_auth_listen_port(peer_id) self.state = STATE_DATA_WAIT if not self.handler.got_auth_connection(self): self.close() return def read_header_len(self, s): if ord(s) != len(protocol_name): return None return (len(protocol_name), self.read_header) def read_header(self, s): if s != protocol_name: return None return (8, self.read_reserved) def read_reserved(self, s): if DEBUG: print >> sys.stderr, 'olconn: Reserved bits:', `s` self.set_options(s) return (20, self.read_download_id) def read_download_id(self, s): if s != overlay_infohash: return None return (20, self.read_peer_id) def read_peer_id(self, s): self.unauth_peer_id = s self.low_proto_ver, self.cur_proto_ver = get_proto_version_from_peer_id(self.unauth_peer_id) self.sel_proto_ver = select_supported_protoversion(self.low_proto_ver, self.cur_proto_ver) if not self.sel_proto_ver: if DEBUG: print >> sys.stderr, "olconn: We don't support peer's version of the protocol" return None if DEBUG: print >> sys.stderr, 'olconn: Selected protocol version', self.sel_proto_ver if self.cur_proto_ver <= 2: print >> sys.stderr, 'olconn: Kicking ancient peer', `(self.unauth_peer_id)`, self.get_ip() return None self.state = STATE_AUTH_WAIT self.cr = ChallengeResponse(self.handler.get_my_keypair(), self.handler.get_my_peer_id(), self) if self.locally_initiated: self.cr.start_cr(self) return (4, self.read_len) def read_len(self, s): l = toint(s) if l > self.handler.get_max_len(): return None return (l, self.read_message) def read_message(self, s): if s != '': if self.state == STATE_AUTH_WAIT: if not self.cr.got_message(self, s): return None elif self.state == STATE_DATA_WAIT: if not self.handler.got_message(self.auth_permid, s, self.sel_proto_ver): return None else: if DEBUG: print >> sys.stderr, 'olconn: Received message while in illegal state, internal error!' return None return (4, self.read_len) def read_dead(self, s): return None def write(self, s): self.singsock.write(s) def set_options(self, options): self.options = options def close(self): if DEBUG: print >> sys.stderr, 'olconn: we close()', self.get_ip(), self.get_port() self.state_when_error = self.state if self.state != STATE_CLOSED: self.state = STATE_CLOSED self.handler.local_close(self) self.singsock.close() def _olconn_auto_close(self): if time() - self.last_use > EXPIRE_THRESHOLD: self.close() else: self.rawserver.add_task(self._olconn_auto_close, EXPIRE_CHECK_INTERVAL)