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_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)
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)