summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYury Selivanov <yselivanov@sprymix.com>2016-03-02 16:17:01 (GMT)
committerYury Selivanov <yselivanov@sprymix.com>2016-03-02 16:17:01 (GMT)
commite076ffb068ce4e76a7103451c3bef79c2610f791 (patch)
treede92e99ab9d04635d20adfdff6003e3c0d40f9cf
parentf9e1f2bda930054eed3115e19e9f3f7bfc83c1b6 (diff)
downloadcpython-e076ffb068ce4e76a7103451c3bef79c2610f791.zip
cpython-e076ffb068ce4e76a7103451c3bef79c2610f791.tar.gz
cpython-e076ffb068ce4e76a7103451c3bef79c2610f791.tar.bz2
asyncio: Remove duplicate bind addresses in create_server.
Patch by Sebastien Bourdeauducq (issue #26338)
-rw-r--r--Lib/asyncio/base_events.py7
-rw-r--r--Lib/test/test_asyncio/test_events.py23
2 files changed, 18 insertions, 12 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 4505732..9d07673 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 e72b86e..b3f9f0b 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)