Skip to content

Commit

Permalink
Consistent loop.getaddrinfo() API
Browse files Browse the repository at this point in the history
* ai_canonname is different across libc impls (#494)
* AddressFamily and SocketKind can be enums
* Also fixed failing test
  • Loading branch information
fantix committed Sep 11, 2022
1 parent d6a2b59 commit 64d6fe3
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 7 deletions.
4 changes: 4 additions & 0 deletions tests/test_dns.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,14 @@ def test_getaddrinfo_18(self):
def test_getaddrinfo_19(self):
self._test_getaddrinfo('::1', 80)
self._test_getaddrinfo('::1', 80, type=socket.SOCK_STREAM)
self._test_getaddrinfo('::1', 80, type=socket.SOCK_STREAM,
flags=socket.AI_CANONNAME)

def test_getaddrinfo_20(self):
self._test_getaddrinfo('127.0.0.1', 80)
self._test_getaddrinfo('127.0.0.1', 80, type=socket.SOCK_STREAM)
self._test_getaddrinfo('127.0.0.1', 80, type=socket.SOCK_STREAM,
flags=socket.AI_CANONNAME)

######

Expand Down
2 changes: 1 addition & 1 deletion tests/test_tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def test_create_server_4(self):

with self.assertRaisesRegex(OSError,
r"error while attempting.*\('127.*: "
r"address already in use"):
r"address( already)? in use"):

self.loop.run_until_complete(
self.loop.create_server(object, *addr))
Expand Down
37 changes: 34 additions & 3 deletions uvloop/dns.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,17 @@ cdef __static_getaddrinfo(object host, object port,
return (family, type, proto)


# This bitmask is used in __static_getaddrinfo_pyaddr() to manage
# if ai_canonname should be set if AI_CANONNAME flag is set.
# This bitmask is lazily set in loop.getaddrinfo() to make sure that
# __static_getaddrinfo_pyaddr() behaves consistently as libc getaddrinfo().
# 1 << 0 : If 1 << 1 is set
# 1 << 1 : If ai_canonname should be set if AI_CANONNAME is set
# 1 << 2 : If 1 << 3 is set
# 1 << 3 : If ai_canonname should be set if AI_CANONNAME is not set
cdef int __static_getaddrinfo_canonname_mode = 0


cdef __static_getaddrinfo_pyaddr(object host, object port,
int family, int type,
int proto, int flags):
Expand All @@ -245,7 +256,20 @@ cdef __static_getaddrinfo_pyaddr(object host, object port,
except Exception:
return

return af, type, proto, '', pyaddr
if __static_getaddrinfo_canonname_mode & (
1 << 1 if flags & socket_AI_CANONNAME else 1 << 3
):
if isinstance(host, (bytes, bytearray)):
host = host.decode('ascii')
else:
host = ''
return (
_intenum_converter(af, socket_AddressFamily),
_intenum_converter(type, socket_SocketKind),
proto,
host,
pyaddr,
)


@cython.freelist(DEFAULT_FREELIST_SIZE)
Expand Down Expand Up @@ -276,8 +300,8 @@ cdef class AddrInfo:
while ptr != NULL:
if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
result.append((
ptr.ai_family,
ptr.ai_socktype,
_intenum_converter(ptr.ai_family, socket_AddressFamily),
_intenum_converter(ptr.ai_socktype, socket_SocketKind),
ptr.ai_protocol,
('' if ptr.ai_canonname is NULL else
(<bytes>ptr.ai_canonname).decode()),
Expand Down Expand Up @@ -370,6 +394,13 @@ cdef class NameInfoRequest(UVRequest):
self.callback(convert_error(err))


cdef _intenum_converter(value, enum_klass):
try:
return enum_klass(value)
except ValueError:
return value


cdef void __on_addrinfo_resolved(uv.uv_getaddrinfo_t *resolver,
int status, system.addrinfo *res) with gil:

Expand Down
1 change: 1 addition & 0 deletions uvloop/includes/stdlib.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ cdef int has_SO_REUSEPORT = hasattr(socket, 'SO_REUSEPORT')
cdef int SO_REUSEPORT = getattr(socket, 'SO_REUSEPORT', 0)
cdef int SO_BROADCAST = getattr(socket, 'SO_BROADCAST')
cdef int SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', -1)
cdef int socket_AI_CANONNAME = getattr(socket, 'AI_CANONNAME')

cdef socket_gaierror = socket.gaierror
cdef socket_error = socket.error
Expand Down
24 changes: 21 additions & 3 deletions uvloop/loop.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1523,13 +1523,31 @@ cdef class Loop:
@cython.iterable_coroutine
async def getaddrinfo(self, object host, object port, *,
int family=0, int type=0, int proto=0, int flags=0):
global __static_getaddrinfo_canonname_mode

addr = __static_getaddrinfo_pyaddr(host, port, family,
type, proto, flags)
if addr is not None:
fut = self._new_future()
fut.set_result([addr])
return await fut
if __static_getaddrinfo_canonname_mode & (
1 << 0 if flags & socket_AI_CANONNAME else 1 << 2
):
return [addr]

rv = await self._getaddrinfo(
host, port, family, type, proto, flags, 1)

if flags & socket_AI_CANONNAME:
if rv[0][3]:
__static_getaddrinfo_canonname_mode |= 1 << 0 | 1 << 1
else:
__static_getaddrinfo_canonname_mode |= 1 << 0
else:
if rv[0][3]:
__static_getaddrinfo_canonname_mode |= 1 << 2 | 1 << 3
else:
__static_getaddrinfo_canonname_mode |= 1 << 2

return rv

return await self._getaddrinfo(
host, port, family, type, proto, flags, 1)
Expand Down

0 comments on commit 64d6fe3

Please sign in to comment.