From e1b26280586bd5a4368b17796601c35a54498fea Mon Sep 17 00:00:00 2001 From: CjHanks Date: Fri, 4 Jul 2014 15:37:32 -0700 Subject: [PATCH] Fix address resolution for cases where first result is not useful. The socket connection logic always presumed the first returned result from socket.getaddrinfo(...) is the target. However it is not uncommon to be listening IPv4 while ignore IPv6. This code iterates through the return list until one connects without a CONNECTION REFUSED error, if all fail, the exception is rethrown. `man getaddrinfo` demonstrates a similar use pattern in C. --- websocket/_core.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/websocket/_core.py b/websocket/_core.py index 780706e..5948ab3 100644 --- a/websocket/_core.py +++ b/websocket/_core.py @@ -47,6 +47,7 @@ else: from base64 import encodestring as base64encode import os +import errno import struct import uuid import hashlib @@ -418,16 +419,27 @@ class WebSocket(object): if not addrinfo_list: raise WebSocketException("Host not found.: " + hostname + ":" + str(port)) - family = addrinfo_list[0][0] - self.sock = socket.socket(family) - self.sock.settimeout(self.timeout) - for opts in DEFAULT_SOCKET_OPTION: - self.sock.setsockopt(*opts) - for opts in self.sockopt: - self.sock.setsockopt(*opts) - # TODO: we need to support proxy - address = addrinfo_list[0][4] - self.sock.connect(address) + for addrinfo in addrinfo_list: + family = addrinfo[0] + self.sock = socket.socket(family) + self.sock.settimeout(self.timeout) + for opts in DEFAULT_SOCKET_OPTION: + self.sock.setsockopt(*opts) + for opts in self.sockopt: + self.sock.setsockopt(*opts) + # TODO: we need to support proxy + address = addrinfo[4] + try: + self.sock.connect(address) + except socket.error as error: + if error.errno in (errno.ECONNREFUSED, ): + continue + else: + raise + else: + break + else: + raise error if proxy_host: self._tunnel(hostname, port)