Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
86 changes: 75 additions & 11 deletions winloop/dns.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,18 @@ cdef class AddrInfo:
return type(other) is AddrInfo


# part of addrinfo's todolist. For now please leave this function here for the library owner/author.
ctypedef int (*addrinfo_callback)(object fut, object result) except -1

cdef class AddrInfoRequest(UVRequest):
cdef:
system.addrinfo hints
# TODO: ctypedef callbacks.
object callback
AddrInfoFuture fut
uv.uv_getaddrinfo_t _req_data


def __cinit__(self, Loop loop,
bytes host, bytes port,
int family, int type, int proto, int flags,
Expand Down Expand Up @@ -379,6 +385,7 @@ cdef class AddrInfoRequest(UVRequest):

self.request = <uv.uv_req_t*> &self._req_data
self.callback = callback
self.fut = AddrInfoFuture(loop, self)
self.request.data = <void*>self

err = uv.uv_getaddrinfo(loop.uvloop,
Expand Down Expand Up @@ -406,21 +413,34 @@ cdef class AddrInfoRequest(UVRequest):
else:
ex = convert_error(err)
except Exception as ex:
callback(ex)
callback(self.fut, ex)
else:
callback(ex)
callback(self.fut, ex)





# TODO: Combine UVRequest subclasses and Future objects together.
# It will mean less callbacks & costly interpreter code required.
ctypedef int (*nameinfo_callback)(object fut, object exception) except -1

cdef class NameInfoRequest(UVRequest):
cdef:
object callback
# TODO: ctypedef callbacks.
nameinfo_callback callback
NameInfoFuture fut
uv.uv_getnameinfo_t _req_data

def __cinit__(self, Loop loop, callback):
def __cinit__(self, Loop loop):
self.request = <uv.uv_req_t*> &self._req_data
self.callback = callback
self.fut = NameInfoFuture(loop, self)
self.request.data = <void*>self

cdef set_callback(self, nameinfo_callback cb):
self.callback = cb


cdef query(self, system.sockaddr *addr, int flags):
cdef int err
err = uv.uv_getnameinfo(self.loop.uvloop,
Expand All @@ -430,7 +450,48 @@ cdef class NameInfoRequest(UVRequest):
flags)
if err < 0:
self.on_done()
self.callback(convert_error(err))
self.callback(self.fut, convert_error(err))


# XXX: These subclasses are to ensure awaiting these objects does not
# trigger deadlocks (Example: what if NameInfoRequest is considered as being
# out of scope)

cdef class NameInfoFuture(Future):
cdef:
Loop loop
NameInfoRequest req

def __init__(self, Loop loop, NameInfoRequest req):
super().__init__(loop=loop)
self.req = req

cpdef object set_result(self, result):
return Future.set_result(self, result)

cpdef object set_exception(self, exc):
return Future.set_exception(self, exc)



cdef class AddrInfoFuture(Future):
cdef:
Loop loop
AddrInfoRequest req

def __init__(self, Loop loop, AddrInfoRequest req):
super().__init__(loop=loop)
self.req = req

cpdef object set_result(self, result):
return Future.set_result(self, result)

cpdef object set_exception(self, exc):
return Future.set_exception(self, exc)

cpdef bint cancelled(self) noexcept:
return Future.cancelled(self)



cdef _intenum_converter(value, enum_klass):
Expand All @@ -455,15 +516,17 @@ cdef void __on_addrinfo_resolved(
AddrInfoRequest request = <AddrInfoRequest> resolver.data
Loop loop = request.loop
object callback = request.callback
object fut = request.fut
AddrInfo ai


try:
if status < 0:
callback(convert_error(status))
callback(fut, convert_error(status))
else:
ai = AddrInfo()
ai.set_data(res)
callback(ai)
callback(fut, ai)
except (KeyboardInterrupt, SystemExit):
raise
except BaseException as ex:
Expand All @@ -481,13 +544,14 @@ cdef void __on_nameinfo_resolved(
cdef:
NameInfoRequest request = <NameInfoRequest> req.data
Loop loop = request.loop
object callback = request.callback
object fut = request.fut
nameinfo_callback callback = request.callback

try:
if status < 0:
callback(convert_error(status))
callback(fut, convert_error(status))
else:
callback(((<bytes>hostname).decode(),
callback(fut, ((<bytes>hostname).decode(),
(<bytes>service).decode()))
except (KeyboardInterrupt, SystemExit):
raise
Expand Down
4 changes: 2 additions & 2 deletions winloop/loop.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ cdef class Loop:
cdef inline _check_closed(self)
cdef inline _check_thread(self)

cdef Future _getaddrinfo(self, object host, object port,
cdef _getaddrinfo(self, object host, object port,
int family, int type,
int proto, int flags,
int unpack)

cdef Future _getnameinfo(self, system.sockaddr *addr, int flags)
cdef _getnameinfo(self, system.sockaddr *addr, int flags)

cdef _track_transport(self, UVBaseTransport transport)
cdef _fileobj_to_fd(self, fileobj)
Expand Down
64 changes: 33 additions & 31 deletions winloop/loop.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ cdef inline run_in_context2(context, method, arg1, arg2):
Context_Exit(context)


cdef int on_nameinfo_cb(fut, result) except -1:
cdef Future _fut = <Future>fut

# Ensure we can still stop midway through for any reason
# cython does automatic returning of -1
PyErr_CheckSignals()

if isinstance(result, tuple):
_fut.set_result(result)
else:
_fut.set_exception(result)
return 0

# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s
# *reuse_address* parameter
_unset = object()
Expand Down Expand Up @@ -892,12 +905,12 @@ cdef class Loop:

return poll.is_writing()

cdef Future _getaddrinfo(self, object host, object port,
cdef _getaddrinfo(self, object host, object port,
int family, int type,
int proto, int flags,
int unpack):

cdef Future fut
cdef AddrInfoRequest fut

if isinstance(port, str):
port = port.encode()
Expand All @@ -912,15 +925,13 @@ cdef class Loop:
if not isinstance(host, bytes):
raise TypeError('host must be a str or bytes')

# TODO: Use _new_future to return compiled Future objects
# in a later update (0.8.0)
fut = Future(loop=self)

# TODO: Sometime before or after 0.8.0,
# Let's Convert this callback to a ctypedef callback
# for added performance.
# example: ctypedef int (*addrinfo_callback)(Future fut, object result) except -1
def callback(fut, result):
def callback(_fut, result):
cdef AddrInfoFuture fut = <AddrInfoFuture>_fut
if AddrInfo.isinstance(result):
try:
if unpack == 0:
Expand All @@ -939,28 +950,15 @@ cdef class Loop:
if not fut.cancelled():
fut.set_exception(result)

# NOTE: ft_partial is needed to hold future for long enough
# otherwise 3.14t could freeze.
AddrInfoRequest(self, host, port, family, type, proto, flags, ft_partial(callback, fut))
return fut

cdef Future _getnameinfo(self, system.sockaddr *addr, int flags):
cdef NameInfoRequest nr
cdef Future fut
fut = Future(loop=self)

# Ditto of 0.8.0's TODO list:
# Something like ctypedef int (*nameinfo_callback)(Future, object) except -1
# would be sufficient.
def callback(fut, result):
if isinstance(result, tuple):
fut.set_result(result)
else:
fut.set_exception(result)
fut = AddrInfoRequest(self, host, port, family, type, proto, flags, callback)
return fut.fut

nr = NameInfoRequest(self, ft_partial(callback, fut))
nr.query(addr, flags)
return fut
cdef _getnameinfo(self, system.sockaddr *addr, int flags):
cdef NameInfoRequest req
req = NameInfoRequest(self)
req.set_callback(on_nameinfo_cb)
req.query(addr, flags)
return req.fut

cdef _sock_recv(self, _fut, sock, n):
cdef _SyncSocketReaderFuture fut = <_SyncSocketReaderFuture>_fut
Expand Down Expand Up @@ -1559,22 +1557,25 @@ 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):

cdef AddrInfoFuture aif
addr = __static_getaddrinfo_pyaddr(host, port, family,
type, proto, flags)
if addr is not None:
return [addr]

return await self._getaddrinfo(
# recast so that we don't need a dns.pxd file
# and we still get compilation benefits.
aif = <AddrInfoFuture>self._getaddrinfo(
host, port, family, type, proto, flags, 1)

return await aif

@cython.iterable_coroutine
async def getnameinfo(self, sockaddr, int flags=0):
cdef:
AddrInfo ai_cnt
system.addrinfo *ai
system.sockaddr_in6 *sin6
NameInfoFuture nif

if not isinstance(sockaddr, tuple):
raise TypeError('getnameinfo() argument 1 must be a tuple')
Expand Down Expand Up @@ -1622,7 +1623,8 @@ cdef class Loop:
sin6.sin6_flowinfo = system.htonl(flowinfo)
sin6.sin6_scope_id = scope_id

return await self._getnameinfo(ai.ai_addr, flags)
nif = <NameInfoFuture>self._getnameinfo(ai.ai_addr, flags)
return await nif

@cython.iterable_coroutine
async def start_tls(self, transport, protocol, sslcontext, *,
Expand Down
Loading