'Negotiates a connection through a SOCKS5 server.'

def _negotiate_SOCKS5(self, dest_addr, dest_port):

    (proxy_type, addr, port, rdns, username, password) = self.proxy
    if (username and password):
        self.sendall('\x05\x02\x00\x02')
    else:
        self.sendall('\x05\x01\x00')
    chosen_auth = self._recvall(2)
    if (chosen_auth[0:1] != '\x05'):
        raise GeneralProxyError('SOCKS5    proxy    server    sent    invalid    data')
    if (chosen_auth[1:2] == '\x02'):
        self.sendall((((('\x01' + chr(len(username)).encode()) + username) + chr(len(password)).encode()) + password))
        auth_status = self._recvall(2)
        if (auth_status[0:1] != '\x01'):
            raise GeneralProxyError('SOCKS5    proxy    server    sent    invalid    data')
        if (auth_status[1:2] != '\x00'):
            raise SOCKS5AuthError('SOCKS5    authentication    failed')
    elif (chosen_auth[1:2] != '\x00'):
        if (chosen_auth[1:2] == '\xff'):
            raise SOCKS5AuthError('All    offered    SOCKS5    authentication    methods    were    rejected')
        else:
            raise GeneralProxyError('SOCKS5    proxy    server    sent    invalid    data')
    req = '\x05\x01\x00'
    try:
        addr_bytes = socket.inet_aton(dest_addr)
        req += ('\x01' + addr_bytes)
    except socket.error:
        if rdns:
            addr_bytes = None
            req += (('\x03' + chr(len(dest_addr)).encode()) + dest_addr.encode())
        else:
            addr_bytes = socket.inet_aton(socket.gethostbyname(dest_addr))
            req += ('\x01' + addr_bytes)
    req += struct.pack('>H', dest_port)
    self.sendall(req)
    resp = self._recvall(4)
    if (resp[0:1] != '\x05'):
        raise GeneralProxyError('SOCKS5    proxy    server    sent    invalid    data')
    status = ord(resp[1:2])
    if (status != 0):
        error = SOCKS5_ERRORS.get(status, 'Unknown    error')
        raise SOCKS5Error('{:#04x}:    {}'.format(status, error))
    if (resp[3:4] == '\x01'):
        bound_addr = self._recvall(4)
    elif (resp[3:4] == '\x03'):
        resp += self.recv(1)
        bound_addr = self._recvall(ord(resp[4:5]))
    else:
        raise GeneralProxyError('SOCKS5    proxy    server    sent    invalid    data')
    bound_port = struct.unpack('>H', self._recvall(2))[0]
    self.proxy_sockname = (bound_addr, bound_port)
    if addr_bytes:
        self.proxy_peername = (socket.inet_ntoa(addr_bytes), dest_port)
    else:
        self.proxy_peername = (dest_addr, dest_port)
