diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 4505732f9ac..9d07673fbad 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -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: diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index e72b86e77c3..b3f9f0bf066 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -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)