]> granicus.if.org Git - python/commitdiff
asyncio: Remove duplicate bind addresses in create_server.
authorYury Selivanov <yselivanov@sprymix.com>
Wed, 2 Mar 2016 16:17:01 +0000 (11:17 -0500)
committerYury Selivanov <yselivanov@sprymix.com>
Wed, 2 Mar 2016 16:17:01 +0000 (11:17 -0500)
Patch by Sebastien Bourdeauducq (issue #26338)

Lib/asyncio/base_events.py
Lib/test/test_asyncio/test_events.py

index 4505732f9ac02bdf3919a678b2347ff1ee353cae..9d07673fbad2120f7d65e0963b601f7eb0f0ea06 100644 (file)
@@ -880,7 +880,10 @@ class BaseEventLoop(events.AbstractEventLoop):
         to host and port.
 
         The host parameter can also be a sequence of strings and in that case
-        the TCP server is bound to all hosts of the sequence.
+        the TCP server is bound to all hosts of the sequence. If a host
+        appears multiple times (possibly indirectly e.g. when hostnames
+        resolve to the same IP address), the server is only bound once to that
+        host.
 
         Return a Server object which can be used to stop the service.
 
@@ -909,7 +912,7 @@ class BaseEventLoop(events.AbstractEventLoop):
                                                   flags=flags)
                   for host in hosts]
             infos = yield from tasks.gather(*fs, loop=self)
-            infos = itertools.chain.from_iterable(infos)
+            infos = set(itertools.chain.from_iterable(infos))
 
             completed = False
             try:
index e72b86e77c36576c7c5bbb0e2b27ce56e02bc90c..b3f9f0bf0667639c23261196b72253532d91dda1 100644 (file)
@@ -749,34 +749,37 @@ class EventLoopTestsMixin:
         @asyncio.coroutine
         def getaddrinfo(host, port, *args, **kw):
             if family == socket.AF_INET:
-                return [[family, socket.SOCK_STREAM, 6, '', (host, port)]]
+                return [(family, socket.SOCK_STREAM, 6, '', (host, port))]
             else:
-                return [[family, socket.SOCK_STREAM, 6, '', (host, port, 0, 0)]]
+                return [(family, socket.SOCK_STREAM, 6, '', (host, port, 0, 0))]
 
         def getaddrinfo_task(*args, **kwds):
             return asyncio.Task(getaddrinfo(*args, **kwds), loop=self.loop)
 
+        unique_hosts = set(hosts)
+
         if family == socket.AF_INET:
-            mock_sock.socket().getsockbyname.side_effect = [(host, 80)
-                                                            for host in hosts]
+            mock_sock.socket().getsockbyname.side_effect = [
+                (host, 80) for host in unique_hosts]
         else:
-            mock_sock.socket().getsockbyname.side_effect = [(host, 80, 0, 0)
-                                                            for host in hosts]
+            mock_sock.socket().getsockbyname.side_effect = [
+                (host, 80, 0, 0) for host in unique_hosts]
         self.loop.getaddrinfo = getaddrinfo_task
         self.loop._start_serving = mock.Mock()
         self.loop._stop_serving = mock.Mock()
         f = self.loop.create_server(lambda: MyProto(self.loop), hosts, 80)
         server = self.loop.run_until_complete(f)
         self.addCleanup(server.close)
-        server_hosts = [sock.getsockbyname()[0] for sock in server.sockets]
-        self.assertEqual(server_hosts, hosts)
+        server_hosts = {sock.getsockbyname()[0] for sock in server.sockets}
+        self.assertEqual(server_hosts, unique_hosts)
 
     def test_create_server_multiple_hosts_ipv4(self):
         self.create_server_multiple_hosts(socket.AF_INET,
-                                          ['1.2.3.4', '5.6.7.8'])
+                                          ['1.2.3.4', '5.6.7.8', '1.2.3.4'])
 
     def test_create_server_multiple_hosts_ipv6(self):
-        self.create_server_multiple_hosts(socket.AF_INET6, ['::1', '::2'])
+        self.create_server_multiple_hosts(socket.AF_INET6,
+                                          ['::1', '::2', '::1'])
 
     def test_create_server(self):
         proto = MyProto(self.loop)