From: Silent-Nights Date: Mon, 23 Jul 2018 13:42:44 +0000 (+0200) Subject: Sort getaddrinfo result based on address family X-Git-Tag: v6.0.0b1~43^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2454%2Fhead;p=thirdparty%2Ftornado.git Sort getaddrinfo result based on address family Putting getaddrinfo result in a set to eliminate duplicates causes race conditions because sets are unordered For example consider 2 applications try to bind to many random ports at once in both IPV4 and IPV6. App1: Bind to random IPV4 address and get port 50000 App2: Bind to random IPV6 address and get port 50000 App2: Try to bind to same port on IPV4 and fails as App1 already bound to it The same goes for App1 To resolve this, we create the set explicitly outside the loop. We order the returned list of getaddrinfo based on Address family. We skip the iteration if the iteration tuple already in the set. Otherwise we execute the loop. --- diff --git a/tornado/netutil.py b/tornado/netutil.py index c57f6fd34..7bb587dce 100644 --- a/tornado/netutil.py +++ b/tornado/netutil.py @@ -102,8 +102,14 @@ def bind_sockets(port, address=None, family=socket.AF_UNSPEC, if flags is None: flags = socket.AI_PASSIVE bound_port = None - for res in set(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, - 0, flags)): + unique_addresses = set() + for res in sorted(socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, + 0, flags), key=lambda x: x[0]): + if res in unique_addresses: + continue + + unique_addresses.add(res) + af, socktype, proto, canonname, sockaddr = res if (sys.platform == 'darwin' and address == 'localhost' and af == socket.AF_INET6 and sockaddr[3] != 0):