Commit d904c238 authored by Yury Selivanov's avatar Yury Selivanov Committed by GitHub

bpo-27500: Fix static version of getaddrinfo to resolve IPv6 (GH-7993)

parent 41cb0bae
...@@ -61,6 +61,8 @@ _MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5 ...@@ -61,6 +61,8 @@ _MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5
_FATAL_ERROR_IGNORE = (BrokenPipeError, _FATAL_ERROR_IGNORE = (BrokenPipeError,
ConnectionResetError, ConnectionAbortedError) ConnectionResetError, ConnectionAbortedError)
_HAS_IPv6 = hasattr(socket, 'AF_INET6')
def _format_handle(handle): def _format_handle(handle):
cb = handle._callback cb = handle._callback
...@@ -123,7 +125,7 @@ def _ipaddr_info(host, port, family, type, proto): ...@@ -123,7 +125,7 @@ def _ipaddr_info(host, port, family, type, proto):
if family == socket.AF_UNSPEC: if family == socket.AF_UNSPEC:
afs = [socket.AF_INET] afs = [socket.AF_INET]
if hasattr(socket, 'AF_INET6'): if _HAS_IPv6:
afs.append(socket.AF_INET6) afs.append(socket.AF_INET6)
else: else:
afs = [family] afs = [family]
...@@ -139,6 +141,9 @@ def _ipaddr_info(host, port, family, type, proto): ...@@ -139,6 +141,9 @@ def _ipaddr_info(host, port, family, type, proto):
try: try:
socket.inet_pton(af, host) socket.inet_pton(af, host)
# The host has already been resolved. # The host has already been resolved.
if _HAS_IPv6 and af == socket.AF_INET6:
return af, type, proto, '', (host, port, 0, 0)
else:
return af, type, proto, '', (host, port) return af, type, proto, '', (host, port)
except OSError: except OSError:
pass pass
...@@ -1309,7 +1314,6 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -1309,7 +1314,6 @@ class BaseEventLoop(events.AbstractEventLoop):
raise ValueError( raise ValueError(
'host/port and sock can not be specified at the same time') 'host/port and sock can not be specified at the same time')
AF_INET6 = getattr(socket, 'AF_INET6', 0)
if reuse_address is None: if reuse_address is None:
reuse_address = os.name == 'posix' and sys.platform != 'cygwin' reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
sockets = [] sockets = []
...@@ -1349,7 +1353,9 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -1349,7 +1353,9 @@ class BaseEventLoop(events.AbstractEventLoop):
# Disable IPv4/IPv6 dual stack support (enabled by # Disable IPv4/IPv6 dual stack support (enabled by
# default on Linux) which makes a single socket # default on Linux) which makes a single socket
# listen on both address families. # listen on both address families.
if af == AF_INET6 and hasattr(socket, 'IPPROTO_IPV6'): if (_HAS_IPv6 and
af == socket.AF_INET6 and
hasattr(socket, 'IPPROTO_IPV6')):
sock.setsockopt(socket.IPPROTO_IPV6, sock.setsockopt(socket.IPPROTO_IPV6,
socket.IPV6_V6ONLY, socket.IPV6_V6ONLY,
True) True)
......
...@@ -97,11 +97,11 @@ class BaseEventTests(test_utils.TestCase): ...@@ -97,11 +97,11 @@ class BaseEventTests(test_utils.TestCase):
base_events._ipaddr_info('1.2.3.4', 1, INET6, STREAM, TCP)) base_events._ipaddr_info('1.2.3.4', 1, INET6, STREAM, TCP))
self.assertEqual( self.assertEqual(
(INET6, STREAM, TCP, '', ('::3', 1)), (INET6, STREAM, TCP, '', ('::3', 1, 0, 0)),
base_events._ipaddr_info('::3', 1, INET6, STREAM, TCP)) base_events._ipaddr_info('::3', 1, INET6, STREAM, TCP))
self.assertEqual( self.assertEqual(
(INET6, STREAM, TCP, '', ('::3', 1)), (INET6, STREAM, TCP, '', ('::3', 1, 0, 0)),
base_events._ipaddr_info('::3', 1, UNSPEC, STREAM, TCP)) base_events._ipaddr_info('::3', 1, UNSPEC, STREAM, TCP))
# IPv6 address with family IPv4. # IPv6 address with family IPv4.
...@@ -1077,6 +1077,26 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): ...@@ -1077,6 +1077,26 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
srv.close() srv.close()
self.loop.run_until_complete(srv.wait_closed()) self.loop.run_until_complete(srv.wait_closed())
@unittest.skipUnless(hasattr(socket, 'AF_INET6'), 'no IPv6 support')
def test_create_server_ipv6(self):
async def main():
srv = await asyncio.start_server(
lambda: None, '::1', 0, loop=self.loop)
try:
self.assertGreater(len(srv.sockets), 0)
finally:
srv.close()
await srv.wait_closed()
try:
self.loop.run_until_complete(main())
except OSError as ex:
if (hasattr(errno, 'EADDRNOTAVAIL') and
ex.errno == errno.EADDRNOTAVAIL):
self.skipTest('failed to bind to ::1')
else:
raise
def test_create_datagram_endpoint_wrong_sock(self): def test_create_datagram_endpoint_wrong_sock(self):
sock = socket.socket(socket.AF_INET) sock = socket.socket(socket.AF_INET)
with sock: with sock:
......
Fix getaddrinfo to resolve IPv6 addresses correctly.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment