From f12d7e19a93dde118b40ca4d54dbb20a49aee30a Mon Sep 17 00:00:00 2001 From: Ralf Schmitt Date: Thu, 31 Jan 2013 20:59:02 +0100 Subject: [PATCH] try connecting to all possible values returned from getaddrinfo if getaddrinfo returns multiple values, we try to connect to each one until the first succeeds. we block while doing that, but we probably already did in getaddrinfo. however if getaddrinfo returns exactly one value, we still use a nonblocking connect. so, if someone want to make sure the connect function doesn't block, he can use a numeric IP address. --- puka/connection.py | 59 +++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/puka/connection.py b/puka/connection.py index c6c666e..2ff768d 100644 --- a/puka/connection.py +++ b/puka/connection.py @@ -68,27 +68,24 @@ def _connect(self): self._handle_read = self._handle_conn_read self._init_buffers() - addrinfo = None - if socket.has_ipv6: + addrinfo = socket.getaddrinfo( + self.host, self.port, + socket.AF_UNSPEC if socket.has_ipv6 else socket.AF_INET, + socket.SOCK_STREAM) + + err = None + + for addr in addrinfo: try: - addrinfo = socket.getaddrinfo( - self.host, self.port, socket.AF_INET6, socket.SOCK_STREAM) - except socket.gaierror: + self.sd = connect_to(addr, len(addrinfo) == 1) + err = None + break + except socket.error, err: pass - if not addrinfo: - addrinfo = socket.getaddrinfo( - self.host, self.port, socket.AF_INET, socket.SOCK_STREAM) - - (family, socktype, proto, canonname, sockaddr) = addrinfo[0] - self.sd = socket.socket(family, socktype, proto) - self.sd.setblocking(False) - set_ridiculously_high_buffers(self.sd) - set_close_exec(self.sd) - try: - self.sd.connect(sockaddr) - except socket.error, e: - if e.errno not in (errno.EINPROGRESS, errno.EWOULDBLOCK): - raise + + if err is not None: + raise err + return machine.connection_handshake(self) def on_read(self): @@ -435,3 +432,27 @@ def set_close_exec(fd): fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) except ImportError: pass + +def prepare_socket(sd): + sd.setblocking(False) + set_ridiculously_high_buffers(sd) + set_close_exec(sd) + +def connect_to(addr, nonblocking): + (family, socktype, proto, canonname, sockaddr) = addr + sock = socket.socket(family, socktype, proto) + if nonblocking: + prepare_socket(sock) + + try: + sock.connect(sockaddr) + except socket.error, e: + if nonblocking and e.errno in (errno.EINPROGRESS, errno.EWOULDBLOCK): + return sock + sock.close() + raise e + + if not nonblocking: + prepare_socket(sock) + + return sock