Repository: bitcoin/bitcoin
File: test/functional/test_framework/socks5.py (Python)

Code before:
        self.queue = queue.Queue() # report connections and exceptions to client
        self.keep_alive = conf.keep_alive

    def run(self):
        while self.running:
            (sockconn, _) = self.s.accept()
            if self.running:
                conn = Socks5Connection(self, sockconn)
                thread = threading.Thread(None, conn.handle)
                thread.daemon = True
                thread.start()

    def start(self):
        assert not self.running
        self.running = True
        self.thread = threading.Thread(None, self.run)
        self.thread.daemon = True
        self.thread.start()

    def stop(self):
        self.running = False
        # connect to self to end run loop
        s = socket.socket(self.conf.af)
        s.connect(self.conf.addr)
        s.close()
        self.thread.join()


Review comment (bug):
i don't think `sendall` can be guaranteed with non-blocking sockets, it will fail if it gets EAGAIN
https://stackoverflow.com/questions/6240737/python-socket-sendall-function

Code after:
            password = None
            if method == 0x02:
                ver = recvall(self.conn, 1)[0]
                if ver != 0x01:
                    raise IOError('Invalid auth packet version %i' % ver)
                ulen = recvall(self.conn, 1)[0]
                username = str(recvall(self.conn, ulen))
                plen = recvall(self.conn, 1)[0]
                password = str(recvall(self.conn, plen))
                # Send authentication response
                self.conn.sendall(bytearray([0x01, 0x00]))

            # Read connect request
            ver, cmd, _, atyp = recvall(self.conn, 4)
            if ver != 0x05:
                raise IOError('Invalid socks version %i in connect request' % ver)
            if cmd != Command.CONNECT:
                raise IOError('Unhandled command %i in connect request' % cmd)

            if atyp == AddressType.IPV4:
                addr = recvall(self.conn, 4)
            elif atyp == AddressType.DOMAINNAME:
                n = recvall(self.conn, 1)[0]
                addr = recvall(self.conn, n)
            elif atyp == AddressType.IPV6:
                addr = recvall(self.conn, 16)
            else:
                raise IOError('Unknown address type %i' % atyp)
            port_hi,port_lo = recvall(self.conn, 2)
            port = (port_hi << 8) | port_lo

            # Send dummy response
            self.conn.sendall(bytearray([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))

            cmdin = Socks5Command(cmd, atyp, addr, port, username, password)
            self.serv.queue.put(cmdin)
            logger.debug('Proxy: %s', cmdin)

            requested_to_addr = addr.decode("utf-8")
            requested_to = format_addr_port(requested_to_addr, port)

            if self.serv.conf.destinations_factory is not None:
                dest = self.serv.conf.destinations_factory(requested_to_addr, port)
                if dest is not None:
                    logger.debug(f"Serving connection to {requested_to}, will redirect it to "
                                 f"{dest['actual_to_addr']}:{dest['actual_to_port']} instead")
                    with socket.create_connection((dest["actual_to_addr"], dest["actual_to_port"])) as conn_to:
                        forward_sockets(self.conn, conn_to)
                else:
                    logger.debug(f"Closing connection to {requested_to}: the destinations factory returned None")
            else: