Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix loop.getaddrinfo() and tests #495

Merged
merged 3 commits into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
40 changes: 37 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,23 @@ 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, str):
canon_name = host
else:
canon_name = host.decode('ascii')
else:
canon_name = ''

return (
_intenum_converter(af, socket_AddressFamily),
_intenum_converter(type, socket_SocketKind),
proto,
canon_name,
pyaddr,
)


@cython.freelist(DEFAULT_FREELIST_SIZE)
Expand Down Expand Up @@ -276,8 +303,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 +397,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]:
fantix marked this conversation as resolved.
Show resolved Hide resolved
__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