second commit
This commit is contained in:
168
env/lib/python3.11/site-packages/uvloop/__init__.py
vendored
Normal file
168
env/lib/python3.11/site-packages/uvloop/__init__.py
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
import asyncio as __asyncio
|
||||
import typing as _typing
|
||||
import sys as _sys
|
||||
import warnings as _warnings
|
||||
|
||||
from asyncio.events import BaseDefaultEventLoopPolicy as __BasePolicy
|
||||
|
||||
from . import includes as __includes # NOQA
|
||||
from .loop import Loop as __BaseLoop # NOQA
|
||||
from ._version import __version__ # NOQA
|
||||
|
||||
|
||||
__all__ = ('new_event_loop', 'install', 'EventLoopPolicy')
|
||||
|
||||
|
||||
_T = _typing.TypeVar("_T")
|
||||
|
||||
|
||||
class Loop(__BaseLoop, __asyncio.AbstractEventLoop): # type: ignore[misc]
|
||||
pass
|
||||
|
||||
|
||||
def new_event_loop() -> Loop:
|
||||
"""Return a new event loop."""
|
||||
return Loop()
|
||||
|
||||
|
||||
def install() -> None:
|
||||
"""A helper function to install uvloop policy."""
|
||||
if _sys.version_info[:2] >= (3, 12):
|
||||
_warnings.warn(
|
||||
'uvloop.install() is deprecated in favor of uvloop.run() '
|
||||
'starting with Python 3.12.',
|
||||
DeprecationWarning,
|
||||
stacklevel=1,
|
||||
)
|
||||
__asyncio.set_event_loop_policy(EventLoopPolicy())
|
||||
|
||||
|
||||
if _typing.TYPE_CHECKING:
|
||||
def run(
|
||||
main: _typing.Coroutine[_typing.Any, _typing.Any, _T],
|
||||
*,
|
||||
loop_factory: _typing.Optional[
|
||||
_typing.Callable[[], Loop]
|
||||
] = new_event_loop,
|
||||
debug: _typing.Optional[bool]=None,
|
||||
) -> _T:
|
||||
"""The preferred way of running a coroutine with uvloop."""
|
||||
else:
|
||||
def run(main, *, loop_factory=new_event_loop, debug=None, **run_kwargs):
|
||||
"""The preferred way of running a coroutine with uvloop."""
|
||||
|
||||
async def wrapper():
|
||||
# If `loop_factory` is provided we want it to return
|
||||
# either uvloop.Loop or a subtype of it, assuming the user
|
||||
# is using `uvloop.run()` intentionally.
|
||||
loop = __asyncio._get_running_loop()
|
||||
if not isinstance(loop, Loop):
|
||||
raise TypeError('uvloop.run() uses a non-uvloop event loop')
|
||||
return await main
|
||||
|
||||
vi = _sys.version_info[:2]
|
||||
|
||||
if vi <= (3, 10):
|
||||
# Copied from python/cpython
|
||||
|
||||
if __asyncio._get_running_loop() is not None:
|
||||
raise RuntimeError(
|
||||
"asyncio.run() cannot be called from a running event loop")
|
||||
|
||||
if not __asyncio.iscoroutine(main):
|
||||
raise ValueError(
|
||||
"a coroutine was expected, got {!r}".format(main)
|
||||
)
|
||||
|
||||
loop = loop_factory()
|
||||
try:
|
||||
__asyncio.set_event_loop(loop)
|
||||
if debug is not None:
|
||||
loop.set_debug(debug)
|
||||
return loop.run_until_complete(wrapper())
|
||||
finally:
|
||||
try:
|
||||
_cancel_all_tasks(loop)
|
||||
loop.run_until_complete(loop.shutdown_asyncgens())
|
||||
if hasattr(loop, 'shutdown_default_executor'):
|
||||
loop.run_until_complete(
|
||||
loop.shutdown_default_executor()
|
||||
)
|
||||
finally:
|
||||
__asyncio.set_event_loop(None)
|
||||
loop.close()
|
||||
|
||||
elif vi == (3, 11):
|
||||
if __asyncio._get_running_loop() is not None:
|
||||
raise RuntimeError(
|
||||
"asyncio.run() cannot be called from a running event loop")
|
||||
|
||||
with __asyncio.Runner(
|
||||
loop_factory=loop_factory,
|
||||
debug=debug,
|
||||
**run_kwargs
|
||||
) as runner:
|
||||
return runner.run(wrapper())
|
||||
|
||||
else:
|
||||
assert vi >= (3, 12)
|
||||
return __asyncio.run(
|
||||
wrapper(),
|
||||
loop_factory=loop_factory,
|
||||
debug=debug,
|
||||
**run_kwargs
|
||||
)
|
||||
|
||||
|
||||
def _cancel_all_tasks(loop: __asyncio.AbstractEventLoop) -> None:
|
||||
# Copied from python/cpython
|
||||
|
||||
to_cancel = __asyncio.all_tasks(loop)
|
||||
if not to_cancel:
|
||||
return
|
||||
|
||||
for task in to_cancel:
|
||||
task.cancel()
|
||||
|
||||
loop.run_until_complete(
|
||||
__asyncio.gather(*to_cancel, return_exceptions=True)
|
||||
)
|
||||
|
||||
for task in to_cancel:
|
||||
if task.cancelled():
|
||||
continue
|
||||
if task.exception() is not None:
|
||||
loop.call_exception_handler({
|
||||
'message': 'unhandled exception during asyncio.run() shutdown',
|
||||
'exception': task.exception(),
|
||||
'task': task,
|
||||
})
|
||||
|
||||
|
||||
class EventLoopPolicy(__BasePolicy):
|
||||
"""Event loop policy.
|
||||
|
||||
The preferred way to make your application use uvloop:
|
||||
|
||||
>>> import asyncio
|
||||
>>> import uvloop
|
||||
>>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
|
||||
>>> asyncio.get_event_loop()
|
||||
<uvloop.Loop running=False closed=False debug=False>
|
||||
"""
|
||||
|
||||
def _loop_factory(self) -> Loop:
|
||||
return new_event_loop()
|
||||
|
||||
if _typing.TYPE_CHECKING:
|
||||
# EventLoopPolicy doesn't implement these, but since they are marked
|
||||
# as abstract in typeshed, we have to put them in so mypy thinks
|
||||
# the base methods are overridden. This is the same approach taken
|
||||
# for the Windows event loop policy classes in typeshed.
|
||||
def get_child_watcher(self) -> _typing.NoReturn:
|
||||
...
|
||||
|
||||
def set_child_watcher(
|
||||
self, watcher: _typing.Any
|
||||
) -> _typing.NoReturn:
|
||||
...
|
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc
vendored
Normal file
Binary file not shown.
3
env/lib/python3.11/site-packages/uvloop/_noop.py
vendored
Normal file
3
env/lib/python3.11/site-packages/uvloop/_noop.py
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
def noop() -> None:
|
||||
"""Empty function to invoke CPython ceval loop."""
|
||||
return
|
552
env/lib/python3.11/site-packages/uvloop/_testbase.py
vendored
Normal file
552
env/lib/python3.11/site-packages/uvloop/_testbase.py
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
"""Test utilities. Don't use outside of the uvloop project."""
|
||||
|
||||
|
||||
import asyncio
|
||||
import asyncio.events
|
||||
import collections
|
||||
import contextlib
|
||||
import gc
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
import select
|
||||
import socket
|
||||
import ssl
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import uvloop
|
||||
|
||||
|
||||
class MockPattern(str):
|
||||
def __eq__(self, other):
|
||||
return bool(re.search(str(self), other, re.S))
|
||||
|
||||
|
||||
class TestCaseDict(collections.UserDict):
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key in self.data:
|
||||
raise RuntimeError('duplicate test {}.{}'.format(
|
||||
self.name, key))
|
||||
super().__setitem__(key, value)
|
||||
|
||||
|
||||
class BaseTestCaseMeta(type):
|
||||
|
||||
@classmethod
|
||||
def __prepare__(mcls, name, bases):
|
||||
return TestCaseDict(name)
|
||||
|
||||
def __new__(mcls, name, bases, dct):
|
||||
for test_name in dct:
|
||||
if not test_name.startswith('test_'):
|
||||
continue
|
||||
for base in bases:
|
||||
if hasattr(base, test_name):
|
||||
raise RuntimeError(
|
||||
'duplicate test {}.{} (also defined in {} '
|
||||
'parent class)'.format(
|
||||
name, test_name, base.__name__))
|
||||
|
||||
return super().__new__(mcls, name, bases, dict(dct))
|
||||
|
||||
|
||||
class BaseTestCase(unittest.TestCase, metaclass=BaseTestCaseMeta):
|
||||
|
||||
def new_loop(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def new_policy(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def mock_pattern(self, str):
|
||||
return MockPattern(str)
|
||||
|
||||
async def wait_closed(self, obj):
|
||||
if not isinstance(obj, asyncio.StreamWriter):
|
||||
return
|
||||
try:
|
||||
await obj.wait_closed()
|
||||
except (BrokenPipeError, ConnectionError):
|
||||
pass
|
||||
|
||||
def is_asyncio_loop(self):
|
||||
return type(self.loop).__module__.startswith('asyncio.')
|
||||
|
||||
def run_loop_briefly(self, *, delay=0.01):
|
||||
self.loop.run_until_complete(asyncio.sleep(delay))
|
||||
|
||||
def loop_exception_handler(self, loop, context):
|
||||
self.__unhandled_exceptions.append(context)
|
||||
self.loop.default_exception_handler(context)
|
||||
|
||||
def setUp(self):
|
||||
self.loop = self.new_loop()
|
||||
asyncio.set_event_loop_policy(self.new_policy())
|
||||
asyncio.set_event_loop(self.loop)
|
||||
self._check_unclosed_resources_in_debug = True
|
||||
|
||||
self.loop.set_exception_handler(self.loop_exception_handler)
|
||||
self.__unhandled_exceptions = []
|
||||
|
||||
def tearDown(self):
|
||||
self.loop.close()
|
||||
|
||||
if self.__unhandled_exceptions:
|
||||
print('Unexpected calls to loop.call_exception_handler():')
|
||||
pprint.pprint(self.__unhandled_exceptions)
|
||||
self.fail('unexpected calls to loop.call_exception_handler()')
|
||||
return
|
||||
|
||||
if not self._check_unclosed_resources_in_debug:
|
||||
return
|
||||
|
||||
# GC to show any resource warnings as the test completes
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
|
||||
if getattr(self.loop, '_debug_cc', False):
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
gc.collect()
|
||||
|
||||
self.assertEqual(
|
||||
self.loop._debug_uv_handles_total,
|
||||
self.loop._debug_uv_handles_freed,
|
||||
'not all uv_handle_t handles were freed')
|
||||
|
||||
self.assertEqual(
|
||||
self.loop._debug_cb_handles_count, 0,
|
||||
'not all callbacks (call_soon) are GCed')
|
||||
|
||||
self.assertEqual(
|
||||
self.loop._debug_cb_timer_handles_count, 0,
|
||||
'not all timer callbacks (call_later) are GCed')
|
||||
|
||||
self.assertEqual(
|
||||
self.loop._debug_stream_write_ctx_cnt, 0,
|
||||
'not all stream write contexts are GCed')
|
||||
|
||||
for h_name, h_cnt in self.loop._debug_handles_current.items():
|
||||
with self.subTest('Alive handle after test',
|
||||
handle_name=h_name):
|
||||
self.assertEqual(
|
||||
h_cnt, 0,
|
||||
'alive {} after test'.format(h_name))
|
||||
|
||||
for h_name, h_cnt in self.loop._debug_handles_total.items():
|
||||
with self.subTest('Total/closed handles',
|
||||
handle_name=h_name):
|
||||
self.assertEqual(
|
||||
h_cnt, self.loop._debug_handles_closed[h_name],
|
||||
'total != closed for {}'.format(h_name))
|
||||
|
||||
asyncio.set_event_loop(None)
|
||||
asyncio.set_event_loop_policy(None)
|
||||
self.loop = None
|
||||
|
||||
def skip_unclosed_handles_check(self):
|
||||
self._check_unclosed_resources_in_debug = False
|
||||
|
||||
def tcp_server(self, server_prog, *,
|
||||
family=socket.AF_INET,
|
||||
addr=None,
|
||||
timeout=5,
|
||||
backlog=1,
|
||||
max_clients=10):
|
||||
|
||||
if addr is None:
|
||||
if family == socket.AF_UNIX:
|
||||
with tempfile.NamedTemporaryFile() as tmp:
|
||||
addr = tmp.name
|
||||
else:
|
||||
addr = ('127.0.0.1', 0)
|
||||
|
||||
sock = socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
if timeout is None:
|
||||
raise RuntimeError('timeout is required')
|
||||
if timeout <= 0:
|
||||
raise RuntimeError('only blocking sockets are supported')
|
||||
sock.settimeout(timeout)
|
||||
|
||||
try:
|
||||
sock.bind(addr)
|
||||
sock.listen(backlog)
|
||||
except OSError as ex:
|
||||
sock.close()
|
||||
raise ex
|
||||
|
||||
return TestThreadedServer(
|
||||
self, sock, server_prog, timeout, max_clients)
|
||||
|
||||
def tcp_client(self, client_prog,
|
||||
family=socket.AF_INET,
|
||||
timeout=10):
|
||||
|
||||
sock = socket.socket(family, socket.SOCK_STREAM)
|
||||
|
||||
if timeout is None:
|
||||
raise RuntimeError('timeout is required')
|
||||
if timeout <= 0:
|
||||
raise RuntimeError('only blocking sockets are supported')
|
||||
sock.settimeout(timeout)
|
||||
|
||||
return TestThreadedClient(
|
||||
self, sock, client_prog, timeout)
|
||||
|
||||
def unix_server(self, *args, **kwargs):
|
||||
return self.tcp_server(*args, family=socket.AF_UNIX, **kwargs)
|
||||
|
||||
def unix_client(self, *args, **kwargs):
|
||||
return self.tcp_client(*args, family=socket.AF_UNIX, **kwargs)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def unix_sock_name(self):
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fn = os.path.join(td, 'sock')
|
||||
try:
|
||||
yield fn
|
||||
finally:
|
||||
try:
|
||||
os.unlink(fn)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _abort_socket_test(self, ex):
|
||||
try:
|
||||
self.loop.stop()
|
||||
finally:
|
||||
self.fail(ex)
|
||||
|
||||
|
||||
def _cert_fullname(test_file_name, cert_file_name):
|
||||
fullname = os.path.abspath(os.path.join(
|
||||
os.path.dirname(test_file_name), 'certs', cert_file_name))
|
||||
assert os.path.isfile(fullname)
|
||||
return fullname
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def silence_long_exec_warning():
|
||||
|
||||
class Filter(logging.Filter):
|
||||
def filter(self, record):
|
||||
return not (record.msg.startswith('Executing') and
|
||||
record.msg.endswith('seconds'))
|
||||
|
||||
logger = logging.getLogger('asyncio')
|
||||
filter = Filter()
|
||||
logger.addFilter(filter)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
logger.removeFilter(filter)
|
||||
|
||||
|
||||
def find_free_port(start_from=50000):
|
||||
for port in range(start_from, start_from + 500):
|
||||
sock = socket.socket()
|
||||
with sock:
|
||||
try:
|
||||
sock.bind(('', port))
|
||||
except socket.error:
|
||||
continue
|
||||
else:
|
||||
return port
|
||||
raise RuntimeError('could not find a free port')
|
||||
|
||||
|
||||
class SSLTestCase:
|
||||
|
||||
def _create_server_ssl_context(self, certfile, keyfile=None):
|
||||
if hasattr(ssl, 'PROTOCOL_TLS_SERVER'):
|
||||
sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
elif hasattr(ssl, 'PROTOCOL_TLS'):
|
||||
sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
else:
|
||||
sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
sslcontext.options |= ssl.OP_NO_SSLv2
|
||||
sslcontext.load_cert_chain(certfile, keyfile)
|
||||
return sslcontext
|
||||
|
||||
def _create_client_ssl_context(self, *, disable_verify=True):
|
||||
sslcontext = ssl.create_default_context()
|
||||
sslcontext.check_hostname = False
|
||||
if disable_verify:
|
||||
sslcontext.verify_mode = ssl.CERT_NONE
|
||||
return sslcontext
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _silence_eof_received_warning(self):
|
||||
# TODO This warning has to be fixed in asyncio.
|
||||
logger = logging.getLogger('asyncio')
|
||||
filter = logging.Filter('has no effect when using ssl')
|
||||
logger.addFilter(filter)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
logger.removeFilter(filter)
|
||||
|
||||
|
||||
class UVTestCase(BaseTestCase):
|
||||
|
||||
implementation = 'uvloop'
|
||||
|
||||
def new_loop(self):
|
||||
return uvloop.new_event_loop()
|
||||
|
||||
def new_policy(self):
|
||||
return uvloop.EventLoopPolicy()
|
||||
|
||||
|
||||
class AIOTestCase(BaseTestCase):
|
||||
|
||||
implementation = 'asyncio'
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
if sys.version_info < (3, 12):
|
||||
watcher = asyncio.SafeChildWatcher()
|
||||
watcher.attach_loop(self.loop)
|
||||
asyncio.set_child_watcher(watcher)
|
||||
|
||||
def tearDown(self):
|
||||
if sys.version_info < (3, 12):
|
||||
asyncio.set_child_watcher(None)
|
||||
super().tearDown()
|
||||
|
||||
def new_loop(self):
|
||||
return asyncio.new_event_loop()
|
||||
|
||||
def new_policy(self):
|
||||
return asyncio.DefaultEventLoopPolicy()
|
||||
|
||||
|
||||
def has_IPv6():
|
||||
server_sock = socket.socket(socket.AF_INET6)
|
||||
with server_sock:
|
||||
try:
|
||||
server_sock.bind(('::1', 0))
|
||||
except OSError:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
has_IPv6 = has_IPv6()
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Socket Testing Utilities
|
||||
###############################################################################
|
||||
|
||||
|
||||
class TestSocketWrapper:
|
||||
|
||||
def __init__(self, sock):
|
||||
self.__sock = sock
|
||||
|
||||
def recv_all(self, n):
|
||||
buf = b''
|
||||
while len(buf) < n:
|
||||
data = self.recv(n - len(buf))
|
||||
if data == b'':
|
||||
raise ConnectionAbortedError
|
||||
buf += data
|
||||
return buf
|
||||
|
||||
def starttls(self, ssl_context, *,
|
||||
server_side=False,
|
||||
server_hostname=None,
|
||||
do_handshake_on_connect=True):
|
||||
|
||||
assert isinstance(ssl_context, ssl.SSLContext)
|
||||
|
||||
ssl_sock = ssl_context.wrap_socket(
|
||||
self.__sock, server_side=server_side,
|
||||
server_hostname=server_hostname,
|
||||
do_handshake_on_connect=do_handshake_on_connect)
|
||||
|
||||
if server_side:
|
||||
ssl_sock.do_handshake()
|
||||
|
||||
self.__sock.close()
|
||||
self.__sock = ssl_sock
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.__sock, name)
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} {!r}>'.format(type(self).__name__, self.__sock)
|
||||
|
||||
|
||||
class SocketThread(threading.Thread):
|
||||
|
||||
def stop(self):
|
||||
self._active = False
|
||||
self.join()
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
self.stop()
|
||||
|
||||
|
||||
class TestThreadedClient(SocketThread):
|
||||
|
||||
def __init__(self, test, sock, prog, timeout):
|
||||
threading.Thread.__init__(self, None, None, 'test-client')
|
||||
self.daemon = True
|
||||
|
||||
self._timeout = timeout
|
||||
self._sock = sock
|
||||
self._active = True
|
||||
self._prog = prog
|
||||
self._test = test
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self._prog(TestSocketWrapper(self._sock))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
self._test._abort_socket_test(ex)
|
||||
|
||||
|
||||
class TestThreadedServer(SocketThread):
|
||||
|
||||
def __init__(self, test, sock, prog, timeout, max_clients):
|
||||
threading.Thread.__init__(self, None, None, 'test-server')
|
||||
self.daemon = True
|
||||
|
||||
self._clients = 0
|
||||
self._finished_clients = 0
|
||||
self._max_clients = max_clients
|
||||
self._timeout = timeout
|
||||
self._sock = sock
|
||||
self._active = True
|
||||
|
||||
self._prog = prog
|
||||
|
||||
self._s1, self._s2 = socket.socketpair()
|
||||
self._s1.setblocking(False)
|
||||
|
||||
self._test = test
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
if self._s2 and self._s2.fileno() != -1:
|
||||
try:
|
||||
self._s2.send(b'stop')
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
super().stop()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
with self._sock:
|
||||
self._sock.setblocking(0)
|
||||
self._run()
|
||||
finally:
|
||||
self._s1.close()
|
||||
self._s2.close()
|
||||
|
||||
def _run(self):
|
||||
while self._active:
|
||||
if self._clients >= self._max_clients:
|
||||
return
|
||||
|
||||
r, w, x = select.select(
|
||||
[self._sock, self._s1], [], [], self._timeout)
|
||||
|
||||
if self._s1 in r:
|
||||
return
|
||||
|
||||
if self._sock in r:
|
||||
try:
|
||||
conn, addr = self._sock.accept()
|
||||
except BlockingIOError:
|
||||
continue
|
||||
except socket.timeout:
|
||||
if not self._active:
|
||||
return
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
self._clients += 1
|
||||
conn.settimeout(self._timeout)
|
||||
try:
|
||||
with conn:
|
||||
self._handle_client(conn)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
self._active = False
|
||||
try:
|
||||
raise
|
||||
finally:
|
||||
self._test._abort_socket_test(ex)
|
||||
|
||||
def _handle_client(self, sock):
|
||||
self._prog(TestSocketWrapper(sock))
|
||||
|
||||
@property
|
||||
def addr(self):
|
||||
return self._sock.getsockname()
|
||||
|
||||
|
||||
###############################################################################
|
||||
# A few helpers from asyncio/tests/testutils.py
|
||||
###############################################################################
|
||||
|
||||
|
||||
def run_briefly(loop):
|
||||
async def once():
|
||||
pass
|
||||
gen = once()
|
||||
t = loop.create_task(gen)
|
||||
# Don't log a warning if the task is not done after run_until_complete().
|
||||
# It occurs if the loop is stopped or if a task raises a BaseException.
|
||||
t._log_destroy_pending = False
|
||||
try:
|
||||
loop.run_until_complete(t)
|
||||
finally:
|
||||
gen.close()
|
||||
|
||||
|
||||
def run_until(loop, pred, timeout=30):
|
||||
deadline = time.time() + timeout
|
||||
while not pred():
|
||||
if timeout is not None:
|
||||
timeout = deadline - time.time()
|
||||
if timeout <= 0:
|
||||
raise asyncio.futures.TimeoutError()
|
||||
loop.run_until_complete(asyncio.tasks.sleep(0.001))
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def disable_logger():
|
||||
"""Context manager to disable asyncio logger.
|
||||
|
||||
For example, it can be used to ignore warnings in debug mode.
|
||||
"""
|
||||
old_level = asyncio.log.logger.level
|
||||
try:
|
||||
asyncio.log.logger.setLevel(logging.CRITICAL + 1)
|
||||
yield
|
||||
finally:
|
||||
asyncio.log.logger.setLevel(old_level)
|
13
env/lib/python3.11/site-packages/uvloop/_version.py
vendored
Normal file
13
env/lib/python3.11/site-packages/uvloop/_version.py
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# This file MUST NOT contain anything but the __version__ assignment.
|
||||
#
|
||||
# When making a release, change the value of __version__
|
||||
# to an appropriate value, and open a pull request against
|
||||
# the correct branch (master if making a new feature release).
|
||||
# The commit message MUST contain a properly formatted release
|
||||
# log, and the commit must be signed.
|
||||
#
|
||||
# The release automation will: build and test the packages for the
|
||||
# supported platforms, publish the packages on PyPI, merge the PR
|
||||
# to the target branch, create a Git tag pointing to the commit.
|
||||
|
||||
__version__ = '0.21.0'
|
39
env/lib/python3.11/site-packages/uvloop/cbhandles.pxd
vendored
Normal file
39
env/lib/python3.11/site-packages/uvloop/cbhandles.pxd
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
cdef class Handle:
|
||||
cdef:
|
||||
Loop loop
|
||||
object context
|
||||
bint _cancelled
|
||||
|
||||
str meth_name
|
||||
int cb_type
|
||||
void *callback
|
||||
object arg1, arg2, arg3, arg4
|
||||
|
||||
object __weakref__
|
||||
|
||||
readonly _source_traceback
|
||||
|
||||
cdef inline _set_loop(self, Loop loop)
|
||||
cdef inline _set_context(self, object context)
|
||||
|
||||
cdef inline _run(self)
|
||||
cdef _cancel(self)
|
||||
|
||||
cdef _format_handle(self)
|
||||
|
||||
|
||||
cdef class TimerHandle:
|
||||
cdef:
|
||||
object callback
|
||||
tuple args
|
||||
bint _cancelled
|
||||
UVTimer timer
|
||||
Loop loop
|
||||
object context
|
||||
tuple _debug_info
|
||||
object __weakref__
|
||||
object _when
|
||||
|
||||
cdef _run(self)
|
||||
cdef _cancel(self)
|
||||
cdef inline _clear(self)
|
434
env/lib/python3.11/site-packages/uvloop/cbhandles.pyx
vendored
Normal file
434
env/lib/python3.11/site-packages/uvloop/cbhandles.pyx
vendored
Normal file
@ -0,0 +1,434 @@
|
||||
@cython.no_gc_clear
|
||||
@cython.freelist(DEFAULT_FREELIST_SIZE)
|
||||
cdef class Handle:
|
||||
def __cinit__(self):
|
||||
self._cancelled = 0
|
||||
self.cb_type = 0
|
||||
self._source_traceback = None
|
||||
|
||||
cdef inline _set_loop(self, Loop loop):
|
||||
self.loop = loop
|
||||
if UVLOOP_DEBUG:
|
||||
loop._debug_cb_handles_total += 1
|
||||
loop._debug_cb_handles_count += 1
|
||||
if loop._debug:
|
||||
self._source_traceback = extract_stack()
|
||||
|
||||
cdef inline _set_context(self, object context):
|
||||
if context is None:
|
||||
context = Context_CopyCurrent()
|
||||
self.context = context
|
||||
|
||||
def __dealloc__(self):
|
||||
if UVLOOP_DEBUG and self.loop is not None:
|
||||
self.loop._debug_cb_handles_count -= 1
|
||||
if self.loop is None:
|
||||
raise RuntimeError('Handle.loop is None in Handle.__dealloc__')
|
||||
|
||||
def __init__(self):
|
||||
raise TypeError(
|
||||
'{} is not supposed to be instantiated from Python'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
cdef inline _run(self):
|
||||
cdef:
|
||||
int cb_type
|
||||
object callback
|
||||
|
||||
if self._cancelled:
|
||||
return
|
||||
|
||||
cb_type = self.cb_type
|
||||
|
||||
# Since _run is a cdef and there's no BoundMethod,
|
||||
# we guard 'self' manually (since the callback
|
||||
# might cause GC of the handle.)
|
||||
Py_INCREF(self)
|
||||
|
||||
try:
|
||||
assert self.context is not None
|
||||
Context_Enter(self.context)
|
||||
|
||||
if cb_type == 1:
|
||||
callback = self.arg1
|
||||
if callback is None:
|
||||
raise RuntimeError(
|
||||
'cannot run Handle; callback is not set')
|
||||
|
||||
args = self.arg2
|
||||
|
||||
if args is None:
|
||||
callback()
|
||||
else:
|
||||
callback(*args)
|
||||
|
||||
elif cb_type == 2:
|
||||
(<method_t>self.callback)(self.arg1)
|
||||
|
||||
elif cb_type == 3:
|
||||
(<method1_t>self.callback)(self.arg1, self.arg2)
|
||||
|
||||
elif cb_type == 4:
|
||||
(<method2_t>self.callback)(self.arg1, self.arg2, self.arg3)
|
||||
|
||||
elif cb_type == 5:
|
||||
(<method3_t>self.callback)(
|
||||
self.arg1, self.arg2, self.arg3, self.arg4)
|
||||
|
||||
else:
|
||||
raise RuntimeError('invalid Handle.cb_type: {}'.format(
|
||||
cb_type))
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
if cb_type == 1:
|
||||
msg = 'Exception in callback {}'.format(callback)
|
||||
else:
|
||||
msg = 'Exception in callback {}'.format(self.meth_name)
|
||||
|
||||
context = {
|
||||
'message': msg,
|
||||
'exception': ex,
|
||||
'handle': self,
|
||||
}
|
||||
|
||||
if self._source_traceback is not None:
|
||||
context['source_traceback'] = self._source_traceback
|
||||
|
||||
self.loop.call_exception_handler(context)
|
||||
|
||||
finally:
|
||||
context = self.context
|
||||
Py_DECREF(self)
|
||||
Context_Exit(context)
|
||||
|
||||
cdef _cancel(self):
|
||||
self._cancelled = 1
|
||||
self.callback = NULL
|
||||
self.arg1 = self.arg2 = self.arg3 = self.arg4 = None
|
||||
|
||||
cdef _format_handle(self):
|
||||
# Mirrors `asyncio.base_events._format_handle`.
|
||||
if self.cb_type == 1 and self.arg1 is not None:
|
||||
cb = self.arg1
|
||||
if isinstance(getattr(cb, '__self__', None), aio_Task):
|
||||
try:
|
||||
return repr(cb.__self__)
|
||||
except (AttributeError, TypeError, ValueError) as ex:
|
||||
# Cython generates empty __code__ objects for coroutines
|
||||
# that can crash asyncio.Task.__repr__ with an
|
||||
# AttributeError etc. Guard against that.
|
||||
self.loop.call_exception_handler({
|
||||
'message': 'exception in Task.__repr__',
|
||||
'task': cb.__self__,
|
||||
'exception': ex,
|
||||
'handle': self,
|
||||
})
|
||||
return repr(self)
|
||||
|
||||
# Public API
|
||||
|
||||
def __repr__(self):
|
||||
info = [self.__class__.__name__]
|
||||
|
||||
if self._cancelled:
|
||||
info.append('cancelled')
|
||||
|
||||
if self.cb_type == 1 and self.arg1 is not None:
|
||||
func = self.arg1
|
||||
# Cython can unset func.__qualname__/__name__, hence the checks.
|
||||
if hasattr(func, '__qualname__') and func.__qualname__:
|
||||
cb_name = func.__qualname__
|
||||
elif hasattr(func, '__name__') and func.__name__:
|
||||
cb_name = func.__name__
|
||||
else:
|
||||
cb_name = repr(func)
|
||||
|
||||
info.append(cb_name)
|
||||
elif self.meth_name is not None:
|
||||
info.append(self.meth_name)
|
||||
|
||||
if self._source_traceback is not None:
|
||||
frame = self._source_traceback[-1]
|
||||
info.append('created at {}:{}'.format(frame[0], frame[1]))
|
||||
|
||||
return '<' + ' '.join(info) + '>'
|
||||
|
||||
def cancel(self):
|
||||
self._cancel()
|
||||
|
||||
def cancelled(self):
|
||||
return self._cancelled
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
@cython.freelist(DEFAULT_FREELIST_SIZE)
|
||||
cdef class TimerHandle:
|
||||
def __cinit__(self, Loop loop, object callback, object args,
|
||||
uint64_t delay, object context):
|
||||
|
||||
self.loop = loop
|
||||
self.callback = callback
|
||||
self.args = args
|
||||
self._cancelled = 0
|
||||
|
||||
if UVLOOP_DEBUG:
|
||||
self.loop._debug_cb_timer_handles_total += 1
|
||||
self.loop._debug_cb_timer_handles_count += 1
|
||||
|
||||
if context is None:
|
||||
context = Context_CopyCurrent()
|
||||
self.context = context
|
||||
|
||||
if loop._debug:
|
||||
self._debug_info = (
|
||||
format_callback_name(callback),
|
||||
extract_stack()
|
||||
)
|
||||
else:
|
||||
self._debug_info = None
|
||||
|
||||
self.timer = UVTimer.new(
|
||||
loop, <method_t>self._run, self, delay)
|
||||
|
||||
self.timer.start()
|
||||
self._when = self.timer.get_when() * 1e-3
|
||||
|
||||
# Only add to loop._timers when `self.timer` is successfully created
|
||||
loop._timers.add(self)
|
||||
|
||||
property _source_traceback:
|
||||
def __get__(self):
|
||||
if self._debug_info is not None:
|
||||
return self._debug_info[1]
|
||||
|
||||
def __dealloc__(self):
|
||||
if UVLOOP_DEBUG:
|
||||
self.loop._debug_cb_timer_handles_count -= 1
|
||||
if self.timer is not None:
|
||||
raise RuntimeError('active TimerHandle is deallacating')
|
||||
|
||||
cdef _cancel(self):
|
||||
if self._cancelled == 1:
|
||||
return
|
||||
self._cancelled = 1
|
||||
self._clear()
|
||||
|
||||
cdef inline _clear(self):
|
||||
if self.timer is None:
|
||||
return
|
||||
|
||||
self.callback = None
|
||||
self.args = None
|
||||
|
||||
try:
|
||||
self.loop._timers.remove(self)
|
||||
finally:
|
||||
self.timer._close()
|
||||
self.timer = None # let the UVTimer handle GC
|
||||
|
||||
cdef _run(self):
|
||||
if self._cancelled == 1:
|
||||
return
|
||||
if self.callback is None:
|
||||
raise RuntimeError('cannot run TimerHandle; callback is not set')
|
||||
|
||||
callback = self.callback
|
||||
args = self.args
|
||||
|
||||
# Since _run is a cdef and there's no BoundMethod,
|
||||
# we guard 'self' manually.
|
||||
Py_INCREF(self)
|
||||
|
||||
if self.loop._debug:
|
||||
started = time_monotonic()
|
||||
try:
|
||||
assert self.context is not None
|
||||
Context_Enter(self.context)
|
||||
|
||||
if args is not None:
|
||||
callback(*args)
|
||||
else:
|
||||
callback()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
context = {
|
||||
'message': 'Exception in callback {}'.format(callback),
|
||||
'exception': ex,
|
||||
'handle': self,
|
||||
}
|
||||
|
||||
if self._debug_info is not None:
|
||||
context['source_traceback'] = self._debug_info[1]
|
||||
|
||||
self.loop.call_exception_handler(context)
|
||||
else:
|
||||
if self.loop._debug:
|
||||
delta = time_monotonic() - started
|
||||
if delta > self.loop.slow_callback_duration:
|
||||
aio_logger.warning(
|
||||
'Executing %r took %.3f seconds',
|
||||
self, delta)
|
||||
finally:
|
||||
context = self.context
|
||||
Py_DECREF(self)
|
||||
Context_Exit(context)
|
||||
self._clear()
|
||||
|
||||
# Public API
|
||||
|
||||
def __repr__(self):
|
||||
info = [self.__class__.__name__]
|
||||
|
||||
if self._cancelled:
|
||||
info.append('cancelled')
|
||||
|
||||
if self._debug_info is not None:
|
||||
callback_name = self._debug_info[0]
|
||||
source_traceback = self._debug_info[1]
|
||||
else:
|
||||
callback_name = None
|
||||
source_traceback = None
|
||||
|
||||
if callback_name is not None:
|
||||
info.append(callback_name)
|
||||
elif self.callback is not None:
|
||||
info.append(format_callback_name(self.callback))
|
||||
|
||||
if source_traceback is not None:
|
||||
frame = source_traceback[-1]
|
||||
info.append('created at {}:{}'.format(frame[0], frame[1]))
|
||||
|
||||
return '<' + ' '.join(info) + '>'
|
||||
|
||||
def cancelled(self):
|
||||
return self._cancelled
|
||||
|
||||
def cancel(self):
|
||||
self._cancel()
|
||||
|
||||
def when(self):
|
||||
return self._when
|
||||
|
||||
|
||||
cdef format_callback_name(func):
|
||||
if hasattr(func, '__qualname__'):
|
||||
cb_name = getattr(func, '__qualname__')
|
||||
elif hasattr(func, '__name__'):
|
||||
cb_name = getattr(func, '__name__')
|
||||
else:
|
||||
cb_name = repr(func)
|
||||
return cb_name
|
||||
|
||||
|
||||
cdef new_Handle(Loop loop, object callback, object args, object context):
|
||||
cdef Handle handle
|
||||
handle = Handle.__new__(Handle)
|
||||
handle._set_loop(loop)
|
||||
handle._set_context(context)
|
||||
|
||||
handle.cb_type = 1
|
||||
|
||||
handle.arg1 = callback
|
||||
handle.arg2 = args
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
cdef new_MethodHandle(Loop loop, str name, method_t callback, object context,
|
||||
object bound_to):
|
||||
cdef Handle handle
|
||||
handle = Handle.__new__(Handle)
|
||||
handle._set_loop(loop)
|
||||
handle._set_context(context)
|
||||
|
||||
handle.cb_type = 2
|
||||
handle.meth_name = name
|
||||
|
||||
handle.callback = <void*> callback
|
||||
handle.arg1 = bound_to
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
cdef new_MethodHandle1(Loop loop, str name, method1_t callback, object context,
|
||||
object bound_to, object arg):
|
||||
|
||||
cdef Handle handle
|
||||
handle = Handle.__new__(Handle)
|
||||
handle._set_loop(loop)
|
||||
handle._set_context(context)
|
||||
|
||||
handle.cb_type = 3
|
||||
handle.meth_name = name
|
||||
|
||||
handle.callback = <void*> callback
|
||||
handle.arg1 = bound_to
|
||||
handle.arg2 = arg
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
cdef new_MethodHandle2(Loop loop, str name, method2_t callback, object context,
|
||||
object bound_to, object arg1, object arg2):
|
||||
|
||||
cdef Handle handle
|
||||
handle = Handle.__new__(Handle)
|
||||
handle._set_loop(loop)
|
||||
handle._set_context(context)
|
||||
|
||||
handle.cb_type = 4
|
||||
handle.meth_name = name
|
||||
|
||||
handle.callback = <void*> callback
|
||||
handle.arg1 = bound_to
|
||||
handle.arg2 = arg1
|
||||
handle.arg3 = arg2
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
cdef new_MethodHandle3(Loop loop, str name, method3_t callback, object context,
|
||||
object bound_to, object arg1, object arg2, object arg3):
|
||||
|
||||
cdef Handle handle
|
||||
handle = Handle.__new__(Handle)
|
||||
handle._set_loop(loop)
|
||||
handle._set_context(context)
|
||||
|
||||
handle.cb_type = 5
|
||||
handle.meth_name = name
|
||||
|
||||
handle.callback = <void*> callback
|
||||
handle.arg1 = bound_to
|
||||
handle.arg2 = arg1
|
||||
handle.arg3 = arg2
|
||||
handle.arg4 = arg3
|
||||
|
||||
return handle
|
||||
|
||||
|
||||
cdef extract_stack():
|
||||
"""Replacement for traceback.extract_stack() that only does the
|
||||
necessary work for asyncio debug mode.
|
||||
"""
|
||||
try:
|
||||
f = sys_getframe()
|
||||
# sys._getframe() might raise ValueError if being called without a frame, e.g.
|
||||
# from Cython or similar C extensions.
|
||||
except ValueError:
|
||||
return None
|
||||
if f is None:
|
||||
return
|
||||
|
||||
try:
|
||||
stack = tb_StackSummary.extract(tb_walk_stack(f),
|
||||
limit=DEBUG_STACK_DEPTH,
|
||||
lookup_lines=False)
|
||||
finally:
|
||||
f = None
|
||||
|
||||
stack.reverse()
|
||||
return stack
|
479
env/lib/python3.11/site-packages/uvloop/dns.pyx
vendored
Normal file
479
env/lib/python3.11/site-packages/uvloop/dns.pyx
vendored
Normal file
@ -0,0 +1,479 @@
|
||||
cdef __port_to_int(port, proto):
|
||||
if type(port) is int:
|
||||
return port
|
||||
|
||||
if port is None or port == '' or port == b'':
|
||||
return 0
|
||||
|
||||
try:
|
||||
return int(port)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if isinstance(port, bytes):
|
||||
port = port.decode()
|
||||
|
||||
if isinstance(port, str) and proto is not None:
|
||||
if proto == uv.IPPROTO_TCP:
|
||||
return socket_getservbyname(port, 'tcp')
|
||||
elif proto == uv.IPPROTO_UDP:
|
||||
return socket_getservbyname(port, 'udp')
|
||||
|
||||
raise OSError('service/proto not found')
|
||||
|
||||
|
||||
cdef __convert_sockaddr_to_pyaddr(const system.sockaddr* addr):
|
||||
# Converts sockaddr structs into what Python socket
|
||||
# module can understand:
|
||||
# - for IPv4 a tuple of (host, port)
|
||||
# - for IPv6 a tuple of (host, port, flowinfo, scope_id)
|
||||
|
||||
cdef:
|
||||
char buf[128] # INET6_ADDRSTRLEN is usually 46
|
||||
int err
|
||||
system.sockaddr_in *addr4
|
||||
system.sockaddr_in6 *addr6
|
||||
system.sockaddr_un *addr_un
|
||||
|
||||
if addr.sa_family == uv.AF_INET:
|
||||
addr4 = <system.sockaddr_in*>addr
|
||||
|
||||
err = uv.uv_ip4_name(addr4, buf, sizeof(buf))
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
return (
|
||||
PyUnicode_FromString(buf),
|
||||
system.ntohs(addr4.sin_port)
|
||||
)
|
||||
|
||||
elif addr.sa_family == uv.AF_INET6:
|
||||
addr6 = <system.sockaddr_in6*>addr
|
||||
|
||||
err = uv.uv_ip6_name(addr6, buf, sizeof(buf))
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
return (
|
||||
PyUnicode_FromString(buf),
|
||||
system.ntohs(addr6.sin6_port),
|
||||
system.ntohl(addr6.sin6_flowinfo),
|
||||
addr6.sin6_scope_id
|
||||
)
|
||||
|
||||
elif addr.sa_family == uv.AF_UNIX:
|
||||
addr_un = <system.sockaddr_un*>addr
|
||||
return system.MakeUnixSockPyAddr(addr_un)
|
||||
|
||||
raise RuntimeError("cannot convert sockaddr into Python object")
|
||||
|
||||
|
||||
@cython.freelist(DEFAULT_FREELIST_SIZE)
|
||||
cdef class SockAddrHolder:
|
||||
cdef:
|
||||
int family
|
||||
system.sockaddr_storage addr
|
||||
Py_ssize_t addr_size
|
||||
|
||||
|
||||
cdef LruCache sockaddrs = LruCache(maxsize=DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE)
|
||||
|
||||
|
||||
cdef __convert_pyaddr_to_sockaddr(int family, object addr,
|
||||
system.sockaddr* res):
|
||||
cdef:
|
||||
int err
|
||||
int addr_len
|
||||
int scope_id = 0
|
||||
int flowinfo = 0
|
||||
char *buf
|
||||
Py_ssize_t buflen
|
||||
SockAddrHolder ret
|
||||
|
||||
ret = sockaddrs.get(addr, None)
|
||||
if ret is not None and ret.family == family:
|
||||
memcpy(res, &ret.addr, ret.addr_size)
|
||||
return
|
||||
|
||||
ret = SockAddrHolder.__new__(SockAddrHolder)
|
||||
if family == uv.AF_INET:
|
||||
if not isinstance(addr, tuple):
|
||||
raise TypeError('AF_INET address must be tuple')
|
||||
if len(addr) != 2:
|
||||
raise ValueError('AF_INET address must be tuple of (host, port)')
|
||||
host, port = addr
|
||||
if isinstance(host, str):
|
||||
try:
|
||||
# idna codec is rather slow, so we try ascii first.
|
||||
host = host.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
host = host.encode('idna')
|
||||
if not isinstance(host, (bytes, bytearray)):
|
||||
raise TypeError('host must be a string or bytes object')
|
||||
|
||||
port = __port_to_int(port, None)
|
||||
|
||||
ret.addr_size = sizeof(system.sockaddr_in)
|
||||
err = uv.uv_ip4_addr(host, <int>port, <system.sockaddr_in*>&ret.addr)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
elif family == uv.AF_INET6:
|
||||
if not isinstance(addr, tuple):
|
||||
raise TypeError('AF_INET6 address must be tuple')
|
||||
|
||||
addr_len = len(addr)
|
||||
if addr_len < 2 or addr_len > 4:
|
||||
raise ValueError(
|
||||
'AF_INET6 must be a tuple of 2-4 parameters: '
|
||||
'(host, port, flowinfo?, scope_id?)')
|
||||
|
||||
host = addr[0]
|
||||
if isinstance(host, str):
|
||||
try:
|
||||
# idna codec is rather slow, so we try ascii first.
|
||||
host = host.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
host = host.encode('idna')
|
||||
if not isinstance(host, (bytes, bytearray)):
|
||||
raise TypeError('host must be a string or bytes object')
|
||||
|
||||
port = __port_to_int(addr[1], None)
|
||||
|
||||
if addr_len > 2:
|
||||
flowinfo = addr[2]
|
||||
if addr_len > 3:
|
||||
scope_id = addr[3]
|
||||
|
||||
ret.addr_size = sizeof(system.sockaddr_in6)
|
||||
|
||||
err = uv.uv_ip6_addr(host, port, <system.sockaddr_in6*>&ret.addr)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
(<system.sockaddr_in6*>&ret.addr).sin6_flowinfo = flowinfo
|
||||
(<system.sockaddr_in6*>&ret.addr).sin6_scope_id = scope_id
|
||||
|
||||
elif family == uv.AF_UNIX:
|
||||
if isinstance(addr, str):
|
||||
addr = addr.encode(sys_getfilesystemencoding())
|
||||
elif not isinstance(addr, bytes):
|
||||
raise TypeError('AF_UNIX address must be a str or a bytes object')
|
||||
|
||||
PyBytes_AsStringAndSize(addr, &buf, &buflen)
|
||||
if buflen > 107:
|
||||
raise ValueError(
|
||||
f'unix socket path {addr!r} is longer than 107 characters')
|
||||
|
||||
ret.addr_size = sizeof(system.sockaddr_un)
|
||||
memset(&ret.addr, 0, sizeof(system.sockaddr_un))
|
||||
(<system.sockaddr_un*>&ret.addr).sun_family = uv.AF_UNIX
|
||||
memcpy((<system.sockaddr_un*>&ret.addr).sun_path, buf, buflen)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
f'expected AF_INET, AF_INET6, or AF_UNIX family, got {family}')
|
||||
|
||||
ret.family = family
|
||||
sockaddrs[addr] = ret
|
||||
memcpy(res, &ret.addr, ret.addr_size)
|
||||
|
||||
|
||||
cdef __static_getaddrinfo(object host, object port,
|
||||
int family, int type,
|
||||
int proto,
|
||||
system.sockaddr *addr):
|
||||
|
||||
if proto not in {0, uv.IPPROTO_TCP, uv.IPPROTO_UDP}:
|
||||
return
|
||||
|
||||
if _is_sock_stream(type):
|
||||
proto = uv.IPPROTO_TCP
|
||||
elif _is_sock_dgram(type):
|
||||
proto = uv.IPPROTO_UDP
|
||||
else:
|
||||
return
|
||||
|
||||
try:
|
||||
port = __port_to_int(port, proto)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
hp = (host, port)
|
||||
if family == uv.AF_UNSPEC:
|
||||
try:
|
||||
__convert_pyaddr_to_sockaddr(uv.AF_INET, hp, addr)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return (uv.AF_INET, type, proto)
|
||||
|
||||
try:
|
||||
__convert_pyaddr_to_sockaddr(uv.AF_INET6, hp, addr)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return (uv.AF_INET6, type, proto)
|
||||
|
||||
else:
|
||||
try:
|
||||
__convert_pyaddr_to_sockaddr(family, hp, addr)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return (family, type, proto)
|
||||
|
||||
|
||||
cdef __static_getaddrinfo_pyaddr(object host, object port,
|
||||
int family, int type,
|
||||
int proto, int flags):
|
||||
|
||||
cdef:
|
||||
system.sockaddr_storage addr
|
||||
object triplet
|
||||
|
||||
triplet = __static_getaddrinfo(
|
||||
host, port, family, type,
|
||||
proto, <system.sockaddr*>&addr)
|
||||
if triplet is None:
|
||||
return
|
||||
|
||||
af, type, proto = triplet
|
||||
|
||||
try:
|
||||
pyaddr = __convert_sockaddr_to_pyaddr(<system.sockaddr*>&addr)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
# When the host is an IP while type is one of TCP or UDP, different libc
|
||||
# implementations of getaddrinfo() behave differently:
|
||||
# 1. When AI_CANONNAME is set:
|
||||
# * glibc: returns ai_canonname
|
||||
# * musl: returns ai_canonname
|
||||
# * macOS: returns an empty string for ai_canonname
|
||||
# 2. When AI_CANONNAME is NOT set:
|
||||
# * glibc: returns an empty string for ai_canonname
|
||||
# * musl: returns ai_canonname
|
||||
# * macOS: returns an empty string for ai_canonname
|
||||
# At the same time, libuv and CPython both uses libc directly, even though
|
||||
# this different behavior is violating what is in the documentation.
|
||||
#
|
||||
# uvloop potentially should be a 100% drop-in replacement for asyncio,
|
||||
# doing whatever asyncio does, especially when the libc implementations are
|
||||
# also different in the same way. However, making our implementation to be
|
||||
# consistent with libc/CPython would be complex and hard to maintain
|
||||
# (including caching libc behaviors when flag is/not set), therefore we
|
||||
# decided to simply normalize the behavior in uvloop for this very marginal
|
||||
# case following the documentation, even though uvloop would behave
|
||||
# differently to asyncio on macOS and musl platforms, when again the host
|
||||
# is an IP and type is one of TCP or UDP.
|
||||
# All other cases are still asyncio-compatible.
|
||||
if flags & socket_AI_CANONNAME:
|
||||
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)
|
||||
cdef class AddrInfo:
|
||||
cdef:
|
||||
system.addrinfo *data
|
||||
|
||||
def __cinit__(self):
|
||||
self.data = NULL
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.data is not NULL:
|
||||
uv.uv_freeaddrinfo(self.data) # returns void
|
||||
self.data = NULL
|
||||
|
||||
cdef void set_data(self, system.addrinfo *data) noexcept:
|
||||
self.data = data
|
||||
|
||||
cdef unpack(self):
|
||||
cdef:
|
||||
list result = []
|
||||
system.addrinfo *ptr
|
||||
|
||||
if self.data is NULL:
|
||||
raise RuntimeError('AddrInfo.data is NULL')
|
||||
|
||||
ptr = self.data
|
||||
while ptr != NULL:
|
||||
if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
|
||||
result.append((
|
||||
_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()),
|
||||
__convert_sockaddr_to_pyaddr(ptr.ai_addr)
|
||||
))
|
||||
|
||||
ptr = ptr.ai_next
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
cdef int isinstance(object other):
|
||||
return type(other) is AddrInfo
|
||||
|
||||
|
||||
cdef class AddrInfoRequest(UVRequest):
|
||||
cdef:
|
||||
system.addrinfo hints
|
||||
object callback
|
||||
uv.uv_getaddrinfo_t _req_data
|
||||
|
||||
def __cinit__(self, Loop loop,
|
||||
bytes host, bytes port,
|
||||
int family, int type, int proto, int flags,
|
||||
object callback):
|
||||
|
||||
cdef:
|
||||
int err
|
||||
char *chost
|
||||
char *cport
|
||||
|
||||
if host is None:
|
||||
chost = NULL
|
||||
elif host == b'' and sys.platform == 'darwin':
|
||||
# It seems `getaddrinfo("", ...)` on macOS is equivalent to
|
||||
# `getaddrinfo("localhost", ...)`. This is inconsistent with
|
||||
# libuv 1.48 which treats empty nodename as EINVAL.
|
||||
chost = <char*>'localhost'
|
||||
else:
|
||||
chost = <char*>host
|
||||
|
||||
if port is None:
|
||||
cport = NULL
|
||||
else:
|
||||
cport = <char*>port
|
||||
|
||||
memset(&self.hints, 0, sizeof(system.addrinfo))
|
||||
self.hints.ai_flags = flags
|
||||
self.hints.ai_family = family
|
||||
self.hints.ai_socktype = type
|
||||
self.hints.ai_protocol = proto
|
||||
|
||||
self.request = <uv.uv_req_t*> &self._req_data
|
||||
self.callback = callback
|
||||
self.request.data = <void*>self
|
||||
|
||||
err = uv.uv_getaddrinfo(loop.uvloop,
|
||||
<uv.uv_getaddrinfo_t*>self.request,
|
||||
__on_addrinfo_resolved,
|
||||
chost,
|
||||
cport,
|
||||
&self.hints)
|
||||
|
||||
if err < 0:
|
||||
self.on_done()
|
||||
try:
|
||||
if err == uv.UV_EINVAL:
|
||||
# Convert UV_EINVAL to EAI_NONAME to match libc behavior
|
||||
msg = system.gai_strerror(socket_EAI_NONAME).decode('utf-8')
|
||||
ex = socket_gaierror(socket_EAI_NONAME, msg)
|
||||
else:
|
||||
ex = convert_error(err)
|
||||
except Exception as ex:
|
||||
callback(ex)
|
||||
else:
|
||||
callback(ex)
|
||||
|
||||
|
||||
cdef class NameInfoRequest(UVRequest):
|
||||
cdef:
|
||||
object callback
|
||||
uv.uv_getnameinfo_t _req_data
|
||||
|
||||
def __cinit__(self, Loop loop, callback):
|
||||
self.request = <uv.uv_req_t*> &self._req_data
|
||||
self.callback = callback
|
||||
self.request.data = <void*>self
|
||||
|
||||
cdef query(self, system.sockaddr *addr, int flags):
|
||||
cdef int err
|
||||
err = uv.uv_getnameinfo(self.loop.uvloop,
|
||||
<uv.uv_getnameinfo_t*>self.request,
|
||||
__on_nameinfo_resolved,
|
||||
addr,
|
||||
flags)
|
||||
if err < 0:
|
||||
self.on_done()
|
||||
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,
|
||||
) noexcept with gil:
|
||||
|
||||
if resolver.data is NULL:
|
||||
aio_logger.error(
|
||||
'AddrInfoRequest callback called with NULL resolver.data')
|
||||
return
|
||||
|
||||
cdef:
|
||||
AddrInfoRequest request = <AddrInfoRequest> resolver.data
|
||||
Loop loop = request.loop
|
||||
object callback = request.callback
|
||||
AddrInfo ai
|
||||
|
||||
try:
|
||||
if status < 0:
|
||||
callback(convert_error(status))
|
||||
else:
|
||||
ai = AddrInfo()
|
||||
ai.set_data(res)
|
||||
callback(ai)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
loop._handle_exception(ex)
|
||||
finally:
|
||||
request.on_done()
|
||||
|
||||
|
||||
cdef void __on_nameinfo_resolved(
|
||||
uv.uv_getnameinfo_t* req,
|
||||
int status,
|
||||
const char* hostname,
|
||||
const char* service,
|
||||
) noexcept with gil:
|
||||
cdef:
|
||||
NameInfoRequest request = <NameInfoRequest> req.data
|
||||
Loop loop = request.loop
|
||||
object callback = request.callback
|
||||
|
||||
try:
|
||||
if status < 0:
|
||||
callback(convert_error(status))
|
||||
else:
|
||||
callback(((<bytes>hostname).decode(),
|
||||
(<bytes>service).decode()))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
loop._handle_exception(ex)
|
||||
finally:
|
||||
request.on_done()
|
113
env/lib/python3.11/site-packages/uvloop/errors.pyx
vendored
Normal file
113
env/lib/python3.11/site-packages/uvloop/errors.pyx
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
cdef str __strerr(int errno):
|
||||
return strerror(errno).decode()
|
||||
|
||||
|
||||
cdef __convert_python_error(int uverr):
|
||||
# XXX Won't work for Windows:
|
||||
# From libuv docs:
|
||||
# Implementation detail: on Unix error codes are the
|
||||
# negated errno (or -errno), while on Windows they
|
||||
# are defined by libuv to arbitrary negative numbers.
|
||||
cdef int oserr = -uverr
|
||||
|
||||
exc = OSError
|
||||
|
||||
if uverr in (uv.UV_EACCES, uv.UV_EPERM):
|
||||
exc = PermissionError
|
||||
|
||||
elif uverr in (uv.UV_EAGAIN, uv.UV_EALREADY):
|
||||
exc = BlockingIOError
|
||||
|
||||
elif uverr in (uv.UV_EPIPE, uv.UV_ESHUTDOWN):
|
||||
exc = BrokenPipeError
|
||||
|
||||
elif uverr == uv.UV_ECONNABORTED:
|
||||
exc = ConnectionAbortedError
|
||||
|
||||
elif uverr == uv.UV_ECONNREFUSED:
|
||||
exc = ConnectionRefusedError
|
||||
|
||||
elif uverr == uv.UV_ECONNRESET:
|
||||
exc = ConnectionResetError
|
||||
|
||||
elif uverr == uv.UV_EEXIST:
|
||||
exc = FileExistsError
|
||||
|
||||
elif uverr == uv.UV_ENOENT:
|
||||
exc = FileNotFoundError
|
||||
|
||||
elif uverr == uv.UV_EINTR:
|
||||
exc = InterruptedError
|
||||
|
||||
elif uverr == uv.UV_EISDIR:
|
||||
exc = IsADirectoryError
|
||||
|
||||
elif uverr == uv.UV_ESRCH:
|
||||
exc = ProcessLookupError
|
||||
|
||||
elif uverr == uv.UV_ETIMEDOUT:
|
||||
exc = TimeoutError
|
||||
|
||||
return exc(oserr, __strerr(oserr))
|
||||
|
||||
|
||||
cdef int __convert_socket_error(int uverr):
|
||||
cdef int sock_err = 0
|
||||
|
||||
if uverr == uv.UV_EAI_ADDRFAMILY:
|
||||
sock_err = socket_EAI_ADDRFAMILY
|
||||
|
||||
elif uverr == uv.UV_EAI_AGAIN:
|
||||
sock_err = socket_EAI_AGAIN
|
||||
|
||||
elif uverr == uv.UV_EAI_BADFLAGS:
|
||||
sock_err = socket_EAI_BADFLAGS
|
||||
|
||||
elif uverr == uv.UV_EAI_BADHINTS:
|
||||
sock_err = socket_EAI_BADHINTS
|
||||
|
||||
elif uverr == uv.UV_EAI_CANCELED:
|
||||
sock_err = socket_EAI_CANCELED
|
||||
|
||||
elif uverr == uv.UV_EAI_FAIL:
|
||||
sock_err = socket_EAI_FAIL
|
||||
|
||||
elif uverr == uv.UV_EAI_FAMILY:
|
||||
sock_err = socket_EAI_FAMILY
|
||||
|
||||
elif uverr == uv.UV_EAI_MEMORY:
|
||||
sock_err = socket_EAI_MEMORY
|
||||
|
||||
elif uverr == uv.UV_EAI_NODATA:
|
||||
sock_err = socket_EAI_NODATA
|
||||
|
||||
elif uverr == uv.UV_EAI_NONAME:
|
||||
sock_err = socket_EAI_NONAME
|
||||
|
||||
elif uverr == uv.UV_EAI_OVERFLOW:
|
||||
sock_err = socket_EAI_OVERFLOW
|
||||
|
||||
elif uverr == uv.UV_EAI_PROTOCOL:
|
||||
sock_err = socket_EAI_PROTOCOL
|
||||
|
||||
elif uverr == uv.UV_EAI_SERVICE:
|
||||
sock_err = socket_EAI_SERVICE
|
||||
|
||||
elif uverr == uv.UV_EAI_SOCKTYPE:
|
||||
sock_err = socket_EAI_SOCKTYPE
|
||||
|
||||
return sock_err
|
||||
|
||||
|
||||
cdef convert_error(int uverr):
|
||||
cdef int sock_err
|
||||
|
||||
if uverr == uv.UV_ECANCELED:
|
||||
return aio_CancelledError()
|
||||
|
||||
sock_err = __convert_socket_error(uverr)
|
||||
if sock_err:
|
||||
msg = system.gai_strerror(sock_err).decode('utf-8')
|
||||
return socket_gaierror(sock_err, msg)
|
||||
|
||||
return __convert_python_error(uverr)
|
11
env/lib/python3.11/site-packages/uvloop/handles/async_.pxd
vendored
Normal file
11
env/lib/python3.11/site-packages/uvloop/handles/async_.pxd
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
cdef class UVAsync(UVHandle):
|
||||
cdef:
|
||||
method_t callback
|
||||
object ctx
|
||||
|
||||
cdef _init(self, Loop loop, method_t callback, object ctx)
|
||||
|
||||
cdef send(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVAsync new(Loop loop, method_t callback, object ctx)
|
56
env/lib/python3.11/site-packages/uvloop/handles/async_.pyx
vendored
Normal file
56
env/lib/python3.11/site-packages/uvloop/handles/async_.pyx
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVAsync(UVHandle):
|
||||
cdef _init(self, Loop loop, method_t callback, object ctx):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_async_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_async_init(self._loop.uvloop,
|
||||
<uv.uv_async_t*>self._handle,
|
||||
__uvasync_callback)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.callback = callback
|
||||
self.ctx = ctx
|
||||
|
||||
cdef send(self):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_async_send(<uv.uv_async_t*>self._handle)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
cdef UVAsync new(Loop loop, method_t callback, object ctx):
|
||||
cdef UVAsync handle
|
||||
handle = UVAsync.__new__(UVAsync)
|
||||
handle._init(loop, callback, ctx)
|
||||
return handle
|
||||
|
||||
|
||||
cdef void __uvasync_callback(
|
||||
uv.uv_async_t* handle,
|
||||
) noexcept with gil:
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVAsync callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVAsync async_ = <UVAsync> handle.data
|
||||
method_t cb = async_.callback
|
||||
try:
|
||||
cb(async_.ctx)
|
||||
except BaseException as ex:
|
||||
async_._error(ex, False)
|
54
env/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd
vendored
Normal file
54
env/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
cdef class UVBaseTransport(UVSocketHandle):
|
||||
|
||||
cdef:
|
||||
readonly bint _closing
|
||||
|
||||
bint _protocol_connected
|
||||
bint _protocol_paused
|
||||
object _protocol_data_received
|
||||
size_t _high_water
|
||||
size_t _low_water
|
||||
|
||||
object _protocol
|
||||
Server _server
|
||||
object _waiter
|
||||
|
||||
dict _extra_info
|
||||
|
||||
uint32_t _conn_lost
|
||||
|
||||
object __weakref__
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef inline _maybe_pause_protocol(self)
|
||||
cdef inline _maybe_resume_protocol(self)
|
||||
|
||||
cdef inline _schedule_call_connection_made(self)
|
||||
cdef inline _schedule_call_connection_lost(self, exc)
|
||||
|
||||
cdef _wakeup_waiter(self)
|
||||
cdef _call_connection_made(self)
|
||||
cdef _call_connection_lost(self, exc)
|
||||
|
||||
# Overloads of UVHandle methods:
|
||||
cdef _fatal_error(self, exc, throw, reason=?)
|
||||
cdef _close(self)
|
||||
|
||||
cdef inline _set_server(self, Server server)
|
||||
cdef inline _set_waiter(self, object waiter)
|
||||
|
||||
cdef _set_protocol(self, object protocol)
|
||||
cdef _clear_protocol(self)
|
||||
|
||||
cdef inline _init_protocol(self)
|
||||
cdef inline _add_extra_info(self, str name, object obj)
|
||||
|
||||
# === overloads ===
|
||||
|
||||
cdef _new_socket(self)
|
||||
cdef size_t _get_write_buffer_size(self)
|
||||
|
||||
cdef bint _is_reading(self)
|
||||
cdef _start_reading(self)
|
||||
cdef _stop_reading(self)
|
293
env/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx
vendored
Normal file
293
env/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx
vendored
Normal file
@ -0,0 +1,293 @@
|
||||
cdef class UVBaseTransport(UVSocketHandle):
|
||||
|
||||
def __cinit__(self):
|
||||
# Flow control
|
||||
self._high_water = FLOW_CONTROL_HIGH_WATER * 1024
|
||||
self._low_water = FLOW_CONTROL_HIGH_WATER // 4
|
||||
|
||||
self._protocol = None
|
||||
self._protocol_connected = 0
|
||||
self._protocol_paused = 0
|
||||
self._protocol_data_received = None
|
||||
|
||||
self._server = None
|
||||
self._waiter = None
|
||||
self._extra_info = None
|
||||
|
||||
self._conn_lost = 0
|
||||
|
||||
self._closing = 0
|
||||
|
||||
cdef size_t _get_write_buffer_size(self):
|
||||
return 0
|
||||
|
||||
cdef inline _schedule_call_connection_made(self):
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle(self._loop,
|
||||
"UVTransport._call_connection_made",
|
||||
<method_t>self._call_connection_made,
|
||||
self.context,
|
||||
self))
|
||||
|
||||
cdef inline _schedule_call_connection_lost(self, exc):
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle1(self._loop,
|
||||
"UVTransport._call_connection_lost",
|
||||
<method1_t>self._call_connection_lost,
|
||||
self.context,
|
||||
self, exc))
|
||||
|
||||
cdef _fatal_error(self, exc, throw, reason=None):
|
||||
# Overload UVHandle._fatal_error
|
||||
|
||||
self._force_close(exc)
|
||||
|
||||
if not isinstance(exc, OSError):
|
||||
|
||||
if throw or self._loop is None:
|
||||
raise exc
|
||||
|
||||
msg = f'Fatal error on transport {self.__class__.__name__}'
|
||||
if reason is not None:
|
||||
msg = f'{msg} ({reason})'
|
||||
|
||||
self._loop.call_exception_handler({
|
||||
'message': msg,
|
||||
'exception': exc,
|
||||
'transport': self,
|
||||
'protocol': self._protocol,
|
||||
})
|
||||
|
||||
cdef inline _maybe_pause_protocol(self):
|
||||
cdef:
|
||||
size_t size = self._get_write_buffer_size()
|
||||
|
||||
if size <= self._high_water:
|
||||
return
|
||||
|
||||
if not self._protocol_paused:
|
||||
self._protocol_paused = 1
|
||||
try:
|
||||
# _maybe_pause_protocol() is always triggered from user-calls,
|
||||
# so we must copy the context to avoid entering context twice
|
||||
run_in_context(
|
||||
self.context.copy(), self._protocol.pause_writing,
|
||||
)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as exc:
|
||||
self._loop.call_exception_handler({
|
||||
'message': 'protocol.pause_writing() failed',
|
||||
'exception': exc,
|
||||
'transport': self,
|
||||
'protocol': self._protocol,
|
||||
})
|
||||
|
||||
cdef inline _maybe_resume_protocol(self):
|
||||
cdef:
|
||||
size_t size = self._get_write_buffer_size()
|
||||
|
||||
if self._protocol_paused and size <= self._low_water:
|
||||
self._protocol_paused = 0
|
||||
try:
|
||||
# We're copying the context to avoid entering context twice,
|
||||
# even though it's not always necessary to copy - it's easier
|
||||
# to copy here than passing down a copied context.
|
||||
run_in_context(
|
||||
self.context.copy(), self._protocol.resume_writing,
|
||||
)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as exc:
|
||||
self._loop.call_exception_handler({
|
||||
'message': 'protocol.resume_writing() failed',
|
||||
'exception': exc,
|
||||
'transport': self,
|
||||
'protocol': self._protocol,
|
||||
})
|
||||
|
||||
cdef _wakeup_waiter(self):
|
||||
if self._waiter is not None:
|
||||
if not self._waiter.cancelled():
|
||||
if not self._is_alive():
|
||||
self._waiter.set_exception(
|
||||
RuntimeError(
|
||||
'closed Transport handle and unset waiter'))
|
||||
else:
|
||||
self._waiter.set_result(True)
|
||||
self._waiter = None
|
||||
|
||||
cdef _call_connection_made(self):
|
||||
if self._protocol is None:
|
||||
raise RuntimeError(
|
||||
'protocol is not set, cannot call connection_made()')
|
||||
|
||||
# We use `_is_alive()` and not `_closing`, because we call
|
||||
# `transport._close()` in `loop.create_connection()` if an
|
||||
# exception happens during `await waiter`.
|
||||
if not self._is_alive():
|
||||
# A connection waiter can be cancelled between
|
||||
# 'await loop.create_connection()' and
|
||||
# `_schedule_call_connection_made` and
|
||||
# the actual `_call_connection_made`.
|
||||
self._wakeup_waiter()
|
||||
return
|
||||
|
||||
# Set _protocol_connected to 1 before calling "connection_made":
|
||||
# if transport is aborted or closed, "connection_lost" will
|
||||
# still be scheduled.
|
||||
self._protocol_connected = 1
|
||||
|
||||
try:
|
||||
self._protocol.connection_made(self)
|
||||
except BaseException:
|
||||
self._wakeup_waiter()
|
||||
raise
|
||||
|
||||
if not self._is_alive():
|
||||
# This might happen when "transport.abort()" is called
|
||||
# from "Protocol.connection_made".
|
||||
self._wakeup_waiter()
|
||||
return
|
||||
|
||||
self._start_reading()
|
||||
self._wakeup_waiter()
|
||||
|
||||
cdef _call_connection_lost(self, exc):
|
||||
if self._waiter is not None:
|
||||
if not self._waiter.done():
|
||||
self._waiter.set_exception(exc)
|
||||
self._waiter = None
|
||||
|
||||
if self._closed:
|
||||
# The handle is closed -- likely, _call_connection_lost
|
||||
# was already called before.
|
||||
return
|
||||
|
||||
try:
|
||||
if self._protocol_connected:
|
||||
self._protocol.connection_lost(exc)
|
||||
finally:
|
||||
self._clear_protocol()
|
||||
|
||||
self._close()
|
||||
|
||||
server = self._server
|
||||
if server is not None:
|
||||
(<Server>server)._detach()
|
||||
self._server = None
|
||||
|
||||
cdef inline _set_server(self, Server server):
|
||||
self._server = server
|
||||
(<Server>server)._attach()
|
||||
|
||||
cdef inline _set_waiter(self, object waiter):
|
||||
if waiter is not None and not isfuture(waiter):
|
||||
raise TypeError(
|
||||
f'invalid waiter object {waiter!r}, expected asyncio.Future')
|
||||
|
||||
self._waiter = waiter
|
||||
|
||||
cdef _set_protocol(self, object protocol):
|
||||
self._protocol = protocol
|
||||
# Store a reference to the bound method directly
|
||||
try:
|
||||
self._protocol_data_received = protocol.data_received
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
cdef _clear_protocol(self):
|
||||
self._protocol = None
|
||||
self._protocol_data_received = None
|
||||
|
||||
cdef inline _init_protocol(self):
|
||||
self._loop._track_transport(self)
|
||||
if self._protocol is None:
|
||||
raise RuntimeError('invalid _init_protocol call')
|
||||
self._schedule_call_connection_made()
|
||||
|
||||
cdef inline _add_extra_info(self, str name, object obj):
|
||||
if self._extra_info is None:
|
||||
self._extra_info = {}
|
||||
self._extra_info[name] = obj
|
||||
|
||||
cdef bint _is_reading(self):
|
||||
raise NotImplementedError
|
||||
|
||||
cdef _start_reading(self):
|
||||
raise NotImplementedError
|
||||
|
||||
cdef _stop_reading(self):
|
||||
raise NotImplementedError
|
||||
|
||||
# === Public API ===
|
||||
|
||||
property _paused:
|
||||
# Used by SSLProto. Might be removed in the future.
|
||||
def __get__(self):
|
||||
return bool(not self._is_reading())
|
||||
|
||||
def get_protocol(self):
|
||||
return self._protocol
|
||||
|
||||
def set_protocol(self, protocol):
|
||||
self._set_protocol(protocol)
|
||||
if self._is_reading():
|
||||
self._stop_reading()
|
||||
self._start_reading()
|
||||
|
||||
def _force_close(self, exc):
|
||||
# Used by SSLProto. Might be removed in the future.
|
||||
if self._conn_lost or self._closed:
|
||||
return
|
||||
if not self._closing:
|
||||
self._closing = 1
|
||||
self._stop_reading()
|
||||
self._conn_lost += 1
|
||||
self._schedule_call_connection_lost(exc)
|
||||
|
||||
def abort(self):
|
||||
self._force_close(None)
|
||||
|
||||
def close(self):
|
||||
if self._closing or self._closed:
|
||||
return
|
||||
|
||||
self._closing = 1
|
||||
self._stop_reading()
|
||||
|
||||
if not self._get_write_buffer_size():
|
||||
# The write buffer is empty
|
||||
self._conn_lost += 1
|
||||
self._schedule_call_connection_lost(None)
|
||||
|
||||
def is_closing(self):
|
||||
return self._closing
|
||||
|
||||
def get_write_buffer_size(self):
|
||||
return self._get_write_buffer_size()
|
||||
|
||||
def set_write_buffer_limits(self, high=None, low=None):
|
||||
self._ensure_alive()
|
||||
|
||||
self._high_water, self._low_water = add_flowcontrol_defaults(
|
||||
high, low, FLOW_CONTROL_HIGH_WATER)
|
||||
|
||||
self._maybe_pause_protocol()
|
||||
|
||||
def get_write_buffer_limits(self):
|
||||
return (self._low_water, self._high_water)
|
||||
|
||||
def get_extra_info(self, name, default=None):
|
||||
if self._extra_info is not None and name in self._extra_info:
|
||||
return self._extra_info[name]
|
||||
if name == 'socket':
|
||||
return self._get_socket()
|
||||
if name == 'sockname':
|
||||
return self._get_socket().getsockname()
|
||||
if name == 'peername':
|
||||
try:
|
||||
return self._get_socket().getpeername()
|
||||
except socket_error:
|
||||
return default
|
||||
return default
|
14
env/lib/python3.11/site-packages/uvloop/handles/check.pxd
vendored
Normal file
14
env/lib/python3.11/site-packages/uvloop/handles/check.pxd
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
cdef class UVCheck(UVHandle):
|
||||
cdef:
|
||||
Handle h
|
||||
bint running
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef _init(self, Loop loop, Handle h)
|
||||
|
||||
cdef inline stop(self)
|
||||
cdef inline start(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVCheck new(Loop loop, Handle h)
|
72
env/lib/python3.11/site-packages/uvloop/handles/check.pyx
vendored
Normal file
72
env/lib/python3.11/site-packages/uvloop/handles/check.pyx
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVCheck(UVHandle):
|
||||
cdef _init(self, Loop loop, Handle h):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_check_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_check_init(self._loop.uvloop, <uv.uv_check_t*>self._handle)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.h = h
|
||||
self.running = 0
|
||||
|
||||
cdef inline stop(self):
|
||||
cdef int err
|
||||
|
||||
if not self._is_alive():
|
||||
self.running = 0
|
||||
return
|
||||
|
||||
if self.running == 1:
|
||||
err = uv.uv_check_stop(<uv.uv_check_t*>self._handle)
|
||||
self.running = 0
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef inline start(self):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
if self.running == 0:
|
||||
err = uv.uv_check_start(<uv.uv_check_t*>self._handle,
|
||||
cb_check_callback)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
self.running = 1
|
||||
|
||||
@staticmethod
|
||||
cdef UVCheck new(Loop loop, Handle h):
|
||||
cdef UVCheck handle
|
||||
handle = UVCheck.__new__(UVCheck)
|
||||
handle._init(loop, h)
|
||||
return handle
|
||||
|
||||
|
||||
cdef void cb_check_callback(
|
||||
uv.uv_check_t* handle,
|
||||
) noexcept with gil:
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVCheck callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVCheck check = <UVCheck> handle.data
|
||||
Handle h = check.h
|
||||
try:
|
||||
h._run()
|
||||
except BaseException as ex:
|
||||
check._error(ex, False)
|
12
env/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd
vendored
Normal file
12
env/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
cdef class UVFSEvent(UVHandle):
|
||||
cdef:
|
||||
object callback
|
||||
bint running
|
||||
|
||||
cdef _init(self, Loop loop, object callback, object context)
|
||||
cdef _close(self)
|
||||
cdef start(self, char* path, int flags)
|
||||
cdef stop(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVFSEvent new(Loop loop, object callback, object context)
|
116
env/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx
vendored
Normal file
116
env/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
import enum
|
||||
|
||||
|
||||
class FileSystemEvent(enum.IntEnum):
|
||||
RENAME = uv.UV_RENAME
|
||||
CHANGE = uv.UV_CHANGE
|
||||
RENAME_CHANGE = RENAME | CHANGE
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class UVFSEvent(UVHandle):
|
||||
cdef _init(self, Loop loop, object callback, object context):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(
|
||||
sizeof(uv.uv_fs_event_t)
|
||||
)
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_fs_event_init(
|
||||
self._loop.uvloop, <uv.uv_fs_event_t*>self._handle
|
||||
)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.running = 0
|
||||
self.callback = callback
|
||||
if context is None:
|
||||
context = Context_CopyCurrent()
|
||||
self.context = context
|
||||
|
||||
cdef start(self, char* path, int flags):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
if self.running == 0:
|
||||
err = uv.uv_fs_event_start(
|
||||
<uv.uv_fs_event_t*>self._handle,
|
||||
__uvfsevent_callback,
|
||||
path,
|
||||
flags,
|
||||
)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
self.running = 1
|
||||
|
||||
cdef stop(self):
|
||||
cdef int err
|
||||
|
||||
if not self._is_alive():
|
||||
self.running = 0
|
||||
return
|
||||
|
||||
if self.running == 1:
|
||||
err = uv.uv_fs_event_stop(<uv.uv_fs_event_t*>self._handle)
|
||||
self.running = 0
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef _close(self):
|
||||
try:
|
||||
self.stop()
|
||||
finally:
|
||||
UVHandle._close(<UVHandle>self)
|
||||
|
||||
def cancel(self):
|
||||
self._close()
|
||||
|
||||
def cancelled(self):
|
||||
return self.running == 0
|
||||
|
||||
@staticmethod
|
||||
cdef UVFSEvent new(Loop loop, object callback, object context):
|
||||
cdef UVFSEvent handle
|
||||
handle = UVFSEvent.__new__(UVFSEvent)
|
||||
handle._init(loop, callback, context)
|
||||
return handle
|
||||
|
||||
|
||||
cdef void __uvfsevent_callback(
|
||||
uv.uv_fs_event_t* handle,
|
||||
const char *filename,
|
||||
int events,
|
||||
int status,
|
||||
) noexcept with gil:
|
||||
if __ensure_handle_data(
|
||||
<uv.uv_handle_t*>handle, "UVFSEvent callback"
|
||||
) == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVFSEvent fs_event = <UVFSEvent> handle.data
|
||||
Handle h
|
||||
|
||||
try:
|
||||
h = new_Handle(
|
||||
fs_event._loop,
|
||||
fs_event.callback,
|
||||
(filename, FileSystemEvent(events)),
|
||||
fs_event.context,
|
||||
)
|
||||
h._run()
|
||||
except BaseException as ex:
|
||||
fs_event._error(ex, False)
|
48
env/lib/python3.11/site-packages/uvloop/handles/handle.pxd
vendored
Normal file
48
env/lib/python3.11/site-packages/uvloop/handles/handle.pxd
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
cdef class UVHandle:
|
||||
cdef:
|
||||
uv.uv_handle_t *_handle
|
||||
Loop _loop
|
||||
readonly _source_traceback
|
||||
bint _closed
|
||||
bint _inited
|
||||
object context
|
||||
|
||||
# Added to enable current UDPTransport implementation,
|
||||
# which doesn't use libuv handles.
|
||||
bint _has_handle
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef inline _start_init(self, Loop loop)
|
||||
cdef inline _abort_init(self)
|
||||
cdef inline _finish_init(self)
|
||||
|
||||
cdef inline bint _is_alive(self)
|
||||
cdef inline _ensure_alive(self)
|
||||
|
||||
cdef _error(self, exc, throw)
|
||||
cdef _fatal_error(self, exc, throw, reason=?)
|
||||
|
||||
cdef _warn_unclosed(self)
|
||||
|
||||
cdef _free(self)
|
||||
cdef _close(self)
|
||||
|
||||
|
||||
cdef class UVSocketHandle(UVHandle):
|
||||
cdef:
|
||||
# Points to a Python file-object that should be closed
|
||||
# when the transport is closing. Used by pipes. This
|
||||
# should probably be refactored somehow.
|
||||
object _fileobj
|
||||
object __cached_socket
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef _fileno(self)
|
||||
|
||||
cdef _new_socket(self)
|
||||
cdef inline _get_socket(self)
|
||||
cdef inline _attach_fileobj(self, object file)
|
||||
|
||||
cdef _open(self, int sockfd)
|
395
env/lib/python3.11/site-packages/uvloop/handles/handle.pyx
vendored
Normal file
395
env/lib/python3.11/site-packages/uvloop/handles/handle.pyx
vendored
Normal file
@ -0,0 +1,395 @@
|
||||
cdef class UVHandle:
|
||||
"""A base class for all libuv handles.
|
||||
|
||||
Automatically manages memory deallocation and closing.
|
||||
|
||||
Important:
|
||||
|
||||
1. call "_ensure_alive()" before calling any libuv functions on
|
||||
your handles.
|
||||
|
||||
2. call "__ensure_handle_data" in *all* libuv handle callbacks.
|
||||
"""
|
||||
|
||||
def __cinit__(self):
|
||||
self._closed = 0
|
||||
self._inited = 0
|
||||
self._has_handle = 1
|
||||
self._handle = NULL
|
||||
self._loop = None
|
||||
self._source_traceback = None
|
||||
|
||||
def __init__(self):
|
||||
raise TypeError(
|
||||
'{} is not supposed to be instantiated from Python'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
def __dealloc__(self):
|
||||
if UVLOOP_DEBUG:
|
||||
if self._loop is not None:
|
||||
if self._inited:
|
||||
self._loop._debug_handles_current.subtract([
|
||||
self.__class__.__name__])
|
||||
else:
|
||||
# No "@cython.no_gc_clear" decorator on this UVHandle
|
||||
raise RuntimeError(
|
||||
'{} without @no_gc_clear; loop was set to None by GC'
|
||||
.format(self.__class__.__name__))
|
||||
|
||||
if self._handle is NULL:
|
||||
return
|
||||
|
||||
# -> When we're at this point, something is wrong <-
|
||||
|
||||
if self._handle.loop is NULL:
|
||||
# The handle wasn't initialized with "uv_{handle}_init"
|
||||
self._closed = 1
|
||||
self._free()
|
||||
raise RuntimeError(
|
||||
'{} is open in __dealloc__ with loop set to NULL'
|
||||
.format(self.__class__.__name__))
|
||||
|
||||
if self._closed:
|
||||
# So _handle is not NULL and self._closed == 1?
|
||||
raise RuntimeError(
|
||||
'{}.__dealloc__: _handle is NULL, _closed == 1'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
# The handle is dealloced while open. Let's try to close it.
|
||||
# Situations when this is possible include unhandled exceptions,
|
||||
# errors during Handle.__cinit__/__init__ etc.
|
||||
if self._inited:
|
||||
self._handle.data = NULL
|
||||
uv.uv_close(self._handle, __uv_close_handle_cb) # void; no errors
|
||||
self._handle = NULL
|
||||
self._warn_unclosed()
|
||||
else:
|
||||
# The handle was allocated, but not initialized
|
||||
self._closed = 1
|
||||
self._free()
|
||||
|
||||
cdef _free(self):
|
||||
if self._handle == NULL:
|
||||
return
|
||||
|
||||
if UVLOOP_DEBUG and self._inited:
|
||||
self._loop._debug_uv_handles_freed += 1
|
||||
|
||||
PyMem_RawFree(self._handle)
|
||||
self._handle = NULL
|
||||
|
||||
cdef _warn_unclosed(self):
|
||||
if self._source_traceback is not None:
|
||||
try:
|
||||
tb = ''.join(tb_format_list(self._source_traceback))
|
||||
tb = 'object created at (most recent call last):\n{}'.format(
|
||||
tb.rstrip())
|
||||
except Exception as ex:
|
||||
msg = (
|
||||
'unclosed resource {!r}; could not serialize '
|
||||
'debug traceback: {}: {}'
|
||||
).format(self, type(ex).__name__, ex)
|
||||
else:
|
||||
msg = 'unclosed resource {!r}; {}'.format(self, tb)
|
||||
else:
|
||||
msg = 'unclosed resource {!r}'.format(self)
|
||||
warnings_warn(msg, ResourceWarning)
|
||||
|
||||
cdef inline _abort_init(self):
|
||||
if self._handle is not NULL:
|
||||
self._free()
|
||||
|
||||
try:
|
||||
if UVLOOP_DEBUG:
|
||||
name = self.__class__.__name__
|
||||
if self._inited:
|
||||
raise RuntimeError(
|
||||
'_abort_init: {}._inited is set'.format(name))
|
||||
if self._closed:
|
||||
raise RuntimeError(
|
||||
'_abort_init: {}._closed is set'.format(name))
|
||||
finally:
|
||||
self._closed = 1
|
||||
|
||||
cdef inline _finish_init(self):
|
||||
self._inited = 1
|
||||
if self._has_handle == 1:
|
||||
self._handle.data = <void*>self
|
||||
if self._loop._debug:
|
||||
self._source_traceback = extract_stack()
|
||||
if UVLOOP_DEBUG:
|
||||
cls_name = self.__class__.__name__
|
||||
self._loop._debug_uv_handles_total += 1
|
||||
self._loop._debug_handles_total.update([cls_name])
|
||||
self._loop._debug_handles_current.update([cls_name])
|
||||
|
||||
cdef inline _start_init(self, Loop loop):
|
||||
if UVLOOP_DEBUG:
|
||||
if self._loop is not None:
|
||||
raise RuntimeError(
|
||||
'{}._start_init can only be called once'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
self._loop = loop
|
||||
|
||||
cdef inline bint _is_alive(self):
|
||||
cdef bint res
|
||||
res = self._closed != 1 and self._inited == 1
|
||||
if UVLOOP_DEBUG:
|
||||
if res and self._has_handle == 1:
|
||||
name = self.__class__.__name__
|
||||
if self._handle is NULL:
|
||||
raise RuntimeError(
|
||||
'{} is alive, but _handle is NULL'.format(name))
|
||||
if self._loop is None:
|
||||
raise RuntimeError(
|
||||
'{} is alive, but _loop is None'.format(name))
|
||||
if self._handle.loop is not self._loop.uvloop:
|
||||
raise RuntimeError(
|
||||
'{} is alive, but _handle.loop is not '
|
||||
'initialized'.format(name))
|
||||
if self._handle.data is not <void*>self:
|
||||
raise RuntimeError(
|
||||
'{} is alive, but _handle.data is not '
|
||||
'initialized'.format(name))
|
||||
return res
|
||||
|
||||
cdef inline _ensure_alive(self):
|
||||
if not self._is_alive():
|
||||
raise RuntimeError(
|
||||
'unable to perform operation on {!r}; '
|
||||
'the handler is closed'.format(self))
|
||||
|
||||
cdef _fatal_error(self, exc, throw, reason=None):
|
||||
# Fatal error means an error that was returned by the
|
||||
# underlying libuv handle function. We usually can't
|
||||
# recover from that, hence we just close the handle.
|
||||
self._close()
|
||||
|
||||
if throw or self._loop is None:
|
||||
raise exc
|
||||
else:
|
||||
self._loop._handle_exception(exc)
|
||||
|
||||
cdef _error(self, exc, throw):
|
||||
# A non-fatal error is usually an error that was caught
|
||||
# by the handler, but was originated in the client code
|
||||
# (not in libuv). In this case we either want to simply
|
||||
# raise or log it.
|
||||
if throw or self._loop is None:
|
||||
raise exc
|
||||
else:
|
||||
self._loop._handle_exception(exc)
|
||||
|
||||
cdef _close(self):
|
||||
if self._closed == 1:
|
||||
return
|
||||
|
||||
self._closed = 1
|
||||
|
||||
if self._handle is NULL:
|
||||
return
|
||||
|
||||
if UVLOOP_DEBUG:
|
||||
if self._handle.data is NULL:
|
||||
raise RuntimeError(
|
||||
'{}._close: _handle.data is NULL'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
if <object>self._handle.data is not self:
|
||||
raise RuntimeError(
|
||||
'{}._close: _handle.data is not UVHandle/self'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
if uv.uv_is_closing(self._handle):
|
||||
raise RuntimeError(
|
||||
'{}._close: uv_is_closing() is true'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
# We want the handle wrapper (UVHandle) to stay alive until
|
||||
# the closing callback fires.
|
||||
Py_INCREF(self)
|
||||
uv.uv_close(self._handle, __uv_close_handle_cb) # void; no errors
|
||||
|
||||
def __repr__(self):
|
||||
return '<{} closed={} {:#x}>'.format(
|
||||
self.__class__.__name__,
|
||||
self._closed,
|
||||
id(self))
|
||||
|
||||
|
||||
cdef class UVSocketHandle(UVHandle):
|
||||
|
||||
def __cinit__(self):
|
||||
self._fileobj = None
|
||||
self.__cached_socket = None
|
||||
|
||||
cdef _fileno(self):
|
||||
cdef:
|
||||
int fd
|
||||
int err
|
||||
|
||||
self._ensure_alive()
|
||||
err = uv.uv_fileno(self._handle, <uv.uv_os_fd_t*>&fd)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
return fd
|
||||
|
||||
cdef _new_socket(self):
|
||||
raise NotImplementedError
|
||||
|
||||
cdef inline _get_socket(self):
|
||||
if self.__cached_socket is not None:
|
||||
return self.__cached_socket
|
||||
|
||||
if not self._is_alive():
|
||||
return None
|
||||
|
||||
self.__cached_socket = self._new_socket()
|
||||
if UVLOOP_DEBUG:
|
||||
# We don't "dup" for the "__cached_socket".
|
||||
assert self.__cached_socket.fileno() == self._fileno()
|
||||
return self.__cached_socket
|
||||
|
||||
cdef inline _attach_fileobj(self, object file):
|
||||
# When we create a TCP/PIPE/etc connection/server based on
|
||||
# a Python file object, we need to close the file object when
|
||||
# the uv handle is closed.
|
||||
socket_inc_io_ref(file)
|
||||
self._fileobj = file
|
||||
|
||||
cdef _close(self):
|
||||
if self.__cached_socket is not None:
|
||||
(<PseudoSocket>self.__cached_socket)._fd = -1
|
||||
|
||||
UVHandle._close(self)
|
||||
|
||||
try:
|
||||
# This code will only run for transports created from
|
||||
# Python sockets, i.e. with `loop.create_server(sock=sock)` etc.
|
||||
if self._fileobj is not None:
|
||||
if isinstance(self._fileobj, socket_socket):
|
||||
# Detaching the socket object is the ideal solution:
|
||||
# * libuv will actually close the FD;
|
||||
# * detach() call will reset FD for the Python socket
|
||||
# object, which means that it won't be closed 2nd time
|
||||
# when the socket object is GCed.
|
||||
#
|
||||
# No need to call `socket_dec_io_ref()`, as
|
||||
# `socket.detach()` ignores `socket._io_refs`.
|
||||
self._fileobj.detach()
|
||||
else:
|
||||
try:
|
||||
# `socket.close()` will raise an EBADF because libuv
|
||||
# has already closed the underlying FD.
|
||||
self._fileobj.close()
|
||||
except OSError as ex:
|
||||
if ex.errno != errno_EBADF:
|
||||
raise
|
||||
except Exception as ex:
|
||||
self._loop.call_exception_handler({
|
||||
'exception': ex,
|
||||
'transport': self,
|
||||
'message': f'could not close attached file object '
|
||||
f'{self._fileobj!r}',
|
||||
})
|
||||
finally:
|
||||
self._fileobj = None
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
cdef inline bint __ensure_handle_data(uv.uv_handle_t* handle,
|
||||
const char* handle_ctx):
|
||||
|
||||
cdef Loop loop
|
||||
|
||||
if UVLOOP_DEBUG:
|
||||
if handle.loop is NULL:
|
||||
raise RuntimeError(
|
||||
'handle.loop is NULL in __ensure_handle_data')
|
||||
|
||||
if handle.loop.data is NULL:
|
||||
raise RuntimeError(
|
||||
'handle.loop.data is NULL in __ensure_handle_data')
|
||||
|
||||
if handle.data is NULL:
|
||||
loop = <Loop>handle.loop.data
|
||||
loop.call_exception_handler({
|
||||
'message': '{} called with handle.data == NULL'.format(
|
||||
handle_ctx.decode('latin-1'))
|
||||
})
|
||||
return 0
|
||||
|
||||
if handle.data is NULL:
|
||||
# The underlying UVHandle object was GCed with an open uv_handle_t.
|
||||
loop = <Loop>handle.loop.data
|
||||
loop.call_exception_handler({
|
||||
'message': '{} called after destroying the UVHandle'.format(
|
||||
handle_ctx.decode('latin-1'))
|
||||
})
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) noexcept with gil:
|
||||
cdef UVHandle h
|
||||
|
||||
if handle.data is NULL:
|
||||
# The original UVHandle is long dead. Just free the mem of
|
||||
# the uv_handle_t* handler.
|
||||
|
||||
if UVLOOP_DEBUG:
|
||||
if handle.loop == NULL or handle.loop.data == NULL:
|
||||
raise RuntimeError(
|
||||
'__uv_close_handle_cb: handle.loop is invalid')
|
||||
(<Loop>handle.loop.data)._debug_uv_handles_freed += 1
|
||||
|
||||
PyMem_RawFree(handle)
|
||||
else:
|
||||
h = <UVHandle>handle.data
|
||||
try:
|
||||
if UVLOOP_DEBUG:
|
||||
if not h._has_handle:
|
||||
raise RuntimeError(
|
||||
'has_handle=0 in __uv_close_handle_cb')
|
||||
h._loop._debug_handles_closed.update([
|
||||
h.__class__.__name__])
|
||||
h._free()
|
||||
finally:
|
||||
Py_DECREF(h) # Was INCREFed in UVHandle._close
|
||||
|
||||
|
||||
cdef void __close_all_handles(Loop loop) noexcept:
|
||||
uv.uv_walk(loop.uvloop,
|
||||
__uv_walk_close_all_handles_cb,
|
||||
<void*>loop) # void
|
||||
|
||||
|
||||
cdef void __uv_walk_close_all_handles_cb(
|
||||
uv.uv_handle_t* handle,
|
||||
void* arg,
|
||||
) noexcept with gil:
|
||||
|
||||
cdef:
|
||||
Loop loop = <Loop>arg
|
||||
UVHandle h
|
||||
|
||||
if uv.uv_is_closing(handle):
|
||||
# The handle is closed or is closing.
|
||||
return
|
||||
|
||||
if handle.data is NULL:
|
||||
# This shouldn't happen. Ever.
|
||||
loop.call_exception_handler({
|
||||
'message': 'handle.data is NULL in __close_all_handles_cb'
|
||||
})
|
||||
return
|
||||
|
||||
h = <UVHandle>handle.data
|
||||
if not h._closed:
|
||||
h._warn_unclosed()
|
||||
h._close()
|
14
env/lib/python3.11/site-packages/uvloop/handles/idle.pxd
vendored
Normal file
14
env/lib/python3.11/site-packages/uvloop/handles/idle.pxd
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
cdef class UVIdle(UVHandle):
|
||||
cdef:
|
||||
Handle h
|
||||
bint running
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef _init(self, Loop loop, Handle h)
|
||||
|
||||
cdef inline stop(self)
|
||||
cdef inline start(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVIdle new(Loop loop, Handle h)
|
72
env/lib/python3.11/site-packages/uvloop/handles/idle.pyx
vendored
Normal file
72
env/lib/python3.11/site-packages/uvloop/handles/idle.pyx
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVIdle(UVHandle):
|
||||
cdef _init(self, Loop loop, Handle h):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_idle_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_idle_init(self._loop.uvloop, <uv.uv_idle_t*>self._handle)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.h = h
|
||||
self.running = 0
|
||||
|
||||
cdef inline stop(self):
|
||||
cdef int err
|
||||
|
||||
if not self._is_alive():
|
||||
self.running = 0
|
||||
return
|
||||
|
||||
if self.running == 1:
|
||||
err = uv.uv_idle_stop(<uv.uv_idle_t*>self._handle)
|
||||
self.running = 0
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef inline start(self):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
if self.running == 0:
|
||||
err = uv.uv_idle_start(<uv.uv_idle_t*>self._handle,
|
||||
cb_idle_callback)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
self.running = 1
|
||||
|
||||
@staticmethod
|
||||
cdef UVIdle new(Loop loop, Handle h):
|
||||
cdef UVIdle handle
|
||||
handle = UVIdle.__new__(UVIdle)
|
||||
handle._init(loop, h)
|
||||
return handle
|
||||
|
||||
|
||||
cdef void cb_idle_callback(
|
||||
uv.uv_idle_t* handle,
|
||||
) noexcept with gil:
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVIdle callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVIdle idle = <UVIdle> handle.data
|
||||
Handle h = idle.h
|
||||
try:
|
||||
h._run()
|
||||
except BaseException as ex:
|
||||
idle._error(ex, False)
|
33
env/lib/python3.11/site-packages/uvloop/handles/pipe.pxd
vendored
Normal file
33
env/lib/python3.11/site-packages/uvloop/handles/pipe.pxd
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
cdef class UnixServer(UVStreamServer):
|
||||
|
||||
cdef bind(self, str path)
|
||||
|
||||
@staticmethod
|
||||
cdef UnixServer new(Loop loop, object protocol_factory, Server server,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout)
|
||||
|
||||
|
||||
cdef class UnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef UnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter, object context)
|
||||
|
||||
cdef connect(self, char* addr)
|
||||
|
||||
|
||||
cdef class ReadUnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter)
|
||||
|
||||
|
||||
cdef class WriteUnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter)
|
247
env/lib/python3.11/site-packages/uvloop/handles/pipe.pyx
vendored
Normal file
247
env/lib/python3.11/site-packages/uvloop/handles/pipe.pyx
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
cdef __pipe_init_uv_handle(UVStream handle, Loop loop):
|
||||
cdef int err
|
||||
|
||||
handle._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_pipe_t))
|
||||
if handle._handle is NULL:
|
||||
handle._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
# Initialize pipe handle with ipc=0.
|
||||
# ipc=1 means that libuv will use recvmsg/sendmsg
|
||||
# instead of recv/send.
|
||||
err = uv.uv_pipe_init(handle._loop.uvloop,
|
||||
<uv.uv_pipe_t*>handle._handle,
|
||||
0)
|
||||
# UV_HANDLE_READABLE allows calling uv_read_start() on this pipe
|
||||
# even if it is O_WRONLY, see also #317, libuv/libuv#2058
|
||||
handle._handle.flags |= uv.UV_INTERNAL_HANDLE_READABLE
|
||||
if err < 0:
|
||||
handle._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
handle._finish_init()
|
||||
|
||||
|
||||
cdef __pipe_open(UVStream handle, int fd):
|
||||
cdef int err
|
||||
err = uv.uv_pipe_open(<uv.uv_pipe_t *>handle._handle,
|
||||
<uv.uv_os_fd_t>fd)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
|
||||
cdef __pipe_get_socket(UVSocketHandle handle):
|
||||
fileno = handle._fileno()
|
||||
return PseudoSocket(uv.AF_UNIX, uv.SOCK_STREAM, 0, fileno)
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class UnixServer(UVStreamServer):
|
||||
|
||||
@staticmethod
|
||||
cdef UnixServer new(Loop loop, object protocol_factory, Server server,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout):
|
||||
|
||||
cdef UnixServer handle
|
||||
handle = UnixServer.__new__(UnixServer)
|
||||
handle._init(loop, protocol_factory, server, backlog,
|
||||
ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
|
||||
__pipe_init_uv_handle(<UVStream>handle, loop)
|
||||
return handle
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __pipe_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
self._ensure_alive()
|
||||
__pipe_open(<UVStream>self, sockfd)
|
||||
self._mark_as_open()
|
||||
|
||||
cdef bind(self, str path):
|
||||
cdef int err
|
||||
self._ensure_alive()
|
||||
err = uv.uv_pipe_bind(<uv.uv_pipe_t *>self._handle,
|
||||
path.encode())
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
self._mark_as_open()
|
||||
|
||||
cdef UVStream _make_new_transport(self, object protocol, object waiter,
|
||||
object context):
|
||||
cdef UnixTransport tr
|
||||
tr = UnixTransport.new(self._loop, protocol, self._server, waiter,
|
||||
context)
|
||||
return <UVStream>tr
|
||||
|
||||
cdef _close(self):
|
||||
sock = self._fileobj
|
||||
if sock is not None and sock in self._loop._unix_server_sockets:
|
||||
path = sock.getsockname()
|
||||
else:
|
||||
path = None
|
||||
|
||||
UVStreamServer._close(self)
|
||||
|
||||
if path is not None:
|
||||
prev_ino = self._loop._unix_server_sockets[sock]
|
||||
del self._loop._unix_server_sockets[sock]
|
||||
try:
|
||||
if os_stat(path).st_ino == prev_ino:
|
||||
os_unlink(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except OSError as err:
|
||||
aio_logger.error('Unable to clean up listening UNIX socket '
|
||||
'%r: %r', path, err)
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class UnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef UnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter, object context):
|
||||
|
||||
cdef UnixTransport handle
|
||||
handle = UnixTransport.__new__(UnixTransport)
|
||||
handle._init(loop, protocol, server, waiter, context)
|
||||
__pipe_init_uv_handle(<UVStream>handle, loop)
|
||||
return handle
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __pipe_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
__pipe_open(<UVStream>self, sockfd)
|
||||
|
||||
cdef connect(self, char* addr):
|
||||
cdef _PipeConnectRequest req
|
||||
req = _PipeConnectRequest(self._loop, self)
|
||||
req.connect(addr)
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class ReadUnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter):
|
||||
cdef ReadUnixTransport handle
|
||||
handle = ReadUnixTransport.__new__(ReadUnixTransport)
|
||||
# This is only used in connect_read_pipe() and subprocess_shell/exec()
|
||||
# directly, we could simply copy the current context.
|
||||
handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
|
||||
__pipe_init_uv_handle(<UVStream>handle, loop)
|
||||
return handle
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __pipe_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
__pipe_open(<UVStream>self, sockfd)
|
||||
|
||||
def get_write_buffer_limits(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def set_write_buffer_limits(self, high=None, low=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_write_buffer_size(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def write(self, data):
|
||||
raise NotImplementedError
|
||||
|
||||
def writelines(self, list_of_data):
|
||||
raise NotImplementedError
|
||||
|
||||
def write_eof(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def can_write_eof(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def abort(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class WriteUnixTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter):
|
||||
cdef WriteUnixTransport handle
|
||||
handle = WriteUnixTransport.__new__(WriteUnixTransport)
|
||||
|
||||
# We listen for read events on write-end of the pipe. When
|
||||
# the read-end is close, the uv_stream_t.read callback will
|
||||
# receive an error -- we want to silence that error, and just
|
||||
# close the transport.
|
||||
handle._close_on_read_error()
|
||||
|
||||
# This is only used in connect_write_pipe() and subprocess_shell/exec()
|
||||
# directly, we could simply copy the current context.
|
||||
handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
|
||||
__pipe_init_uv_handle(<UVStream>handle, loop)
|
||||
return handle
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __pipe_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
__pipe_open(<UVStream>self, sockfd)
|
||||
|
||||
def pause_reading(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def resume_reading(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
cdef class _PipeConnectRequest(UVRequest):
|
||||
cdef:
|
||||
UnixTransport transport
|
||||
uv.uv_connect_t _req_data
|
||||
|
||||
def __cinit__(self, loop, transport):
|
||||
self.request = <uv.uv_req_t*> &self._req_data
|
||||
self.request.data = <void*>self
|
||||
self.transport = transport
|
||||
|
||||
cdef connect(self, char* addr):
|
||||
# uv_pipe_connect returns void
|
||||
uv.uv_pipe_connect(<uv.uv_connect_t*>self.request,
|
||||
<uv.uv_pipe_t*>self.transport._handle,
|
||||
addr,
|
||||
__pipe_connect_callback)
|
||||
|
||||
cdef void __pipe_connect_callback(
|
||||
uv.uv_connect_t* req,
|
||||
int status,
|
||||
) noexcept with gil:
|
||||
cdef:
|
||||
_PipeConnectRequest wrapper
|
||||
UnixTransport transport
|
||||
|
||||
wrapper = <_PipeConnectRequest> req.data
|
||||
transport = wrapper.transport
|
||||
|
||||
if status < 0:
|
||||
exc = convert_error(status)
|
||||
else:
|
||||
exc = None
|
||||
|
||||
try:
|
||||
transport._on_connect(exc)
|
||||
except BaseException as ex:
|
||||
wrapper.transport._fatal_error(ex, False)
|
||||
finally:
|
||||
wrapper.on_done()
|
25
env/lib/python3.11/site-packages/uvloop/handles/poll.pxd
vendored
Normal file
25
env/lib/python3.11/site-packages/uvloop/handles/poll.pxd
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
cdef class UVPoll(UVHandle):
|
||||
cdef:
|
||||
int fd
|
||||
Handle reading_handle
|
||||
Handle writing_handle
|
||||
|
||||
cdef _init(self, Loop loop, int fd)
|
||||
cdef _close(self)
|
||||
|
||||
cdef inline _poll_start(self, int flags)
|
||||
cdef inline _poll_stop(self)
|
||||
|
||||
cdef int is_active(self) noexcept
|
||||
|
||||
cdef is_reading(self)
|
||||
cdef is_writing(self)
|
||||
|
||||
cdef start_reading(self, Handle callback)
|
||||
cdef start_writing(self, Handle callback)
|
||||
cdef stop_reading(self)
|
||||
cdef stop_writing(self)
|
||||
cdef stop(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVPoll new(Loop loop, int fd)
|
233
env/lib/python3.11/site-packages/uvloop/handles/poll.pyx
vendored
Normal file
233
env/lib/python3.11/site-packages/uvloop/handles/poll.pyx
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVPoll(UVHandle):
|
||||
cdef _init(self, Loop loop, int fd):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_poll_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_poll_init(self._loop.uvloop,
|
||||
<uv.uv_poll_t *>self._handle, fd)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.fd = fd
|
||||
self.reading_handle = None
|
||||
self.writing_handle = None
|
||||
|
||||
@staticmethod
|
||||
cdef UVPoll new(Loop loop, int fd):
|
||||
cdef UVPoll handle
|
||||
handle = UVPoll.__new__(UVPoll)
|
||||
handle._init(loop, fd)
|
||||
return handle
|
||||
|
||||
cdef int is_active(self) noexcept:
|
||||
return (self.reading_handle is not None or
|
||||
self.writing_handle is not None)
|
||||
|
||||
cdef inline _poll_start(self, int flags):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_poll_start(
|
||||
<uv.uv_poll_t*>self._handle,
|
||||
flags,
|
||||
__on_uvpoll_event)
|
||||
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef inline _poll_stop(self):
|
||||
cdef int err
|
||||
|
||||
if not self._is_alive():
|
||||
return
|
||||
|
||||
err = uv.uv_poll_stop(<uv.uv_poll_t*>self._handle)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef:
|
||||
int backend_id
|
||||
system.epoll_event dummy_event
|
||||
|
||||
if system.PLATFORM_IS_LINUX:
|
||||
# libuv doesn't remove the FD from epoll immediately
|
||||
# after uv_poll_stop or uv_poll_close, causing hard
|
||||
# to debug issue with dup-ed file descriptors causing
|
||||
# CPU burn in epoll/epoll_ctl:
|
||||
# https://github.com/MagicStack/uvloop/issues/61
|
||||
#
|
||||
# It's safe though to manually call epoll_ctl here,
|
||||
# after calling uv_poll_stop.
|
||||
|
||||
backend_id = uv.uv_backend_fd(self._loop.uvloop)
|
||||
if backend_id != -1:
|
||||
memset(&dummy_event, 0, sizeof(dummy_event))
|
||||
system.epoll_ctl(
|
||||
backend_id,
|
||||
system.EPOLL_CTL_DEL,
|
||||
self.fd,
|
||||
&dummy_event) # ignore errors
|
||||
|
||||
cdef is_reading(self):
|
||||
return self._is_alive() and self.reading_handle is not None
|
||||
|
||||
cdef is_writing(self):
|
||||
return self._is_alive() and self.writing_handle is not None
|
||||
|
||||
cdef start_reading(self, Handle callback):
|
||||
cdef:
|
||||
int mask = 0
|
||||
|
||||
if self.reading_handle is None:
|
||||
# not reading right now, setup the handle
|
||||
|
||||
mask = uv.UV_READABLE
|
||||
if self.writing_handle is not None:
|
||||
# are we writing right now?
|
||||
mask |= uv.UV_WRITABLE
|
||||
|
||||
self._poll_start(mask)
|
||||
else:
|
||||
self.reading_handle._cancel()
|
||||
|
||||
self.reading_handle = callback
|
||||
|
||||
cdef start_writing(self, Handle callback):
|
||||
cdef:
|
||||
int mask = 0
|
||||
|
||||
if self.writing_handle is None:
|
||||
# not writing right now, setup the handle
|
||||
|
||||
mask = uv.UV_WRITABLE
|
||||
if self.reading_handle is not None:
|
||||
# are we reading right now?
|
||||
mask |= uv.UV_READABLE
|
||||
|
||||
self._poll_start(mask)
|
||||
else:
|
||||
self.writing_handle._cancel()
|
||||
|
||||
self.writing_handle = callback
|
||||
|
||||
cdef stop_reading(self):
|
||||
if self.reading_handle is None:
|
||||
return False
|
||||
|
||||
self.reading_handle._cancel()
|
||||
self.reading_handle = None
|
||||
|
||||
if self.writing_handle is None:
|
||||
self.stop()
|
||||
else:
|
||||
self._poll_start(uv.UV_WRITABLE)
|
||||
|
||||
return True
|
||||
|
||||
cdef stop_writing(self):
|
||||
if self.writing_handle is None:
|
||||
return False
|
||||
|
||||
self.writing_handle._cancel()
|
||||
self.writing_handle = None
|
||||
|
||||
if self.reading_handle is None:
|
||||
self.stop()
|
||||
else:
|
||||
self._poll_start(uv.UV_READABLE)
|
||||
|
||||
return True
|
||||
|
||||
cdef stop(self):
|
||||
if self.reading_handle is not None:
|
||||
self.reading_handle._cancel()
|
||||
self.reading_handle = None
|
||||
|
||||
if self.writing_handle is not None:
|
||||
self.writing_handle._cancel()
|
||||
self.writing_handle = None
|
||||
|
||||
self._poll_stop()
|
||||
|
||||
cdef _close(self):
|
||||
if self.is_active():
|
||||
self.stop()
|
||||
|
||||
UVHandle._close(<UVHandle>self)
|
||||
|
||||
cdef _fatal_error(self, exc, throw, reason=None):
|
||||
try:
|
||||
if self.reading_handle is not None:
|
||||
try:
|
||||
self.reading_handle._run()
|
||||
except BaseException as ex:
|
||||
self._loop._handle_exception(ex)
|
||||
self.reading_handle = None
|
||||
|
||||
if self.writing_handle is not None:
|
||||
try:
|
||||
self.writing_handle._run()
|
||||
except BaseException as ex:
|
||||
self._loop._handle_exception(ex)
|
||||
self.writing_handle = None
|
||||
|
||||
finally:
|
||||
self._close()
|
||||
|
||||
|
||||
cdef void __on_uvpoll_event(
|
||||
uv.uv_poll_t* handle,
|
||||
int status,
|
||||
int events,
|
||||
) noexcept with gil:
|
||||
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVPoll callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVPoll poll = <UVPoll> handle.data
|
||||
|
||||
if status < 0:
|
||||
exc = convert_error(status)
|
||||
poll._fatal_error(exc, False)
|
||||
return
|
||||
|
||||
if ((events & (uv.UV_READABLE | uv.UV_DISCONNECT)) and
|
||||
poll.reading_handle is not None):
|
||||
|
||||
try:
|
||||
if UVLOOP_DEBUG:
|
||||
poll._loop._poll_read_events_total += 1
|
||||
poll.reading_handle._run()
|
||||
except BaseException as ex:
|
||||
if UVLOOP_DEBUG:
|
||||
poll._loop._poll_read_cb_errors_total += 1
|
||||
poll._error(ex, False)
|
||||
# continue code execution
|
||||
|
||||
if ((events & (uv.UV_WRITABLE | uv.UV_DISCONNECT)) and
|
||||
poll.writing_handle is not None):
|
||||
|
||||
try:
|
||||
if UVLOOP_DEBUG:
|
||||
poll._loop._poll_write_events_total += 1
|
||||
poll.writing_handle._run()
|
||||
except BaseException as ex:
|
||||
if UVLOOP_DEBUG:
|
||||
poll._loop._poll_write_cb_errors_total += 1
|
||||
poll._error(ex, False)
|
80
env/lib/python3.11/site-packages/uvloop/handles/process.pxd
vendored
Normal file
80
env/lib/python3.11/site-packages/uvloop/handles/process.pxd
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
cdef class UVProcess(UVHandle):
|
||||
cdef:
|
||||
object _returncode
|
||||
object _pid
|
||||
|
||||
object _errpipe_read
|
||||
object _errpipe_write
|
||||
object _preexec_fn
|
||||
bint _restore_signals
|
||||
|
||||
list _fds_to_close
|
||||
|
||||
# Attributes used to compose uv_process_options_t:
|
||||
uv.uv_process_options_t options
|
||||
uv.uv_stdio_container_t[3] iocnt
|
||||
list __env
|
||||
char **uv_opt_env
|
||||
list __args
|
||||
char **uv_opt_args
|
||||
char *uv_opt_file
|
||||
bytes __cwd
|
||||
|
||||
cdef _close_process_handle(self)
|
||||
|
||||
cdef _init(self, Loop loop, list args, dict env, cwd,
|
||||
start_new_session,
|
||||
_stdin, _stdout, _stderr, pass_fds,
|
||||
debug_flags, preexec_fn, restore_signals)
|
||||
|
||||
cdef _after_fork(self)
|
||||
|
||||
cdef char** __to_cstring_array(self, list arr)
|
||||
cdef _init_args(self, list args)
|
||||
cdef _init_env(self, dict env)
|
||||
cdef _init_files(self, _stdin, _stdout, _stderr)
|
||||
cdef _init_options(self, list args, dict env, cwd, start_new_session,
|
||||
_stdin, _stdout, _stderr, bint force_fork)
|
||||
|
||||
cdef _close_after_spawn(self, int fd)
|
||||
|
||||
cdef _on_exit(self, int64_t exit_status, int term_signal)
|
||||
cdef _kill(self, int signum)
|
||||
|
||||
|
||||
cdef class UVProcessTransport(UVProcess):
|
||||
cdef:
|
||||
list _exit_waiters
|
||||
list _init_futs
|
||||
bint _stdio_ready
|
||||
list _pending_calls
|
||||
object _protocol
|
||||
bint _finished
|
||||
|
||||
WriteUnixTransport _stdin
|
||||
ReadUnixTransport _stdout
|
||||
ReadUnixTransport _stderr
|
||||
|
||||
object stdin_proto
|
||||
object stdout_proto
|
||||
object stderr_proto
|
||||
|
||||
cdef _file_redirect_stdio(self, int fd)
|
||||
cdef _file_devnull(self)
|
||||
cdef _file_inpipe(self)
|
||||
cdef _file_outpipe(self)
|
||||
|
||||
cdef _check_proc(self)
|
||||
cdef _pipe_connection_lost(self, int fd, exc)
|
||||
cdef _pipe_data_received(self, int fd, data)
|
||||
|
||||
cdef _call_connection_made(self, waiter)
|
||||
cdef _try_finish(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVProcessTransport new(Loop loop, protocol, args, env, cwd,
|
||||
start_new_session,
|
||||
_stdin, _stdout, _stderr, pass_fds,
|
||||
waiter,
|
||||
debug_flags,
|
||||
preexec_fn, restore_signals)
|
792
env/lib/python3.11/site-packages/uvloop/handles/process.pyx
vendored
Normal file
792
env/lib/python3.11/site-packages/uvloop/handles/process.pyx
vendored
Normal file
@ -0,0 +1,792 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVProcess(UVHandle):
|
||||
"""Abstract class; wrapper over uv_process_t handle."""
|
||||
|
||||
def __cinit__(self):
|
||||
self.uv_opt_env = NULL
|
||||
self.uv_opt_args = NULL
|
||||
self._returncode = None
|
||||
self._pid = None
|
||||
self._fds_to_close = list()
|
||||
self._preexec_fn = None
|
||||
self._restore_signals = True
|
||||
self.context = Context_CopyCurrent()
|
||||
|
||||
cdef _close_process_handle(self):
|
||||
# XXX: This is a workaround for a libuv bug:
|
||||
# - https://github.com/libuv/libuv/issues/1933
|
||||
# - https://github.com/libuv/libuv/pull/551
|
||||
if self._handle is NULL:
|
||||
return
|
||||
self._handle.data = NULL
|
||||
uv.uv_close(self._handle, __uv_close_process_handle_cb)
|
||||
self._handle = NULL # close callback will free() the memory
|
||||
|
||||
cdef _init(self, Loop loop, list args, dict env,
|
||||
cwd, start_new_session,
|
||||
_stdin, _stdout, _stderr, # std* can be defined as macros in C
|
||||
pass_fds, debug_flags, preexec_fn, restore_signals):
|
||||
|
||||
global __forking
|
||||
global __forking_loop
|
||||
global __forkHandler
|
||||
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(
|
||||
sizeof(uv.uv_process_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
# Too early to call _finish_init, but still a lot of work to do.
|
||||
# Let's set handle.data to NULL, so in case something goes wrong,
|
||||
# callbacks have a chance to avoid casting *something* into UVHandle.
|
||||
self._handle.data = NULL
|
||||
|
||||
force_fork = False
|
||||
if system.PLATFORM_IS_APPLE and not (
|
||||
preexec_fn is None
|
||||
and not pass_fds
|
||||
):
|
||||
# see _execute_child() in CPython/subprocess.py
|
||||
force_fork = True
|
||||
|
||||
try:
|
||||
self._init_options(args, env, cwd, start_new_session,
|
||||
_stdin, _stdout, _stderr, force_fork)
|
||||
|
||||
restore_inheritable = set()
|
||||
if pass_fds:
|
||||
for fd in pass_fds:
|
||||
if not os_get_inheritable(fd):
|
||||
restore_inheritable.add(fd)
|
||||
os_set_inheritable(fd, True)
|
||||
except Exception:
|
||||
self._abort_init()
|
||||
raise
|
||||
|
||||
if __forking or loop.active_process_handler is not None:
|
||||
# Our pthread_atfork handlers won't work correctly when
|
||||
# another loop is forking in another thread (even though
|
||||
# GIL should help us to avoid that.)
|
||||
self._abort_init()
|
||||
raise RuntimeError(
|
||||
'Racing with another loop to spawn a process.')
|
||||
|
||||
self._errpipe_read, self._errpipe_write = os_pipe()
|
||||
fds_to_close = self._fds_to_close
|
||||
self._fds_to_close = None
|
||||
fds_to_close.append(self._errpipe_read)
|
||||
# add the write pipe last so we can close it early
|
||||
fds_to_close.append(self._errpipe_write)
|
||||
try:
|
||||
os_set_inheritable(self._errpipe_write, True)
|
||||
|
||||
self._preexec_fn = preexec_fn
|
||||
self._restore_signals = restore_signals
|
||||
|
||||
loop.active_process_handler = self
|
||||
__forking = 1
|
||||
__forking_loop = loop
|
||||
system.setForkHandler(<system.OnForkHandler>&__get_fork_handler)
|
||||
|
||||
PyOS_BeforeFork()
|
||||
|
||||
err = uv.uv_spawn(loop.uvloop,
|
||||
<uv.uv_process_t*>self._handle,
|
||||
&self.options)
|
||||
|
||||
__forking = 0
|
||||
__forking_loop = None
|
||||
system.resetForkHandler()
|
||||
loop.active_process_handler = None
|
||||
|
||||
PyOS_AfterFork_Parent()
|
||||
|
||||
if err < 0:
|
||||
self._close_process_handle()
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
# close the write pipe early
|
||||
os_close(fds_to_close.pop())
|
||||
|
||||
if preexec_fn is not None:
|
||||
errpipe_data = bytearray()
|
||||
while True:
|
||||
# XXX: This is a blocking code that has to be
|
||||
# rewritten (using loop.connect_read_pipe() or
|
||||
# otherwise.)
|
||||
part = os_read(self._errpipe_read, 50000)
|
||||
errpipe_data += part
|
||||
if not part or len(errpipe_data) > 50000:
|
||||
break
|
||||
|
||||
finally:
|
||||
while fds_to_close:
|
||||
os_close(fds_to_close.pop())
|
||||
|
||||
for fd in restore_inheritable:
|
||||
os_set_inheritable(fd, False)
|
||||
|
||||
# asyncio caches the PID in BaseSubprocessTransport,
|
||||
# so that the transport knows what the PID was even
|
||||
# after the process is finished.
|
||||
self._pid = (<uv.uv_process_t*>self._handle).pid
|
||||
|
||||
# Track the process handle (create a strong ref to it)
|
||||
# to guarantee that __dealloc__ doesn't happen in an
|
||||
# uncontrolled fashion. We want to wait until the process
|
||||
# exits and libuv calls __uvprocess_on_exit_callback,
|
||||
# which will call `UVProcess._close()`, which will, in turn,
|
||||
# untrack this handle.
|
||||
self._loop._track_process(self)
|
||||
|
||||
if debug_flags & __PROCESS_DEBUG_SLEEP_AFTER_FORK:
|
||||
time_sleep(1)
|
||||
|
||||
if preexec_fn is not None and errpipe_data:
|
||||
# preexec_fn has raised an exception. The child
|
||||
# process must be dead now.
|
||||
try:
|
||||
exc_name, exc_msg = errpipe_data.split(b':', 1)
|
||||
exc_name = exc_name.decode()
|
||||
exc_msg = exc_msg.decode()
|
||||
except Exception:
|
||||
self._close()
|
||||
raise subprocess_SubprocessError(
|
||||
'Bad exception data from child: {!r}'.format(
|
||||
errpipe_data))
|
||||
exc_cls = getattr(__builtins__, exc_name,
|
||||
subprocess_SubprocessError)
|
||||
|
||||
exc = subprocess_SubprocessError(
|
||||
'Exception occurred in preexec_fn.')
|
||||
exc.__cause__ = exc_cls(exc_msg)
|
||||
self._close()
|
||||
raise exc
|
||||
|
||||
cdef _after_fork(self):
|
||||
# See CPython/_posixsubprocess.c for details
|
||||
cdef int err
|
||||
|
||||
if self._restore_signals:
|
||||
_Py_RestoreSignals()
|
||||
|
||||
PyOS_AfterFork_Child()
|
||||
|
||||
err = uv.uv_loop_fork(self._loop.uvloop)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
if self._preexec_fn is not None:
|
||||
try:
|
||||
gc_disable()
|
||||
self._preexec_fn()
|
||||
except BaseException as ex:
|
||||
try:
|
||||
with open(self._errpipe_write, 'wb') as f:
|
||||
f.write(str(ex.__class__.__name__).encode())
|
||||
f.write(b':')
|
||||
f.write(str(ex.args[0]).encode())
|
||||
finally:
|
||||
system._exit(255)
|
||||
return
|
||||
else:
|
||||
os_close(self._errpipe_write)
|
||||
else:
|
||||
os_close(self._errpipe_write)
|
||||
|
||||
cdef _close_after_spawn(self, int fd):
|
||||
if self._fds_to_close is None:
|
||||
raise RuntimeError(
|
||||
'UVProcess._close_after_spawn called after uv_spawn')
|
||||
self._fds_to_close.append(fd)
|
||||
|
||||
def __dealloc__(self):
|
||||
if self.uv_opt_env is not NULL:
|
||||
PyMem_RawFree(self.uv_opt_env)
|
||||
self.uv_opt_env = NULL
|
||||
|
||||
if self.uv_opt_args is not NULL:
|
||||
PyMem_RawFree(self.uv_opt_args)
|
||||
self.uv_opt_args = NULL
|
||||
|
||||
cdef char** __to_cstring_array(self, list arr):
|
||||
cdef:
|
||||
int i
|
||||
ssize_t arr_len = len(arr)
|
||||
bytes el
|
||||
|
||||
char **ret
|
||||
|
||||
ret = <char **>PyMem_RawMalloc((arr_len + 1) * sizeof(char *))
|
||||
if ret is NULL:
|
||||
raise MemoryError()
|
||||
|
||||
for i in range(arr_len):
|
||||
el = arr[i]
|
||||
# NB: PyBytes_AsString doesn't copy the data;
|
||||
# we have to be careful when the "arr" is GCed,
|
||||
# and it shouldn't be ever mutated.
|
||||
ret[i] = PyBytes_AsString(el)
|
||||
|
||||
ret[arr_len] = NULL
|
||||
return ret
|
||||
|
||||
cdef _init_options(self, list args, dict env, cwd, start_new_session,
|
||||
_stdin, _stdout, _stderr, bint force_fork):
|
||||
|
||||
memset(&self.options, 0, sizeof(uv.uv_process_options_t))
|
||||
|
||||
self._init_env(env)
|
||||
self.options.env = self.uv_opt_env
|
||||
|
||||
self._init_args(args)
|
||||
self.options.file = self.uv_opt_file
|
||||
self.options.args = self.uv_opt_args
|
||||
|
||||
if start_new_session:
|
||||
self.options.flags |= uv.UV_PROCESS_DETACHED
|
||||
|
||||
if force_fork:
|
||||
# This is a hack to work around the change in libuv 1.44:
|
||||
# > macos: use posix_spawn instead of fork
|
||||
# where Python subprocess options like preexec_fn are
|
||||
# crippled. CPython only uses posix_spawn under a pretty
|
||||
# strict list of conditions (see subprocess.py), and falls
|
||||
# back to using fork() otherwise. We'd like to simulate such
|
||||
# behavior with libuv, but unfortunately libuv doesn't
|
||||
# provide explicit API to choose such implementation detail.
|
||||
# Based on current (libuv 1.46) behavior, setting
|
||||
# UV_PROCESS_SETUID or UV_PROCESS_SETGID would reliably make
|
||||
# libuv fallback to use fork, so let's just use it for now.
|
||||
self.options.flags |= uv.UV_PROCESS_SETUID
|
||||
self.options.uid = uv.getuid()
|
||||
|
||||
if cwd is not None:
|
||||
cwd = os_fspath(cwd)
|
||||
|
||||
if isinstance(cwd, str):
|
||||
cwd = PyUnicode_EncodeFSDefault(cwd)
|
||||
if not isinstance(cwd, bytes):
|
||||
raise ValueError('cwd must be a str or bytes object')
|
||||
|
||||
self.__cwd = cwd
|
||||
self.options.cwd = PyBytes_AsString(self.__cwd)
|
||||
|
||||
self.options.exit_cb = &__uvprocess_on_exit_callback
|
||||
|
||||
self._init_files(_stdin, _stdout, _stderr)
|
||||
|
||||
cdef _init_args(self, list args):
|
||||
cdef:
|
||||
bytes path
|
||||
int an = len(args)
|
||||
|
||||
if an < 1:
|
||||
raise ValueError('cannot spawn a process: args are empty')
|
||||
|
||||
self.__args = args.copy()
|
||||
for i in range(an):
|
||||
arg = os_fspath(args[i])
|
||||
if isinstance(arg, str):
|
||||
self.__args[i] = PyUnicode_EncodeFSDefault(arg)
|
||||
elif not isinstance(arg, bytes):
|
||||
raise TypeError('all args must be str or bytes')
|
||||
|
||||
path = self.__args[0]
|
||||
self.uv_opt_file = PyBytes_AsString(path)
|
||||
self.uv_opt_args = self.__to_cstring_array(self.__args)
|
||||
|
||||
cdef _init_env(self, dict env):
|
||||
if env is not None:
|
||||
self.__env = list()
|
||||
for key in env:
|
||||
val = env[key]
|
||||
|
||||
if isinstance(key, str):
|
||||
key = PyUnicode_EncodeFSDefault(key)
|
||||
elif not isinstance(key, bytes):
|
||||
raise TypeError(
|
||||
'all environment vars must be bytes or str')
|
||||
|
||||
if isinstance(val, str):
|
||||
val = PyUnicode_EncodeFSDefault(val)
|
||||
elif not isinstance(val, bytes):
|
||||
raise TypeError(
|
||||
'all environment values must be bytes or str')
|
||||
|
||||
self.__env.append(key + b'=' + val)
|
||||
|
||||
self.uv_opt_env = self.__to_cstring_array(self.__env)
|
||||
else:
|
||||
self.__env = None
|
||||
|
||||
cdef _init_files(self, _stdin, _stdout, _stderr):
|
||||
self.options.stdio_count = 0
|
||||
|
||||
cdef _kill(self, int signum):
|
||||
cdef int err
|
||||
self._ensure_alive()
|
||||
err = uv.uv_process_kill(<uv.uv_process_t*>self._handle, signum)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
cdef _on_exit(self, int64_t exit_status, int term_signal):
|
||||
if term_signal:
|
||||
# From Python docs:
|
||||
# A negative value -N indicates that the child was
|
||||
# terminated by signal N (POSIX only).
|
||||
self._returncode = -term_signal
|
||||
else:
|
||||
self._returncode = exit_status
|
||||
|
||||
self._close()
|
||||
|
||||
cdef _close(self):
|
||||
try:
|
||||
if self._loop is not None:
|
||||
self._loop._untrack_process(self)
|
||||
finally:
|
||||
UVHandle._close(self)
|
||||
|
||||
|
||||
DEF _CALL_PIPE_DATA_RECEIVED = 0
|
||||
DEF _CALL_PIPE_CONNECTION_LOST = 1
|
||||
DEF _CALL_PROCESS_EXITED = 2
|
||||
DEF _CALL_CONNECTION_LOST = 3
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class UVProcessTransport(UVProcess):
|
||||
def __cinit__(self):
|
||||
self._exit_waiters = []
|
||||
self._protocol = None
|
||||
|
||||
self._init_futs = []
|
||||
self._pending_calls = []
|
||||
self._stdio_ready = 0
|
||||
|
||||
self._stdin = self._stdout = self._stderr = None
|
||||
self.stdin_proto = self.stdout_proto = self.stderr_proto = None
|
||||
|
||||
self._finished = 0
|
||||
|
||||
cdef _on_exit(self, int64_t exit_status, int term_signal):
|
||||
UVProcess._on_exit(self, exit_status, term_signal)
|
||||
|
||||
if self._stdio_ready:
|
||||
self._loop.call_soon(self._protocol.process_exited,
|
||||
context=self.context)
|
||||
else:
|
||||
self._pending_calls.append((_CALL_PROCESS_EXITED, None, None))
|
||||
|
||||
self._try_finish()
|
||||
|
||||
for waiter in self._exit_waiters:
|
||||
if not waiter.cancelled():
|
||||
waiter.set_result(self._returncode)
|
||||
self._exit_waiters.clear()
|
||||
|
||||
self._close()
|
||||
|
||||
cdef _check_proc(self):
|
||||
if not self._is_alive() or self._returncode is not None:
|
||||
raise ProcessLookupError()
|
||||
|
||||
cdef _pipe_connection_lost(self, int fd, exc):
|
||||
if self._stdio_ready:
|
||||
self._loop.call_soon(self._protocol.pipe_connection_lost, fd, exc,
|
||||
context=self.context)
|
||||
self._try_finish()
|
||||
else:
|
||||
self._pending_calls.append((_CALL_PIPE_CONNECTION_LOST, fd, exc))
|
||||
|
||||
cdef _pipe_data_received(self, int fd, data):
|
||||
if self._stdio_ready:
|
||||
self._loop.call_soon(self._protocol.pipe_data_received, fd, data,
|
||||
context=self.context)
|
||||
else:
|
||||
self._pending_calls.append((_CALL_PIPE_DATA_RECEIVED, fd, data))
|
||||
|
||||
cdef _file_redirect_stdio(self, int fd):
|
||||
fd = os_dup(fd)
|
||||
os_set_inheritable(fd, True)
|
||||
self._close_after_spawn(fd)
|
||||
return fd
|
||||
|
||||
cdef _file_devnull(self):
|
||||
dn = os_open(os_devnull, os_O_RDWR)
|
||||
os_set_inheritable(dn, True)
|
||||
self._close_after_spawn(dn)
|
||||
return dn
|
||||
|
||||
cdef _file_outpipe(self):
|
||||
r, w = __socketpair()
|
||||
os_set_inheritable(w, True)
|
||||
self._close_after_spawn(w)
|
||||
return r, w
|
||||
|
||||
cdef _file_inpipe(self):
|
||||
r, w = __socketpair()
|
||||
os_set_inheritable(r, True)
|
||||
self._close_after_spawn(r)
|
||||
return r, w
|
||||
|
||||
cdef _init_files(self, _stdin, _stdout, _stderr):
|
||||
cdef uv.uv_stdio_container_t *iocnt
|
||||
|
||||
UVProcess._init_files(self, _stdin, _stdout, _stderr)
|
||||
|
||||
io = [None, None, None]
|
||||
|
||||
self.options.stdio_count = 3
|
||||
self.options.stdio = self.iocnt
|
||||
|
||||
if _stdin is not None:
|
||||
if _stdin == subprocess_PIPE:
|
||||
r, w = self._file_inpipe()
|
||||
io[0] = r
|
||||
|
||||
self.stdin_proto = WriteSubprocessPipeProto(self, 0)
|
||||
waiter = self._loop._new_future()
|
||||
self._stdin = WriteUnixTransport.new(
|
||||
self._loop, self.stdin_proto, None, waiter)
|
||||
self._init_futs.append(waiter)
|
||||
self._stdin._open(w)
|
||||
self._stdin._init_protocol()
|
||||
elif _stdin == subprocess_DEVNULL:
|
||||
io[0] = self._file_devnull()
|
||||
elif _stdout == subprocess_STDOUT:
|
||||
raise ValueError(
|
||||
'subprocess.STDOUT is supported only by stderr parameter')
|
||||
else:
|
||||
io[0] = self._file_redirect_stdio(_stdin)
|
||||
else:
|
||||
io[0] = self._file_redirect_stdio(0)
|
||||
|
||||
if _stdout is not None:
|
||||
if _stdout == subprocess_PIPE:
|
||||
# We can't use UV_CREATE_PIPE here, since 'stderr' might be
|
||||
# set to 'subprocess.STDOUT', and there is no way to
|
||||
# emulate that functionality with libuv high-level
|
||||
# streams API. Therefore, we create pipes for stdout and
|
||||
# stderr manually.
|
||||
|
||||
r, w = self._file_outpipe()
|
||||
io[1] = w
|
||||
|
||||
self.stdout_proto = ReadSubprocessPipeProto(self, 1)
|
||||
waiter = self._loop._new_future()
|
||||
self._stdout = ReadUnixTransport.new(
|
||||
self._loop, self.stdout_proto, None, waiter)
|
||||
self._init_futs.append(waiter)
|
||||
self._stdout._open(r)
|
||||
self._stdout._init_protocol()
|
||||
elif _stdout == subprocess_DEVNULL:
|
||||
io[1] = self._file_devnull()
|
||||
elif _stdout == subprocess_STDOUT:
|
||||
raise ValueError(
|
||||
'subprocess.STDOUT is supported only by stderr parameter')
|
||||
else:
|
||||
io[1] = self._file_redirect_stdio(_stdout)
|
||||
else:
|
||||
io[1] = self._file_redirect_stdio(1)
|
||||
|
||||
if _stderr is not None:
|
||||
if _stderr == subprocess_PIPE:
|
||||
r, w = self._file_outpipe()
|
||||
io[2] = w
|
||||
|
||||
self.stderr_proto = ReadSubprocessPipeProto(self, 2)
|
||||
waiter = self._loop._new_future()
|
||||
self._stderr = ReadUnixTransport.new(
|
||||
self._loop, self.stderr_proto, None, waiter)
|
||||
self._init_futs.append(waiter)
|
||||
self._stderr._open(r)
|
||||
self._stderr._init_protocol()
|
||||
elif _stderr == subprocess_STDOUT:
|
||||
if io[1] is None:
|
||||
# shouldn't ever happen
|
||||
raise RuntimeError('cannot apply subprocess.STDOUT')
|
||||
|
||||
io[2] = self._file_redirect_stdio(io[1])
|
||||
elif _stderr == subprocess_DEVNULL:
|
||||
io[2] = self._file_devnull()
|
||||
else:
|
||||
io[2] = self._file_redirect_stdio(_stderr)
|
||||
else:
|
||||
io[2] = self._file_redirect_stdio(2)
|
||||
|
||||
assert len(io) == 3
|
||||
for idx in range(3):
|
||||
iocnt = &self.iocnt[idx]
|
||||
if io[idx] is not None:
|
||||
iocnt.flags = uv.UV_INHERIT_FD
|
||||
iocnt.data.fd = io[idx]
|
||||
else:
|
||||
iocnt.flags = uv.UV_IGNORE
|
||||
|
||||
cdef _call_connection_made(self, waiter):
|
||||
try:
|
||||
# we're always called in the right context, so just call the user's
|
||||
self._protocol.connection_made(self)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
if waiter is not None and not waiter.cancelled():
|
||||
waiter.set_exception(ex)
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
if waiter is not None and not waiter.cancelled():
|
||||
waiter.set_result(True)
|
||||
|
||||
self._stdio_ready = 1
|
||||
if self._pending_calls:
|
||||
pending_calls = self._pending_calls.copy()
|
||||
self._pending_calls.clear()
|
||||
for (type, fd, arg) in pending_calls:
|
||||
if type == _CALL_PIPE_CONNECTION_LOST:
|
||||
self._pipe_connection_lost(fd, arg)
|
||||
elif type == _CALL_PIPE_DATA_RECEIVED:
|
||||
self._pipe_data_received(fd, arg)
|
||||
elif type == _CALL_PROCESS_EXITED:
|
||||
self._loop.call_soon(self._protocol.process_exited)
|
||||
elif type == _CALL_CONNECTION_LOST:
|
||||
self._loop.call_soon(self._protocol.connection_lost, None)
|
||||
|
||||
cdef _try_finish(self):
|
||||
if self._returncode is None or self._finished:
|
||||
return
|
||||
|
||||
if ((self.stdin_proto is None or self.stdin_proto.disconnected) and
|
||||
(self.stdout_proto is None or
|
||||
self.stdout_proto.disconnected) and
|
||||
(self.stderr_proto is None or
|
||||
self.stderr_proto.disconnected)):
|
||||
|
||||
self._finished = 1
|
||||
|
||||
if self._stdio_ready:
|
||||
# copy self.context for simplicity
|
||||
self._loop.call_soon(self._protocol.connection_lost, None,
|
||||
context=self.context)
|
||||
else:
|
||||
self._pending_calls.append((_CALL_CONNECTION_LOST, None, None))
|
||||
|
||||
def __stdio_inited(self, waiter, stdio_fut):
|
||||
exc = stdio_fut.exception()
|
||||
if exc is not None:
|
||||
if waiter is None:
|
||||
raise exc
|
||||
else:
|
||||
waiter.set_exception(exc)
|
||||
else:
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle1(self._loop,
|
||||
"UVProcessTransport._call_connection_made",
|
||||
<method1_t>self._call_connection_made,
|
||||
None, # means to copy the current context
|
||||
self, waiter))
|
||||
|
||||
@staticmethod
|
||||
cdef UVProcessTransport new(Loop loop, protocol, args, env,
|
||||
cwd, start_new_session,
|
||||
_stdin, _stdout, _stderr, pass_fds,
|
||||
waiter,
|
||||
debug_flags,
|
||||
preexec_fn,
|
||||
restore_signals):
|
||||
|
||||
cdef UVProcessTransport handle
|
||||
handle = UVProcessTransport.__new__(UVProcessTransport)
|
||||
handle._protocol = protocol
|
||||
handle._init(loop, args, env, cwd, start_new_session,
|
||||
__process_convert_fileno(_stdin),
|
||||
__process_convert_fileno(_stdout),
|
||||
__process_convert_fileno(_stderr),
|
||||
pass_fds,
|
||||
debug_flags,
|
||||
preexec_fn,
|
||||
restore_signals)
|
||||
|
||||
if handle._init_futs:
|
||||
handle._stdio_ready = 0
|
||||
init_fut = aio_gather(*handle._init_futs)
|
||||
# add_done_callback will copy the current context and run the
|
||||
# callback within the context
|
||||
init_fut.add_done_callback(
|
||||
ft_partial(handle.__stdio_inited, waiter))
|
||||
else:
|
||||
handle._stdio_ready = 1
|
||||
loop._call_soon_handle(
|
||||
new_MethodHandle1(loop,
|
||||
"UVProcessTransport._call_connection_made",
|
||||
<method1_t>handle._call_connection_made,
|
||||
None, # means to copy the current context
|
||||
handle, waiter))
|
||||
|
||||
return handle
|
||||
|
||||
def get_protocol(self):
|
||||
return self._protocol
|
||||
|
||||
def set_protocol(self, protocol):
|
||||
self._protocol = protocol
|
||||
|
||||
def get_pid(self):
|
||||
return self._pid
|
||||
|
||||
def get_returncode(self):
|
||||
return self._returncode
|
||||
|
||||
def get_pipe_transport(self, fd):
|
||||
if fd == 0:
|
||||
return self._stdin
|
||||
elif fd == 1:
|
||||
return self._stdout
|
||||
elif fd == 2:
|
||||
return self._stderr
|
||||
|
||||
def terminate(self):
|
||||
self._check_proc()
|
||||
self._kill(uv.SIGTERM)
|
||||
|
||||
def kill(self):
|
||||
self._check_proc()
|
||||
self._kill(uv.SIGKILL)
|
||||
|
||||
def send_signal(self, int signal):
|
||||
self._check_proc()
|
||||
self._kill(signal)
|
||||
|
||||
def is_closing(self):
|
||||
return self._closed
|
||||
|
||||
def close(self):
|
||||
if self._returncode is None:
|
||||
self._kill(uv.SIGKILL)
|
||||
|
||||
if self._stdin is not None:
|
||||
self._stdin.close()
|
||||
if self._stdout is not None:
|
||||
self._stdout.close()
|
||||
if self._stderr is not None:
|
||||
self._stderr.close()
|
||||
|
||||
if self._returncode is not None:
|
||||
# The process is dead, just close the UV handle.
|
||||
#
|
||||
# (If "self._returncode is None", the process should have been
|
||||
# killed already and we're just waiting for a SIGCHLD; after
|
||||
# which the transport will be GC'ed and the uvhandle will be
|
||||
# closed in UVHandle.__dealloc__.)
|
||||
self._close()
|
||||
|
||||
def get_extra_info(self, name, default=None):
|
||||
return default
|
||||
|
||||
def _wait(self):
|
||||
fut = self._loop._new_future()
|
||||
if self._returncode is not None:
|
||||
fut.set_result(self._returncode)
|
||||
return fut
|
||||
|
||||
self._exit_waiters.append(fut)
|
||||
return fut
|
||||
|
||||
|
||||
class WriteSubprocessPipeProto(aio_BaseProtocol):
|
||||
|
||||
def __init__(self, proc, fd):
|
||||
if UVLOOP_DEBUG:
|
||||
if type(proc) is not UVProcessTransport:
|
||||
raise TypeError
|
||||
if not isinstance(fd, int):
|
||||
raise TypeError
|
||||
self.proc = proc
|
||||
self.fd = fd
|
||||
self.pipe = None
|
||||
self.disconnected = False
|
||||
|
||||
def connection_made(self, transport):
|
||||
self.pipe = transport
|
||||
|
||||
def __repr__(self):
|
||||
return ('<%s fd=%s pipe=%r>'
|
||||
% (self.__class__.__name__, self.fd, self.pipe))
|
||||
|
||||
def connection_lost(self, exc):
|
||||
self.disconnected = True
|
||||
(<UVProcessTransport>self.proc)._pipe_connection_lost(self.fd, exc)
|
||||
self.proc = None
|
||||
|
||||
def pause_writing(self):
|
||||
(<UVProcessTransport>self.proc)._protocol.pause_writing()
|
||||
|
||||
def resume_writing(self):
|
||||
(<UVProcessTransport>self.proc)._protocol.resume_writing()
|
||||
|
||||
|
||||
class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
|
||||
aio_Protocol):
|
||||
|
||||
def data_received(self, data):
|
||||
(<UVProcessTransport>self.proc)._pipe_data_received(self.fd, data)
|
||||
|
||||
|
||||
cdef __process_convert_fileno(object obj):
|
||||
if obj is None or isinstance(obj, int):
|
||||
return obj
|
||||
|
||||
fileno = obj.fileno()
|
||||
if not isinstance(fileno, int):
|
||||
raise TypeError(
|
||||
'{!r}.fileno() returned non-integer'.format(obj))
|
||||
return fileno
|
||||
|
||||
|
||||
cdef void __uvprocess_on_exit_callback(
|
||||
uv.uv_process_t *handle,
|
||||
int64_t exit_status,
|
||||
int term_signal,
|
||||
) noexcept with gil:
|
||||
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle,
|
||||
"UVProcess exit callback") == 0:
|
||||
return
|
||||
|
||||
cdef UVProcess proc = <UVProcess> handle.data
|
||||
try:
|
||||
proc._on_exit(exit_status, term_signal)
|
||||
except BaseException as ex:
|
||||
proc._error(ex, False)
|
||||
|
||||
|
||||
cdef __socketpair():
|
||||
cdef:
|
||||
int fds[2]
|
||||
int err
|
||||
|
||||
err = system.socketpair(uv.AF_UNIX, uv.SOCK_STREAM, 0, fds)
|
||||
if err:
|
||||
exc = convert_error(-err)
|
||||
raise exc
|
||||
|
||||
os_set_inheritable(fds[0], False)
|
||||
os_set_inheritable(fds[1], False)
|
||||
|
||||
return fds[0], fds[1]
|
||||
|
||||
|
||||
cdef void __uv_close_process_handle_cb(
|
||||
uv.uv_handle_t* handle
|
||||
) noexcept with gil:
|
||||
PyMem_RawFree(handle)
|
50
env/lib/python3.11/site-packages/uvloop/handles/stream.pxd
vendored
Normal file
50
env/lib/python3.11/site-packages/uvloop/handles/stream.pxd
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
cdef class UVStream(UVBaseTransport):
|
||||
cdef:
|
||||
uv.uv_shutdown_t _shutdown_req
|
||||
bint __shutting_down
|
||||
bint __reading
|
||||
bint __read_error_close
|
||||
|
||||
bint __buffered
|
||||
object _protocol_get_buffer
|
||||
object _protocol_buffer_updated
|
||||
|
||||
bint _eof
|
||||
list _buffer
|
||||
size_t _buffer_size
|
||||
|
||||
Py_buffer _read_pybuf
|
||||
bint _read_pybuf_acquired
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef inline _init(self, Loop loop, object protocol, Server server,
|
||||
object waiter, object context)
|
||||
|
||||
|
||||
cdef inline _shutdown(self)
|
||||
cdef inline _accept(self, UVStream server)
|
||||
|
||||
cdef inline _close_on_read_error(self)
|
||||
|
||||
cdef inline __reading_started(self)
|
||||
cdef inline __reading_stopped(self)
|
||||
|
||||
# The user API write() and writelines() firstly call _buffer_write() to
|
||||
# buffer up user data chunks, potentially multiple times in writelines(),
|
||||
# and then call _initiate_write() to start writing either immediately or in
|
||||
# the next iteration (loop._queue_write()).
|
||||
cdef inline _buffer_write(self, object data)
|
||||
cdef inline _initiate_write(self)
|
||||
|
||||
# _exec_write() is the method that does the actual send, and _try_write()
|
||||
# is a fast-path used in _exec_write() to send a single chunk.
|
||||
cdef inline _exec_write(self)
|
||||
cdef inline _try_write(self, object data)
|
||||
|
||||
cdef _close(self)
|
||||
|
||||
cdef inline _on_accept(self)
|
||||
cdef inline _on_eof(self)
|
||||
cdef inline _on_write(self)
|
||||
cdef inline _on_connect(self, object exc)
|
1019
env/lib/python3.11/site-packages/uvloop/handles/stream.pyx
vendored
Normal file
1019
env/lib/python3.11/site-packages/uvloop/handles/stream.pyx
vendored
Normal file
File diff suppressed because it is too large
Load Diff
26
env/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd
vendored
Normal file
26
env/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
cdef class UVStreamServer(UVSocketHandle):
|
||||
cdef:
|
||||
int backlog
|
||||
object ssl
|
||||
object ssl_handshake_timeout
|
||||
object ssl_shutdown_timeout
|
||||
object protocol_factory
|
||||
bint opened
|
||||
Server _server
|
||||
|
||||
# All "inline" methods are final
|
||||
|
||||
cdef inline _init(self, Loop loop, object protocol_factory,
|
||||
Server server,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout)
|
||||
|
||||
cdef inline _mark_as_open(self)
|
||||
|
||||
cdef inline listen(self)
|
||||
cdef inline _on_listen(self)
|
||||
|
||||
cdef UVStream _make_new_transport(self, object protocol, object waiter,
|
||||
object context)
|
150
env/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx
vendored
Normal file
150
env/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVStreamServer(UVSocketHandle):
|
||||
|
||||
def __cinit__(self):
|
||||
self.opened = 0
|
||||
self._server = None
|
||||
self.ssl = None
|
||||
self.ssl_handshake_timeout = None
|
||||
self.ssl_shutdown_timeout = None
|
||||
self.protocol_factory = None
|
||||
|
||||
cdef inline _init(self, Loop loop, object protocol_factory,
|
||||
Server server,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout):
|
||||
|
||||
if not isinstance(backlog, int):
|
||||
# Don't allow floats
|
||||
raise TypeError('integer argument expected, got {}'.format(
|
||||
type(backlog).__name__))
|
||||
|
||||
if ssl is not None:
|
||||
if not isinstance(ssl, ssl_SSLContext):
|
||||
raise TypeError(
|
||||
'ssl is expected to be None or an instance of '
|
||||
'ssl.SSLContext, got {!r}'.format(ssl))
|
||||
else:
|
||||
if ssl_handshake_timeout is not None:
|
||||
raise ValueError(
|
||||
'ssl_handshake_timeout is only meaningful with ssl')
|
||||
if ssl_shutdown_timeout is not None:
|
||||
raise ValueError(
|
||||
'ssl_shutdown_timeout is only meaningful with ssl')
|
||||
|
||||
self.backlog = backlog
|
||||
self.ssl = ssl
|
||||
self.ssl_handshake_timeout = ssl_handshake_timeout
|
||||
self.ssl_shutdown_timeout = ssl_shutdown_timeout
|
||||
|
||||
self._start_init(loop)
|
||||
self.protocol_factory = protocol_factory
|
||||
self._server = server
|
||||
|
||||
cdef inline listen(self):
|
||||
cdef int err
|
||||
self._ensure_alive()
|
||||
|
||||
if self.protocol_factory is None:
|
||||
raise RuntimeError('unable to listen(); no protocol_factory')
|
||||
|
||||
if self.opened != 1:
|
||||
raise RuntimeError('unopened TCPServer')
|
||||
|
||||
self.context = Context_CopyCurrent()
|
||||
|
||||
err = uv.uv_listen(<uv.uv_stream_t*> self._handle,
|
||||
self.backlog,
|
||||
__uv_streamserver_on_listen)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef inline _on_listen(self):
|
||||
cdef UVStream client
|
||||
|
||||
protocol = run_in_context(self.context, self.protocol_factory)
|
||||
|
||||
if self.ssl is None:
|
||||
client = self._make_new_transport(protocol, None, self.context)
|
||||
|
||||
else:
|
||||
waiter = self._loop._new_future()
|
||||
|
||||
ssl_protocol = SSLProtocol(
|
||||
self._loop, protocol, self.ssl,
|
||||
waiter,
|
||||
server_side=True,
|
||||
server_hostname=None,
|
||||
ssl_handshake_timeout=self.ssl_handshake_timeout,
|
||||
ssl_shutdown_timeout=self.ssl_shutdown_timeout)
|
||||
|
||||
client = self._make_new_transport(ssl_protocol, None, self.context)
|
||||
|
||||
waiter.add_done_callback(
|
||||
ft_partial(self.__on_ssl_connected, client))
|
||||
|
||||
client._accept(<UVStream>self)
|
||||
|
||||
cdef _fatal_error(self, exc, throw, reason=None):
|
||||
# Overload UVHandle._fatal_error
|
||||
|
||||
self._close()
|
||||
|
||||
if not isinstance(exc, OSError):
|
||||
|
||||
if throw or self._loop is None:
|
||||
raise exc
|
||||
|
||||
msg = f'Fatal error on server {self.__class__.__name__}'
|
||||
if reason is not None:
|
||||
msg = f'{msg} ({reason})'
|
||||
|
||||
self._loop.call_exception_handler({
|
||||
'message': msg,
|
||||
'exception': exc,
|
||||
})
|
||||
|
||||
cdef inline _mark_as_open(self):
|
||||
self.opened = 1
|
||||
|
||||
cdef UVStream _make_new_transport(self, object protocol, object waiter,
|
||||
object context):
|
||||
raise NotImplementedError
|
||||
|
||||
def __on_ssl_connected(self, transport, fut):
|
||||
exc = fut.exception()
|
||||
if exc is not None:
|
||||
transport._force_close(exc)
|
||||
|
||||
|
||||
cdef void __uv_streamserver_on_listen(
|
||||
uv.uv_stream_t* handle,
|
||||
int status,
|
||||
) noexcept with gil:
|
||||
|
||||
# callback for uv_listen
|
||||
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle,
|
||||
"UVStream listen callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVStreamServer stream = <UVStreamServer> handle.data
|
||||
|
||||
if status < 0:
|
||||
if UVLOOP_DEBUG:
|
||||
stream._loop._debug_stream_listen_errors_total += 1
|
||||
|
||||
exc = convert_error(status)
|
||||
stream._fatal_error(
|
||||
exc, False, "error status in uv_stream_t.listen callback")
|
||||
return
|
||||
|
||||
try:
|
||||
stream._on_listen()
|
||||
except BaseException as exc:
|
||||
stream._error(exc, False)
|
26
env/lib/python3.11/site-packages/uvloop/handles/tcp.pxd
vendored
Normal file
26
env/lib/python3.11/site-packages/uvloop/handles/tcp.pxd
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
cdef class TCPServer(UVStreamServer):
|
||||
cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
|
||||
|
||||
@staticmethod
|
||||
cdef TCPServer new(Loop loop, object protocol_factory, Server server,
|
||||
unsigned int flags,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout)
|
||||
|
||||
|
||||
cdef class TCPTransport(UVStream):
|
||||
cdef:
|
||||
bint __peername_set
|
||||
bint __sockname_set
|
||||
system.sockaddr_storage __peername
|
||||
system.sockaddr_storage __sockname
|
||||
|
||||
cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
|
||||
cdef connect(self, system.sockaddr* addr)
|
||||
cdef _set_nodelay(self)
|
||||
|
||||
@staticmethod
|
||||
cdef TCPTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter, object context)
|
228
env/lib/python3.11/site-packages/uvloop/handles/tcp.pyx
vendored
Normal file
228
env/lib/python3.11/site-packages/uvloop/handles/tcp.pyx
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
cdef __tcp_init_uv_handle(UVStream handle, Loop loop, unsigned int flags):
|
||||
cdef int err
|
||||
|
||||
handle._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_tcp_t))
|
||||
if handle._handle is NULL:
|
||||
handle._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_tcp_init_ex(handle._loop.uvloop,
|
||||
<uv.uv_tcp_t*>handle._handle,
|
||||
flags)
|
||||
if err < 0:
|
||||
handle._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
handle._finish_init()
|
||||
|
||||
|
||||
cdef __tcp_bind(UVStream handle, system.sockaddr* addr, unsigned int flags):
|
||||
cdef int err
|
||||
err = uv.uv_tcp_bind(<uv.uv_tcp_t *>handle._handle,
|
||||
addr, flags)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
|
||||
cdef __tcp_open(UVStream handle, int sockfd):
|
||||
cdef int err
|
||||
err = uv.uv_tcp_open(<uv.uv_tcp_t *>handle._handle,
|
||||
<uv.uv_os_sock_t>sockfd)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
|
||||
cdef __tcp_get_socket(UVSocketHandle handle):
|
||||
cdef:
|
||||
int buf_len = sizeof(system.sockaddr_storage)
|
||||
int fileno
|
||||
int err
|
||||
system.sockaddr_storage buf
|
||||
|
||||
fileno = handle._fileno()
|
||||
|
||||
err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>handle._handle,
|
||||
<system.sockaddr*>&buf,
|
||||
&buf_len)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
return PseudoSocket(buf.ss_family, uv.SOCK_STREAM, 0, fileno)
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class TCPServer(UVStreamServer):
|
||||
|
||||
@staticmethod
|
||||
cdef TCPServer new(Loop loop, object protocol_factory, Server server,
|
||||
unsigned int flags,
|
||||
object backlog,
|
||||
object ssl,
|
||||
object ssl_handshake_timeout,
|
||||
object ssl_shutdown_timeout):
|
||||
|
||||
cdef TCPServer handle
|
||||
handle = TCPServer.__new__(TCPServer)
|
||||
handle._init(loop, protocol_factory, server, backlog,
|
||||
ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
|
||||
__tcp_init_uv_handle(<UVStream>handle, loop, flags)
|
||||
return handle
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __tcp_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
self._ensure_alive()
|
||||
try:
|
||||
__tcp_open(<UVStream>self, sockfd)
|
||||
except Exception as exc:
|
||||
self._fatal_error(exc, True)
|
||||
else:
|
||||
self._mark_as_open()
|
||||
|
||||
cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
|
||||
self._ensure_alive()
|
||||
try:
|
||||
__tcp_bind(<UVStream>self, addr, flags)
|
||||
except Exception as exc:
|
||||
self._fatal_error(exc, True)
|
||||
else:
|
||||
self._mark_as_open()
|
||||
|
||||
cdef UVStream _make_new_transport(self, object protocol, object waiter,
|
||||
object context):
|
||||
cdef TCPTransport tr
|
||||
tr = TCPTransport.new(self._loop, protocol, self._server, waiter,
|
||||
context)
|
||||
return <UVStream>tr
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class TCPTransport(UVStream):
|
||||
|
||||
@staticmethod
|
||||
cdef TCPTransport new(Loop loop, object protocol, Server server,
|
||||
object waiter, object context):
|
||||
|
||||
cdef TCPTransport handle
|
||||
handle = TCPTransport.__new__(TCPTransport)
|
||||
handle._init(loop, protocol, server, waiter, context)
|
||||
__tcp_init_uv_handle(<UVStream>handle, loop, uv.AF_UNSPEC)
|
||||
handle.__peername_set = 0
|
||||
handle.__sockname_set = 0
|
||||
handle._set_nodelay()
|
||||
return handle
|
||||
|
||||
cdef _set_nodelay(self):
|
||||
cdef int err
|
||||
self._ensure_alive()
|
||||
err = uv.uv_tcp_nodelay(<uv.uv_tcp_t*>self._handle, 1)
|
||||
if err < 0:
|
||||
raise convert_error(err)
|
||||
|
||||
cdef _call_connection_made(self):
|
||||
# asyncio saves peername & sockname when transports are instantiated,
|
||||
# so that they're accessible even after the transport is closed.
|
||||
# We are doing the same thing here, except that we create Python
|
||||
# objects lazily, on request in get_extra_info()
|
||||
|
||||
cdef:
|
||||
int err
|
||||
int buf_len
|
||||
|
||||
buf_len = sizeof(system.sockaddr_storage)
|
||||
err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>self._handle,
|
||||
<system.sockaddr*>&self.__sockname,
|
||||
&buf_len)
|
||||
if err >= 0:
|
||||
# Ignore errors, this is an optional thing.
|
||||
# If something serious is going on, the transport
|
||||
# will crash later (in roughly the same way how
|
||||
# an asyncio transport would.)
|
||||
self.__sockname_set = 1
|
||||
|
||||
buf_len = sizeof(system.sockaddr_storage)
|
||||
err = uv.uv_tcp_getpeername(<uv.uv_tcp_t*>self._handle,
|
||||
<system.sockaddr*>&self.__peername,
|
||||
&buf_len)
|
||||
if err >= 0:
|
||||
# Same as few lines above -- we don't really care
|
||||
# about error case here.
|
||||
self.__peername_set = 1
|
||||
|
||||
UVBaseTransport._call_connection_made(self)
|
||||
|
||||
def get_extra_info(self, name, default=None):
|
||||
if name == 'sockname':
|
||||
if self.__sockname_set:
|
||||
return __convert_sockaddr_to_pyaddr(
|
||||
<system.sockaddr*>&self.__sockname)
|
||||
elif name == 'peername':
|
||||
if self.__peername_set:
|
||||
return __convert_sockaddr_to_pyaddr(
|
||||
<system.sockaddr*>&self.__peername)
|
||||
return super().get_extra_info(name, default)
|
||||
|
||||
cdef _new_socket(self):
|
||||
return __tcp_get_socket(<UVSocketHandle>self)
|
||||
|
||||
cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
|
||||
self._ensure_alive()
|
||||
__tcp_bind(<UVStream>self, addr, flags)
|
||||
|
||||
cdef _open(self, int sockfd):
|
||||
self._ensure_alive()
|
||||
__tcp_open(<UVStream>self, sockfd)
|
||||
|
||||
cdef connect(self, system.sockaddr* addr):
|
||||
cdef _TCPConnectRequest req
|
||||
req = _TCPConnectRequest(self._loop, self)
|
||||
req.connect(addr)
|
||||
|
||||
|
||||
cdef class _TCPConnectRequest(UVRequest):
|
||||
cdef:
|
||||
TCPTransport transport
|
||||
uv.uv_connect_t _req_data
|
||||
|
||||
def __cinit__(self, loop, transport):
|
||||
self.request = <uv.uv_req_t*>&self._req_data
|
||||
self.request.data = <void*>self
|
||||
self.transport = transport
|
||||
|
||||
cdef connect(self, system.sockaddr* addr):
|
||||
cdef int err
|
||||
err = uv.uv_tcp_connect(<uv.uv_connect_t*>self.request,
|
||||
<uv.uv_tcp_t*>self.transport._handle,
|
||||
addr,
|
||||
__tcp_connect_callback)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self.on_done()
|
||||
raise exc
|
||||
|
||||
|
||||
cdef void __tcp_connect_callback(
|
||||
uv.uv_connect_t* req,
|
||||
int status,
|
||||
) noexcept with gil:
|
||||
cdef:
|
||||
_TCPConnectRequest wrapper
|
||||
TCPTransport transport
|
||||
|
||||
wrapper = <_TCPConnectRequest> req.data
|
||||
transport = wrapper.transport
|
||||
|
||||
if status < 0:
|
||||
exc = convert_error(status)
|
||||
else:
|
||||
exc = None
|
||||
|
||||
try:
|
||||
transport._on_connect(exc)
|
||||
except BaseException as ex:
|
||||
wrapper.transport._fatal_error(ex, False)
|
||||
finally:
|
||||
wrapper.on_done()
|
18
env/lib/python3.11/site-packages/uvloop/handles/timer.pxd
vendored
Normal file
18
env/lib/python3.11/site-packages/uvloop/handles/timer.pxd
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
cdef class UVTimer(UVHandle):
|
||||
cdef:
|
||||
method_t callback
|
||||
object ctx
|
||||
bint running
|
||||
uint64_t timeout
|
||||
uint64_t start_t
|
||||
|
||||
cdef _init(self, Loop loop, method_t callback, object ctx,
|
||||
uint64_t timeout)
|
||||
|
||||
cdef stop(self)
|
||||
cdef start(self)
|
||||
cdef get_when(self)
|
||||
|
||||
@staticmethod
|
||||
cdef UVTimer new(Loop loop, method_t callback, object ctx,
|
||||
uint64_t timeout)
|
89
env/lib/python3.11/site-packages/uvloop/handles/timer.pyx
vendored
Normal file
89
env/lib/python3.11/site-packages/uvloop/handles/timer.pyx
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
@cython.no_gc_clear
|
||||
cdef class UVTimer(UVHandle):
|
||||
cdef _init(self, Loop loop, method_t callback, object ctx,
|
||||
uint64_t timeout):
|
||||
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*> PyMem_RawMalloc(sizeof(uv.uv_timer_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_timer_init(self._loop.uvloop, <uv.uv_timer_t*>self._handle)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
self._finish_init()
|
||||
|
||||
self.callback = callback
|
||||
self.ctx = ctx
|
||||
self.running = 0
|
||||
self.timeout = timeout
|
||||
self.start_t = 0
|
||||
|
||||
cdef stop(self):
|
||||
cdef int err
|
||||
|
||||
if not self._is_alive():
|
||||
self.running = 0
|
||||
return
|
||||
|
||||
if self.running == 1:
|
||||
err = uv.uv_timer_stop(<uv.uv_timer_t*>self._handle)
|
||||
self.running = 0
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
|
||||
cdef start(self):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
if self.running == 0:
|
||||
# Update libuv internal time.
|
||||
uv.uv_update_time(self._loop.uvloop) # void
|
||||
self.start_t = uv.uv_now(self._loop.uvloop)
|
||||
|
||||
err = uv.uv_timer_start(<uv.uv_timer_t*>self._handle,
|
||||
__uvtimer_callback,
|
||||
self.timeout, 0)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
self.running = 1
|
||||
|
||||
cdef get_when(self):
|
||||
return self.start_t + self.timeout
|
||||
|
||||
@staticmethod
|
||||
cdef UVTimer new(Loop loop, method_t callback, object ctx,
|
||||
uint64_t timeout):
|
||||
|
||||
cdef UVTimer handle
|
||||
handle = UVTimer.__new__(UVTimer)
|
||||
handle._init(loop, callback, ctx, timeout)
|
||||
return handle
|
||||
|
||||
|
||||
cdef void __uvtimer_callback(
|
||||
uv.uv_timer_t* handle,
|
||||
) noexcept with gil:
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVTimer callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UVTimer timer = <UVTimer> handle.data
|
||||
method_t cb = timer.callback
|
||||
|
||||
timer.running = 0
|
||||
try:
|
||||
cb(timer.ctx)
|
||||
except BaseException as ex:
|
||||
timer._error(ex, False)
|
22
env/lib/python3.11/site-packages/uvloop/handles/udp.pxd
vendored
Normal file
22
env/lib/python3.11/site-packages/uvloop/handles/udp.pxd
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
cdef class UDPTransport(UVBaseTransport):
|
||||
cdef:
|
||||
bint __receiving
|
||||
int _family
|
||||
object _address
|
||||
|
||||
cdef _init(self, Loop loop, unsigned int family)
|
||||
cdef _set_address(self, system.addrinfo *addr)
|
||||
|
||||
cdef _connect(self, system.sockaddr* addr, size_t addr_len)
|
||||
|
||||
cdef _bind(self, system.sockaddr* addr)
|
||||
cdef open(self, int family, int sockfd)
|
||||
cdef _set_broadcast(self, bint on)
|
||||
|
||||
cdef inline __receiving_started(self)
|
||||
cdef inline __receiving_stopped(self)
|
||||
|
||||
cdef _send(self, object data, object addr)
|
||||
|
||||
cdef _on_receive(self, bytes data, object exc, object addr)
|
||||
cdef _on_sent(self, object exc, object context=*)
|
408
env/lib/python3.11/site-packages/uvloop/handles/udp.pyx
vendored
Normal file
408
env/lib/python3.11/site-packages/uvloop/handles/udp.pyx
vendored
Normal file
@ -0,0 +1,408 @@
|
||||
@cython.no_gc_clear
|
||||
@cython.freelist(DEFAULT_FREELIST_SIZE)
|
||||
cdef class _UDPSendContext:
|
||||
# used to hold additional write request information for uv_write
|
||||
|
||||
cdef:
|
||||
uv.uv_udp_send_t req
|
||||
|
||||
uv.uv_buf_t uv_buf
|
||||
Py_buffer py_buf
|
||||
|
||||
UDPTransport udp
|
||||
|
||||
bint closed
|
||||
|
||||
cdef close(self):
|
||||
if self.closed:
|
||||
return
|
||||
|
||||
self.closed = 1
|
||||
PyBuffer_Release(&self.py_buf) # void
|
||||
self.req.data = NULL
|
||||
self.uv_buf.base = NULL
|
||||
Py_DECREF(self)
|
||||
self.udp = None
|
||||
|
||||
@staticmethod
|
||||
cdef _UDPSendContext new(UDPTransport udp, object data):
|
||||
cdef _UDPSendContext ctx
|
||||
ctx = _UDPSendContext.__new__(_UDPSendContext)
|
||||
ctx.udp = None
|
||||
ctx.closed = 1
|
||||
|
||||
ctx.req.data = <void*> ctx
|
||||
Py_INCREF(ctx)
|
||||
|
||||
PyObject_GetBuffer(data, &ctx.py_buf, PyBUF_SIMPLE)
|
||||
ctx.uv_buf.base = <char*>ctx.py_buf.buf
|
||||
ctx.uv_buf.len = ctx.py_buf.len
|
||||
ctx.udp = udp
|
||||
|
||||
ctx.closed = 0
|
||||
return ctx
|
||||
|
||||
def __dealloc__(self):
|
||||
if UVLOOP_DEBUG:
|
||||
if not self.closed:
|
||||
raise RuntimeError(
|
||||
'open _UDPSendContext is being deallocated')
|
||||
self.udp = None
|
||||
|
||||
|
||||
@cython.no_gc_clear
|
||||
cdef class UDPTransport(UVBaseTransport):
|
||||
def __cinit__(self):
|
||||
self._family = uv.AF_UNSPEC
|
||||
self.__receiving = 0
|
||||
self._address = None
|
||||
self.context = Context_CopyCurrent()
|
||||
|
||||
cdef _init(self, Loop loop, unsigned int family):
|
||||
cdef int err
|
||||
|
||||
self._start_init(loop)
|
||||
|
||||
self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_udp_t))
|
||||
if self._handle is NULL:
|
||||
self._abort_init()
|
||||
raise MemoryError()
|
||||
|
||||
err = uv.uv_udp_init_ex(loop.uvloop,
|
||||
<uv.uv_udp_t*>self._handle,
|
||||
family)
|
||||
if err < 0:
|
||||
self._abort_init()
|
||||
raise convert_error(err)
|
||||
|
||||
if family in (uv.AF_INET, uv.AF_INET6):
|
||||
self._family = family
|
||||
|
||||
self._finish_init()
|
||||
|
||||
cdef _set_address(self, system.addrinfo *addr):
|
||||
self._address = __convert_sockaddr_to_pyaddr(addr.ai_addr)
|
||||
|
||||
cdef _connect(self, system.sockaddr* addr, size_t addr_len):
|
||||
cdef int err
|
||||
err = uv.uv_udp_connect(<uv.uv_udp_t*>self._handle, addr)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
cdef open(self, int family, int sockfd):
|
||||
if family in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
|
||||
self._family = family
|
||||
else:
|
||||
raise ValueError(
|
||||
'cannot open a UDP handle, invalid family {}'.format(family))
|
||||
|
||||
cdef int err
|
||||
err = uv.uv_udp_open(<uv.uv_udp_t*>self._handle,
|
||||
<uv.uv_os_sock_t>sockfd)
|
||||
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
cdef _bind(self, system.sockaddr* addr):
|
||||
cdef:
|
||||
int err
|
||||
int flags = 0
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_udp_bind(<uv.uv_udp_t*>self._handle, addr, flags)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
cdef _set_broadcast(self, bint on):
|
||||
cdef int err
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_udp_set_broadcast(<uv.uv_udp_t*>self._handle, on)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
raise exc
|
||||
|
||||
cdef size_t _get_write_buffer_size(self):
|
||||
if self._handle is NULL:
|
||||
return 0
|
||||
return (<uv.uv_udp_t*>self._handle).send_queue_size
|
||||
|
||||
cdef bint _is_reading(self):
|
||||
return self.__receiving
|
||||
|
||||
cdef _start_reading(self):
|
||||
cdef int err
|
||||
|
||||
if self.__receiving:
|
||||
return
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_udp_recv_start(<uv.uv_udp_t*>self._handle,
|
||||
__loop_alloc_buffer,
|
||||
__uv_udp_on_receive)
|
||||
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
else:
|
||||
# UDPTransport must live until the read callback is called
|
||||
self.__receiving_started()
|
||||
|
||||
cdef _stop_reading(self):
|
||||
cdef int err
|
||||
|
||||
if not self.__receiving:
|
||||
return
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
err = uv.uv_udp_recv_stop(<uv.uv_udp_t*>self._handle)
|
||||
if err < 0:
|
||||
exc = convert_error(err)
|
||||
self._fatal_error(exc, True)
|
||||
return
|
||||
else:
|
||||
self.__receiving_stopped()
|
||||
|
||||
cdef inline __receiving_started(self):
|
||||
if self.__receiving:
|
||||
return
|
||||
self.__receiving = 1
|
||||
Py_INCREF(self)
|
||||
|
||||
cdef inline __receiving_stopped(self):
|
||||
if not self.__receiving:
|
||||
return
|
||||
self.__receiving = 0
|
||||
Py_DECREF(self)
|
||||
|
||||
cdef _new_socket(self):
|
||||
if self._family not in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
|
||||
raise RuntimeError(
|
||||
'UDPTransport.family is undefined; '
|
||||
'cannot create python socket')
|
||||
|
||||
fileno = self._fileno()
|
||||
return PseudoSocket(self._family, uv.SOCK_DGRAM, 0, fileno)
|
||||
|
||||
cdef _send(self, object data, object addr):
|
||||
cdef:
|
||||
_UDPSendContext ctx
|
||||
system.sockaddr_storage saddr_st
|
||||
system.sockaddr *saddr
|
||||
Py_buffer try_pybuf
|
||||
uv.uv_buf_t try_uvbuf
|
||||
|
||||
self._ensure_alive()
|
||||
|
||||
if self._family not in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
|
||||
raise RuntimeError('UDPTransport.family is undefined; cannot send')
|
||||
|
||||
if addr is None:
|
||||
saddr = NULL
|
||||
else:
|
||||
try:
|
||||
__convert_pyaddr_to_sockaddr(self._family, addr,
|
||||
<system.sockaddr*>&saddr_st)
|
||||
except (ValueError, TypeError):
|
||||
raise
|
||||
except Exception:
|
||||
raise ValueError(
|
||||
f'{addr!r}: socket family mismatch or '
|
||||
f'a DNS lookup is required')
|
||||
saddr = <system.sockaddr*>(&saddr_st)
|
||||
|
||||
if self._get_write_buffer_size() == 0:
|
||||
PyObject_GetBuffer(data, &try_pybuf, PyBUF_SIMPLE)
|
||||
try_uvbuf.base = <char*>try_pybuf.buf
|
||||
try_uvbuf.len = try_pybuf.len
|
||||
err = uv.uv_udp_try_send(<uv.uv_udp_t*>self._handle,
|
||||
&try_uvbuf,
|
||||
1,
|
||||
saddr)
|
||||
PyBuffer_Release(&try_pybuf)
|
||||
else:
|
||||
err = uv.UV_EAGAIN
|
||||
|
||||
if err == uv.UV_EAGAIN:
|
||||
ctx = _UDPSendContext.new(self, data)
|
||||
err = uv.uv_udp_send(&ctx.req,
|
||||
<uv.uv_udp_t*>self._handle,
|
||||
&ctx.uv_buf,
|
||||
1,
|
||||
saddr,
|
||||
__uv_udp_on_send)
|
||||
|
||||
if err < 0:
|
||||
ctx.close()
|
||||
|
||||
exc = convert_error(err)
|
||||
if isinstance(exc, OSError):
|
||||
run_in_context1(self.context.copy(), self._protocol.error_received, exc)
|
||||
else:
|
||||
self._fatal_error(exc, True)
|
||||
else:
|
||||
self._maybe_pause_protocol()
|
||||
|
||||
else:
|
||||
self._on_sent(convert_error(err) if err < 0 else None, self.context.copy())
|
||||
|
||||
cdef _on_receive(self, bytes data, object exc, object addr):
|
||||
if exc is None:
|
||||
run_in_context2(
|
||||
self.context, self._protocol.datagram_received, data, addr,
|
||||
)
|
||||
else:
|
||||
run_in_context1(self.context, self._protocol.error_received, exc)
|
||||
|
||||
cdef _on_sent(self, object exc, object context=None):
|
||||
if exc is not None:
|
||||
if isinstance(exc, OSError):
|
||||
if context is None:
|
||||
context = self.context
|
||||
run_in_context1(context, self._protocol.error_received, exc)
|
||||
else:
|
||||
self._fatal_error(
|
||||
exc, False, 'Fatal write error on datagram transport')
|
||||
|
||||
self._maybe_resume_protocol()
|
||||
if not self._get_write_buffer_size():
|
||||
if self._closing:
|
||||
self._schedule_call_connection_lost(None)
|
||||
|
||||
# === Public API ===
|
||||
|
||||
def sendto(self, data, addr=None):
|
||||
if not data:
|
||||
# Replicating asyncio logic here.
|
||||
return
|
||||
|
||||
if self._address:
|
||||
if addr not in (None, self._address):
|
||||
# Replicating asyncio logic here.
|
||||
raise ValueError(
|
||||
'Invalid address: must be None or %s' % (self._address,))
|
||||
|
||||
# Instead of setting addr to self._address below like what asyncio
|
||||
# does, we depend on previous uv_udp_connect() to set the address
|
||||
addr = None
|
||||
|
||||
if self._conn_lost:
|
||||
# Replicating asyncio logic here.
|
||||
if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
|
||||
aio_logger.warning('socket.send() raised exception.')
|
||||
self._conn_lost += 1
|
||||
return
|
||||
|
||||
self._send(data, addr)
|
||||
|
||||
|
||||
cdef void __uv_udp_on_receive(
|
||||
uv.uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv.uv_buf_t* buf,
|
||||
const system.sockaddr* addr,
|
||||
unsigned flags
|
||||
) noexcept with gil:
|
||||
|
||||
if __ensure_handle_data(<uv.uv_handle_t*>handle,
|
||||
"UDPTransport receive callback") == 0:
|
||||
return
|
||||
|
||||
cdef:
|
||||
UDPTransport udp = <UDPTransport>handle.data
|
||||
Loop loop = udp._loop
|
||||
bytes data
|
||||
object pyaddr
|
||||
|
||||
# It's OK to free the buffer early, since nothing will
|
||||
# be able to touch it until this method is done.
|
||||
__loop_free_buffer(loop)
|
||||
|
||||
if udp._closed:
|
||||
# The handle was closed, there is no reason to
|
||||
# do any work now.
|
||||
udp.__receiving_stopped() # Just in case.
|
||||
return
|
||||
|
||||
if addr is NULL and nread == 0:
|
||||
# From libuv docs:
|
||||
# addr: struct sockaddr* containing the address
|
||||
# of the sender. Can be NULL. Valid for the duration
|
||||
# of the callback only.
|
||||
# [...]
|
||||
# The receive callback will be called with
|
||||
# nread == 0 and addr == NULL when there is
|
||||
# nothing to read, and with nread == 0 and
|
||||
# addr != NULL when an empty UDP packet is
|
||||
# received.
|
||||
return
|
||||
|
||||
if addr is NULL:
|
||||
pyaddr = None
|
||||
elif addr.sa_family == uv.AF_UNSPEC:
|
||||
# https://github.com/MagicStack/uvloop/issues/304
|
||||
if system.PLATFORM_IS_LINUX:
|
||||
pyaddr = None
|
||||
else:
|
||||
pyaddr = ''
|
||||
else:
|
||||
try:
|
||||
pyaddr = __convert_sockaddr_to_pyaddr(addr)
|
||||
except BaseException as exc:
|
||||
udp._error(exc, False)
|
||||
return
|
||||
|
||||
if nread < 0:
|
||||
exc = convert_error(nread)
|
||||
udp._on_receive(None, exc, pyaddr)
|
||||
return
|
||||
|
||||
if nread == 0:
|
||||
data = b''
|
||||
else:
|
||||
data = loop._recv_buffer[:nread]
|
||||
|
||||
try:
|
||||
udp._on_receive(data, None, pyaddr)
|
||||
except BaseException as exc:
|
||||
udp._error(exc, False)
|
||||
|
||||
|
||||
cdef void __uv_udp_on_send(
|
||||
uv.uv_udp_send_t* req,
|
||||
int status,
|
||||
) noexcept with gil:
|
||||
|
||||
if req.data is NULL:
|
||||
# Shouldn't happen as:
|
||||
# - _UDPSendContext does an extra INCREF in its 'init()'
|
||||
# - _UDPSendContext holds a ref to the relevant UDPTransport
|
||||
aio_logger.error(
|
||||
'UVStream.write callback called with NULL req.data, status=%r',
|
||||
status)
|
||||
return
|
||||
|
||||
cdef:
|
||||
_UDPSendContext ctx = <_UDPSendContext> req.data
|
||||
UDPTransport udp = <UDPTransport>ctx.udp
|
||||
|
||||
ctx.close()
|
||||
|
||||
if status < 0:
|
||||
exc = convert_error(status)
|
||||
print(exc)
|
||||
else:
|
||||
exc = None
|
||||
|
||||
try:
|
||||
udp._on_sent(exc)
|
||||
except BaseException as exc:
|
||||
udp._error(exc, False)
|
23
env/lib/python3.11/site-packages/uvloop/includes/__init__.py
vendored
Normal file
23
env/lib/python3.11/site-packages/uvloop/includes/__init__.py
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# flake8: noqa
|
||||
|
||||
# These have to be synced with the stdlib.pxi
|
||||
import asyncio
|
||||
import collections
|
||||
import concurrent.futures
|
||||
import errno
|
||||
import functools
|
||||
import gc
|
||||
import inspect
|
||||
import itertools
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import ssl
|
||||
import stat
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import time
|
||||
import warnings
|
||||
import weakref
|
BIN
env/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
BIN
env/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc
vendored
Normal file
Binary file not shown.
33
env/lib/python3.11/site-packages/uvloop/includes/consts.pxi
vendored
Normal file
33
env/lib/python3.11/site-packages/uvloop/includes/consts.pxi
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
cdef enum:
|
||||
UV_STREAM_RECV_BUF_SIZE = 256000 # 250kb
|
||||
|
||||
FLOW_CONTROL_HIGH_WATER = 64 # KiB
|
||||
FLOW_CONTROL_HIGH_WATER_SSL_READ = 256 # KiB
|
||||
FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512 # KiB
|
||||
|
||||
DEFAULT_FREELIST_SIZE = 250
|
||||
DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE = 2048
|
||||
|
||||
DEBUG_STACK_DEPTH = 10
|
||||
|
||||
|
||||
__PROCESS_DEBUG_SLEEP_AFTER_FORK = 1
|
||||
|
||||
|
||||
LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
|
||||
SSL_READ_MAX_SIZE = 256 * 1024
|
||||
|
||||
|
||||
cdef extern from *:
|
||||
'''
|
||||
// Number of seconds to wait for SSL handshake to complete
|
||||
// The default timeout matches that of Nginx.
|
||||
#define SSL_HANDSHAKE_TIMEOUT 60.0
|
||||
|
||||
// Number of seconds to wait for SSL shutdown to complete
|
||||
// The default timeout mimics lingering_time
|
||||
#define SSL_SHUTDOWN_TIMEOUT 30.0
|
||||
'''
|
||||
|
||||
const float SSL_HANDSHAKE_TIMEOUT
|
||||
const float SSL_SHUTDOWN_TIMEOUT
|
3
env/lib/python3.11/site-packages/uvloop/includes/debug.pxd
vendored
Normal file
3
env/lib/python3.11/site-packages/uvloop/includes/debug.pxd
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
cdef extern from "includes/debug.h":
|
||||
|
||||
cdef int UVLOOP_DEBUG
|
23
env/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd
vendored
Normal file
23
env/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
cdef inline add_flowcontrol_defaults(high, low, int kb):
|
||||
cdef int h, l
|
||||
if high is None:
|
||||
if low is None:
|
||||
h = kb * 1024
|
||||
else:
|
||||
l = low
|
||||
h = 4 * l
|
||||
else:
|
||||
h = high
|
||||
if low is None:
|
||||
l = h // 4
|
||||
else:
|
||||
l = low
|
||||
|
||||
if not h >= l >= 0:
|
||||
raise ValueError('high (%r) must be >= low (%r) must be >= 0' %
|
||||
(h, l))
|
||||
|
||||
return h, l
|
31
env/lib/python3.11/site-packages/uvloop/includes/python.pxd
vendored
Normal file
31
env/lib/python3.11/site-packages/uvloop/includes/python.pxd
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
cdef extern from "Python.h":
|
||||
int PY_VERSION_HEX
|
||||
|
||||
unicode PyUnicode_FromString(const char *)
|
||||
|
||||
void* PyMem_RawMalloc(size_t n) nogil
|
||||
void* PyMem_RawRealloc(void *p, size_t n) nogil
|
||||
void* PyMem_RawCalloc(size_t nelem, size_t elsize) nogil
|
||||
void PyMem_RawFree(void *p) nogil
|
||||
|
||||
object PyUnicode_EncodeFSDefault(object)
|
||||
void PyErr_SetInterrupt() nogil
|
||||
|
||||
object PyMemoryView_FromMemory(char *mem, ssize_t size, int flags)
|
||||
object PyMemoryView_FromObject(object obj)
|
||||
int PyMemoryView_Check(object obj)
|
||||
|
||||
cdef enum:
|
||||
PyBUF_WRITE
|
||||
|
||||
|
||||
cdef extern from "includes/compat.h":
|
||||
object Context_CopyCurrent()
|
||||
int Context_Enter(object) except -1
|
||||
int Context_Exit(object) except -1
|
||||
|
||||
void PyOS_BeforeFork()
|
||||
void PyOS_AfterFork_Parent()
|
||||
void PyOS_AfterFork_Child()
|
||||
|
||||
void _Py_RestoreSignals()
|
176
env/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi
vendored
Normal file
176
env/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
# flake8: noqa
|
||||
|
||||
|
||||
import asyncio, asyncio.log, asyncio.base_events, \
|
||||
asyncio.sslproto, asyncio.coroutines, \
|
||||
asyncio.futures, asyncio.transports
|
||||
import collections.abc
|
||||
import concurrent.futures
|
||||
import errno
|
||||
import functools
|
||||
import gc
|
||||
import inspect
|
||||
import itertools
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import ssl
|
||||
import stat
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
import time
|
||||
import warnings
|
||||
import weakref
|
||||
|
||||
|
||||
cdef aio_get_event_loop = asyncio.get_event_loop
|
||||
cdef aio_CancelledError = asyncio.CancelledError
|
||||
cdef aio_InvalidStateError = asyncio.InvalidStateError
|
||||
cdef aio_TimeoutError = asyncio.TimeoutError
|
||||
cdef aio_Future = asyncio.Future
|
||||
cdef aio_Task = asyncio.Task
|
||||
cdef aio_ensure_future = asyncio.ensure_future
|
||||
cdef aio_gather = asyncio.gather
|
||||
cdef aio_wait = asyncio.wait
|
||||
cdef aio_wrap_future = asyncio.wrap_future
|
||||
cdef aio_logger = asyncio.log.logger
|
||||
cdef aio_iscoroutine = asyncio.iscoroutine
|
||||
cdef aio_iscoroutinefunction = asyncio.iscoroutinefunction
|
||||
cdef aio_BaseProtocol = asyncio.BaseProtocol
|
||||
cdef aio_Protocol = asyncio.Protocol
|
||||
cdef aio_isfuture = getattr(asyncio, 'isfuture', None)
|
||||
cdef aio_get_running_loop = getattr(asyncio, '_get_running_loop', None)
|
||||
cdef aio_set_running_loop = getattr(asyncio, '_set_running_loop', None)
|
||||
cdef aio_debug_wrapper = getattr(asyncio.coroutines, 'debug_wrapper', None)
|
||||
cdef aio_AbstractChildWatcher = asyncio.AbstractChildWatcher
|
||||
cdef aio_Transport = asyncio.Transport
|
||||
cdef aio_FlowControlMixin = asyncio.transports._FlowControlMixin
|
||||
|
||||
cdef col_deque = collections.deque
|
||||
cdef col_Iterable = collections.abc.Iterable
|
||||
cdef col_Counter = collections.Counter
|
||||
cdef col_OrderedDict = collections.OrderedDict
|
||||
|
||||
cdef cc_ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor
|
||||
cdef cc_Future = concurrent.futures.Future
|
||||
|
||||
cdef errno_EBADF = errno.EBADF
|
||||
cdef errno_EINVAL = errno.EINVAL
|
||||
|
||||
cdef ft_partial = functools.partial
|
||||
|
||||
cdef gc_disable = gc.disable
|
||||
|
||||
cdef iter_chain = itertools.chain
|
||||
cdef inspect_isgenerator = inspect.isgenerator
|
||||
|
||||
cdef int has_IPV6_V6ONLY = hasattr(socket, 'IPV6_V6ONLY')
|
||||
cdef int IPV6_V6ONLY = getattr(socket, 'IPV6_V6ONLY', -1)
|
||||
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
|
||||
cdef socket_timeout = socket.timeout
|
||||
cdef socket_socket = socket.socket
|
||||
cdef socket_socketpair = socket.socketpair
|
||||
cdef socket_getservbyname = socket.getservbyname
|
||||
cdef socket_AddressFamily = socket.AddressFamily
|
||||
cdef socket_SocketKind = socket.SocketKind
|
||||
|
||||
cdef int socket_EAI_ADDRFAMILY = getattr(socket, 'EAI_ADDRFAMILY', -1)
|
||||
cdef int socket_EAI_AGAIN = getattr(socket, 'EAI_AGAIN', -1)
|
||||
cdef int socket_EAI_BADFLAGS = getattr(socket, 'EAI_BADFLAGS', -1)
|
||||
cdef int socket_EAI_BADHINTS = getattr(socket, 'EAI_BADHINTS', -1)
|
||||
cdef int socket_EAI_CANCELED = getattr(socket, 'EAI_CANCELED', -1)
|
||||
cdef int socket_EAI_FAIL = getattr(socket, 'EAI_FAIL', -1)
|
||||
cdef int socket_EAI_FAMILY = getattr(socket, 'EAI_FAMILY', -1)
|
||||
cdef int socket_EAI_MEMORY = getattr(socket, 'EAI_MEMORY', -1)
|
||||
cdef int socket_EAI_NODATA = getattr(socket, 'EAI_NODATA', -1)
|
||||
cdef int socket_EAI_NONAME = getattr(socket, 'EAI_NONAME', -1)
|
||||
cdef int socket_EAI_OVERFLOW = getattr(socket, 'EAI_OVERFLOW', -1)
|
||||
cdef int socket_EAI_PROTOCOL = getattr(socket, 'EAI_PROTOCOL', -1)
|
||||
cdef int socket_EAI_SERVICE = getattr(socket, 'EAI_SERVICE', -1)
|
||||
cdef int socket_EAI_SOCKTYPE = getattr(socket, 'EAI_SOCKTYPE', -1)
|
||||
|
||||
|
||||
cdef str os_name = os.name
|
||||
cdef os_environ = os.environ
|
||||
cdef os_dup = os.dup
|
||||
cdef os_set_inheritable = os.set_inheritable
|
||||
cdef os_get_inheritable = os.get_inheritable
|
||||
cdef os_close = os.close
|
||||
cdef os_open = os.open
|
||||
cdef os_devnull = os.devnull
|
||||
cdef os_O_RDWR = os.O_RDWR
|
||||
cdef os_pipe = os.pipe
|
||||
cdef os_read = os.read
|
||||
cdef os_remove = os.remove
|
||||
cdef os_stat = os.stat
|
||||
cdef os_unlink = os.unlink
|
||||
cdef os_fspath = os.fspath
|
||||
|
||||
cdef stat_S_ISSOCK = stat.S_ISSOCK
|
||||
|
||||
cdef sys_ignore_environment = sys.flags.ignore_environment
|
||||
cdef sys_dev_mode = sys.flags.dev_mode
|
||||
cdef sys_exc_info = sys.exc_info
|
||||
cdef sys_set_coroutine_wrapper = getattr(sys, 'set_coroutine_wrapper', None)
|
||||
cdef sys_get_coroutine_wrapper = getattr(sys, 'get_coroutine_wrapper', None)
|
||||
cdef sys_getframe = sys._getframe
|
||||
cdef sys_version_info = sys.version_info
|
||||
cdef sys_getfilesystemencoding = sys.getfilesystemencoding
|
||||
cdef str sys_platform = sys.platform
|
||||
|
||||
cdef ssl_SSLContext = ssl.SSLContext
|
||||
cdef ssl_MemoryBIO = ssl.MemoryBIO
|
||||
cdef ssl_create_default_context = ssl.create_default_context
|
||||
cdef ssl_SSLError = ssl.SSLError
|
||||
cdef ssl_SSLAgainErrors = (ssl.SSLWantReadError, ssl.SSLSyscallError)
|
||||
cdef ssl_SSLZeroReturnError = ssl.SSLZeroReturnError
|
||||
cdef ssl_CertificateError = ssl.CertificateError
|
||||
cdef int ssl_SSL_ERROR_WANT_READ = ssl.SSL_ERROR_WANT_READ
|
||||
cdef int ssl_SSL_ERROR_WANT_WRITE = ssl.SSL_ERROR_WANT_WRITE
|
||||
cdef int ssl_SSL_ERROR_SYSCALL = ssl.SSL_ERROR_SYSCALL
|
||||
|
||||
cdef threading_Thread = threading.Thread
|
||||
cdef threading_main_thread = threading.main_thread
|
||||
|
||||
cdef int subprocess_PIPE = subprocess.PIPE
|
||||
cdef int subprocess_STDOUT = subprocess.STDOUT
|
||||
cdef int subprocess_DEVNULL = subprocess.DEVNULL
|
||||
cdef subprocess_SubprocessError = subprocess.SubprocessError
|
||||
|
||||
cdef int signal_NSIG = signal.NSIG
|
||||
cdef signal_signal = signal.signal
|
||||
cdef signal_siginterrupt = signal.siginterrupt
|
||||
cdef signal_set_wakeup_fd = signal.set_wakeup_fd
|
||||
cdef signal_default_int_handler = signal.default_int_handler
|
||||
cdef signal_SIG_DFL = signal.SIG_DFL
|
||||
|
||||
cdef time_sleep = time.sleep
|
||||
cdef time_monotonic = time.monotonic
|
||||
|
||||
cdef tb_StackSummary = traceback.StackSummary
|
||||
cdef tb_walk_stack = traceback.walk_stack
|
||||
cdef tb_format_list = traceback.format_list
|
||||
|
||||
cdef warnings_warn = warnings.warn
|
||||
|
||||
cdef weakref_WeakValueDictionary = weakref.WeakValueDictionary
|
||||
cdef weakref_WeakSet = weakref.WeakSet
|
||||
|
||||
cdef py_inf = float('inf')
|
||||
|
||||
|
||||
# Cython doesn't clean-up imported objects properly in Py3 mode,
|
||||
# so we delete refs to all modules manually (except sys)
|
||||
del asyncio, concurrent, collections, errno
|
||||
del functools, inspect, itertools, socket, os, threading
|
||||
del signal, subprocess, ssl
|
||||
del time, traceback, warnings, weakref
|
96
env/lib/python3.11/site-packages/uvloop/includes/system.pxd
vendored
Normal file
96
env/lib/python3.11/site-packages/uvloop/includes/system.pxd
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
from libc.stdint cimport int8_t, uint64_t
|
||||
|
||||
cdef extern from "arpa/inet.h" nogil:
|
||||
|
||||
int ntohl(int)
|
||||
int htonl(int)
|
||||
int ntohs(int)
|
||||
|
||||
|
||||
cdef extern from "sys/socket.h" nogil:
|
||||
|
||||
struct sockaddr:
|
||||
unsigned short sa_family
|
||||
char sa_data[14]
|
||||
|
||||
struct addrinfo:
|
||||
int ai_flags
|
||||
int ai_family
|
||||
int ai_socktype
|
||||
int ai_protocol
|
||||
size_t ai_addrlen
|
||||
sockaddr* ai_addr
|
||||
char* ai_canonname
|
||||
addrinfo* ai_next
|
||||
|
||||
struct sockaddr_in:
|
||||
unsigned short sin_family
|
||||
unsigned short sin_port
|
||||
# ...
|
||||
|
||||
struct sockaddr_in6:
|
||||
unsigned short sin6_family
|
||||
unsigned short sin6_port
|
||||
unsigned long sin6_flowinfo
|
||||
# ...
|
||||
unsigned long sin6_scope_id
|
||||
|
||||
struct sockaddr_storage:
|
||||
unsigned short ss_family
|
||||
# ...
|
||||
|
||||
const char *gai_strerror(int errcode)
|
||||
|
||||
int socketpair(int domain, int type, int protocol, int socket_vector[2])
|
||||
|
||||
int setsockopt(int socket, int level, int option_name,
|
||||
const void *option_value, int option_len)
|
||||
|
||||
|
||||
cdef extern from "sys/un.h" nogil:
|
||||
|
||||
struct sockaddr_un:
|
||||
unsigned short sun_family
|
||||
char* sun_path
|
||||
# ...
|
||||
|
||||
|
||||
cdef extern from "unistd.h" nogil:
|
||||
|
||||
ssize_t write(int fd, const void *buf, size_t count)
|
||||
void _exit(int status)
|
||||
|
||||
|
||||
cdef extern from "pthread.h":
|
||||
|
||||
int pthread_atfork(
|
||||
void (*prepare)(),
|
||||
void (*parent)(),
|
||||
void (*child)())
|
||||
|
||||
|
||||
cdef extern from "includes/compat.h" nogil:
|
||||
|
||||
cdef int EWOULDBLOCK
|
||||
|
||||
cdef int PLATFORM_IS_APPLE
|
||||
cdef int PLATFORM_IS_LINUX
|
||||
|
||||
struct epoll_event:
|
||||
# We don't use the fields
|
||||
pass
|
||||
|
||||
int EPOLL_CTL_DEL
|
||||
int epoll_ctl(int epfd, int op, int fd, epoll_event *event)
|
||||
object MakeUnixSockPyAddr(sockaddr_un *addr)
|
||||
|
||||
|
||||
cdef extern from "includes/fork_handler.h":
|
||||
|
||||
uint64_t MAIN_THREAD_ID
|
||||
int8_t MAIN_THREAD_ID_SET
|
||||
ctypedef void (*OnForkHandler)()
|
||||
void handleAtFork()
|
||||
void setForkHandler(OnForkHandler handler)
|
||||
void resetForkHandler()
|
||||
void setMainThreadID(uint64_t id)
|
506
env/lib/python3.11/site-packages/uvloop/includes/uv.pxd
vendored
Normal file
506
env/lib/python3.11/site-packages/uvloop/includes/uv.pxd
vendored
Normal file
@ -0,0 +1,506 @@
|
||||
from libc.stdint cimport uint16_t, uint32_t, uint64_t, int64_t
|
||||
from posix.types cimport gid_t, uid_t
|
||||
from posix.unistd cimport getuid
|
||||
|
||||
from . cimport system
|
||||
|
||||
# This is an internal enum UV_HANDLE_READABLE from uv-common.h, used only by
|
||||
# handles/pipe.pyx to temporarily workaround a libuv issue libuv/libuv#2058,
|
||||
# before there is a proper fix in libuv. In short, libuv disallowed feeding a
|
||||
# write-only pipe to uv_read_start(), which was needed by uvloop to detect a
|
||||
# broken pipe without having to send anything on the write-only end. We're
|
||||
# setting UV_HANDLE_READABLE on pipe_t to workaround this limitation
|
||||
# temporarily, please see also #317.
|
||||
cdef enum:
|
||||
UV_INTERNAL_HANDLE_READABLE = 0x00004000
|
||||
|
||||
cdef extern from "uv.h" nogil:
|
||||
cdef int UV_TCP_IPV6ONLY
|
||||
|
||||
cdef int UV_EACCES
|
||||
cdef int UV_EAGAIN
|
||||
cdef int UV_EALREADY
|
||||
cdef int UV_EBUSY
|
||||
cdef int UV_ECONNABORTED
|
||||
cdef int UV_ECONNREFUSED
|
||||
cdef int UV_ECONNRESET
|
||||
cdef int UV_ECANCELED
|
||||
cdef int UV_EEXIST
|
||||
cdef int UV_EINTR
|
||||
cdef int UV_EINVAL
|
||||
cdef int UV_EISDIR
|
||||
cdef int UV_ENOENT
|
||||
cdef int UV_EOF
|
||||
cdef int UV_EPERM
|
||||
cdef int UV_EPIPE
|
||||
cdef int UV_ESHUTDOWN
|
||||
cdef int UV_ESRCH
|
||||
cdef int UV_ETIMEDOUT
|
||||
cdef int UV_EBADF
|
||||
cdef int UV_ENOBUFS
|
||||
|
||||
cdef int UV_EAI_ADDRFAMILY
|
||||
cdef int UV_EAI_AGAIN
|
||||
cdef int UV_EAI_BADFLAGS
|
||||
cdef int UV_EAI_BADHINTS
|
||||
cdef int UV_EAI_CANCELED
|
||||
cdef int UV_EAI_FAIL
|
||||
cdef int UV_EAI_FAMILY
|
||||
cdef int UV_EAI_MEMORY
|
||||
cdef int UV_EAI_NODATA
|
||||
cdef int UV_EAI_NONAME
|
||||
cdef int UV_EAI_OVERFLOW
|
||||
cdef int UV_EAI_PROTOCOL
|
||||
cdef int UV_EAI_SERVICE
|
||||
cdef int UV_EAI_SOCKTYPE
|
||||
|
||||
cdef int SOL_SOCKET
|
||||
cdef int SO_ERROR
|
||||
cdef int SO_REUSEADDR
|
||||
# use has_SO_REUSEPORT and SO_REUSEPORT in stdlib.pxi instead
|
||||
cdef int AF_INET
|
||||
cdef int AF_INET6
|
||||
cdef int AF_UNIX
|
||||
cdef int AF_UNSPEC
|
||||
cdef int AI_PASSIVE
|
||||
cdef int AI_NUMERICHOST
|
||||
cdef int INET6_ADDRSTRLEN
|
||||
cdef int IPPROTO_IPV6
|
||||
cdef int SOCK_STREAM
|
||||
cdef int SOCK_DGRAM
|
||||
cdef int IPPROTO_TCP
|
||||
cdef int IPPROTO_UDP
|
||||
|
||||
cdef int SIGINT
|
||||
cdef int SIGHUP
|
||||
cdef int SIGCHLD
|
||||
cdef int SIGKILL
|
||||
cdef int SIGTERM
|
||||
|
||||
ctypedef int uv_os_sock_t
|
||||
ctypedef int uv_file
|
||||
ctypedef int uv_os_fd_t
|
||||
|
||||
ctypedef struct uv_buf_t:
|
||||
char* base
|
||||
size_t len
|
||||
|
||||
ctypedef struct uv_loop_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_handle_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
unsigned int flags
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_idle_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_check_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_signal_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_async_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_timer_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_stream_t:
|
||||
void* data
|
||||
size_t write_queue_size
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_tcp_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_pipe_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_udp_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
size_t send_queue_size
|
||||
size_t send_queue_count
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_udp_send_t:
|
||||
void* data
|
||||
uv_udp_t* handle
|
||||
|
||||
ctypedef struct uv_poll_t:
|
||||
void* data
|
||||
uv_loop_t* loop
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_req_t:
|
||||
# Only cancellation of uv_fs_t, uv_getaddrinfo_t,
|
||||
# uv_getnameinfo_t and uv_work_t requests is
|
||||
# currently supported.
|
||||
void* data
|
||||
uv_req_type type
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_connect_t:
|
||||
void* data
|
||||
|
||||
ctypedef struct uv_getaddrinfo_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_getnameinfo_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_write_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_shutdown_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_process_t:
|
||||
void* data
|
||||
int pid
|
||||
# ...
|
||||
|
||||
ctypedef struct uv_fs_event_t:
|
||||
void* data
|
||||
# ...
|
||||
|
||||
ctypedef enum uv_req_type:
|
||||
UV_UNKNOWN_REQ = 0,
|
||||
UV_REQ,
|
||||
UV_CONNECT,
|
||||
UV_WRITE,
|
||||
UV_SHUTDOWN,
|
||||
UV_UDP_SEND,
|
||||
UV_FS,
|
||||
UV_WORK,
|
||||
UV_GETADDRINFO,
|
||||
UV_GETNAMEINFO,
|
||||
UV_REQ_TYPE_PRIVATE,
|
||||
UV_REQ_TYPE_MAX
|
||||
|
||||
ctypedef enum uv_run_mode:
|
||||
UV_RUN_DEFAULT = 0,
|
||||
UV_RUN_ONCE,
|
||||
UV_RUN_NOWAIT
|
||||
|
||||
ctypedef enum uv_poll_event:
|
||||
UV_READABLE = 1,
|
||||
UV_WRITABLE = 2,
|
||||
UV_DISCONNECT = 4
|
||||
|
||||
ctypedef enum uv_udp_flags:
|
||||
UV_UDP_IPV6ONLY = 1,
|
||||
UV_UDP_PARTIAL = 2
|
||||
|
||||
ctypedef enum uv_membership:
|
||||
UV_LEAVE_GROUP = 0,
|
||||
UV_JOIN_GROUP
|
||||
|
||||
cdef enum uv_fs_event:
|
||||
UV_RENAME = 1,
|
||||
UV_CHANGE = 2
|
||||
|
||||
const char* uv_strerror(int err)
|
||||
const char* uv_err_name(int err)
|
||||
|
||||
ctypedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg) with gil
|
||||
|
||||
ctypedef void (*uv_close_cb)(uv_handle_t* handle) with gil
|
||||
ctypedef void (*uv_idle_cb)(uv_idle_t* handle) with gil
|
||||
ctypedef void (*uv_check_cb)(uv_check_t* handle) with gil
|
||||
ctypedef void (*uv_signal_cb)(uv_signal_t* handle, int signum) with gil
|
||||
ctypedef void (*uv_async_cb)(uv_async_t* handle) with gil
|
||||
ctypedef void (*uv_timer_cb)(uv_timer_t* handle) with gil
|
||||
ctypedef void (*uv_connection_cb)(uv_stream_t* server, int status) with gil
|
||||
ctypedef void (*uv_alloc_cb)(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) with gil
|
||||
ctypedef void (*uv_read_cb)(uv_stream_t* stream,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf) with gil
|
||||
ctypedef void (*uv_write_cb)(uv_write_t* req, int status) with gil
|
||||
ctypedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
|
||||
int status,
|
||||
system.addrinfo* res) with gil
|
||||
ctypedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
|
||||
int status,
|
||||
const char* hostname,
|
||||
const char* service) with gil
|
||||
ctypedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) with gil
|
||||
ctypedef void (*uv_poll_cb)(uv_poll_t* handle,
|
||||
int status, int events) with gil
|
||||
|
||||
ctypedef void (*uv_connect_cb)(uv_connect_t* req, int status) with gil
|
||||
|
||||
ctypedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status) with gil
|
||||
ctypedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* buf,
|
||||
const system.sockaddr* addr,
|
||||
unsigned flags) with gil
|
||||
ctypedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
|
||||
const char *filename,
|
||||
int events,
|
||||
int status) with gil
|
||||
|
||||
# Generic request functions
|
||||
int uv_cancel(uv_req_t* req)
|
||||
|
||||
# Generic handler functions
|
||||
int uv_is_active(const uv_handle_t* handle)
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
|
||||
int uv_is_closing(const uv_handle_t* handle)
|
||||
int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd)
|
||||
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg)
|
||||
|
||||
# Loop functions
|
||||
int uv_loop_init(uv_loop_t* loop)
|
||||
int uv_loop_close(uv_loop_t* loop)
|
||||
int uv_loop_alive(uv_loop_t* loop)
|
||||
int uv_loop_fork(uv_loop_t* loop)
|
||||
uv_os_fd_t uv_backend_fd(uv_loop_t* loop)
|
||||
|
||||
void uv_update_time(uv_loop_t* loop)
|
||||
uint64_t uv_now(const uv_loop_t*)
|
||||
|
||||
int uv_run(uv_loop_t*, uv_run_mode mode) nogil
|
||||
void uv_stop(uv_loop_t*)
|
||||
|
||||
# Idle handler
|
||||
int uv_idle_init(uv_loop_t*, uv_idle_t* idle)
|
||||
int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb)
|
||||
int uv_idle_stop(uv_idle_t* idle)
|
||||
|
||||
# Check handler
|
||||
int uv_check_init(uv_loop_t*, uv_check_t* idle)
|
||||
int uv_check_start(uv_check_t* check, uv_check_cb cb)
|
||||
int uv_check_stop(uv_check_t* check)
|
||||
|
||||
# Signal handler
|
||||
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle)
|
||||
int uv_signal_start(uv_signal_t* handle,
|
||||
uv_signal_cb signal_cb,
|
||||
int signum)
|
||||
int uv_signal_stop(uv_signal_t* handle)
|
||||
|
||||
# Async handler
|
||||
int uv_async_init(uv_loop_t*,
|
||||
uv_async_t* async_,
|
||||
uv_async_cb async_cb)
|
||||
int uv_async_send(uv_async_t* async_)
|
||||
|
||||
# Timer handler
|
||||
int uv_timer_init(uv_loop_t*, uv_timer_t* handle)
|
||||
int uv_timer_start(uv_timer_t* handle,
|
||||
uv_timer_cb cb,
|
||||
uint64_t timeout,
|
||||
uint64_t repeat)
|
||||
int uv_timer_stop(uv_timer_t* handle)
|
||||
|
||||
# DNS
|
||||
int uv_getaddrinfo(uv_loop_t* loop,
|
||||
uv_getaddrinfo_t* req,
|
||||
uv_getaddrinfo_cb getaddrinfo_cb,
|
||||
const char* node,
|
||||
const char* service,
|
||||
const system.addrinfo* hints)
|
||||
|
||||
void uv_freeaddrinfo(system.addrinfo* ai)
|
||||
|
||||
int uv_getnameinfo(uv_loop_t* loop,
|
||||
uv_getnameinfo_t* req,
|
||||
uv_getnameinfo_cb getnameinfo_cb,
|
||||
const system.sockaddr* addr,
|
||||
int flags)
|
||||
|
||||
int uv_ip4_name(const system.sockaddr_in* src, char* dst, size_t size)
|
||||
int uv_ip6_name(const system.sockaddr_in6* src, char* dst, size_t size)
|
||||
|
||||
# Streams
|
||||
|
||||
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
|
||||
int uv_accept(uv_stream_t* server, uv_stream_t* client)
|
||||
int uv_read_start(uv_stream_t* stream,
|
||||
uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb)
|
||||
int uv_read_stop(uv_stream_t*)
|
||||
int uv_write(uv_write_t* req, uv_stream_t* handle,
|
||||
uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
|
||||
|
||||
int uv_try_write(uv_stream_t* handle, uv_buf_t bufs[], unsigned int nbufs)
|
||||
|
||||
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb)
|
||||
|
||||
int uv_is_readable(const uv_stream_t* handle)
|
||||
int uv_is_writable(const uv_stream_t* handle)
|
||||
|
||||
# TCP
|
||||
|
||||
int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags)
|
||||
int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
|
||||
int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
|
||||
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
|
||||
int uv_tcp_bind(uv_tcp_t* handle, system.sockaddr* addr,
|
||||
unsigned int flags)
|
||||
|
||||
int uv_tcp_getsockname(const uv_tcp_t* handle, system.sockaddr* name,
|
||||
int* namelen)
|
||||
int uv_tcp_getpeername(const uv_tcp_t* handle, system.sockaddr* name,
|
||||
int* namelen)
|
||||
|
||||
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
|
||||
const system.sockaddr* addr, uv_connect_cb cb)
|
||||
|
||||
# Pipes
|
||||
|
||||
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)
|
||||
int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t file)
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name)
|
||||
|
||||
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
const char* name, uv_connect_cb cb)
|
||||
|
||||
# UDP
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
|
||||
int uv_udp_connect(uv_udp_t* handle, const system.sockaddr* addr)
|
||||
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
|
||||
int uv_udp_bind(uv_udp_t* handle, const system.sockaddr* addr,
|
||||
unsigned int flags)
|
||||
int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs,
|
||||
const system.sockaddr* addr, uv_udp_send_cb send_cb)
|
||||
int uv_udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs,
|
||||
const system.sockaddr* addr)
|
||||
int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_udp_recv_cb recv_cb)
|
||||
int uv_udp_recv_stop(uv_udp_t* handle)
|
||||
int uv_udp_set_broadcast(uv_udp_t* handle, int on)
|
||||
|
||||
# Polling
|
||||
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd)
|
||||
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
uv_os_sock_t socket)
|
||||
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
|
||||
int uv_poll_stop(uv_poll_t* poll)
|
||||
|
||||
# FS Event
|
||||
|
||||
int uv_fs_event_init(uv_loop_t *loop, uv_fs_event_t *handle)
|
||||
int uv_fs_event_start(uv_fs_event_t *handle, uv_fs_event_cb cb,
|
||||
const char *path, unsigned int flags)
|
||||
int uv_fs_event_stop(uv_fs_event_t *handle)
|
||||
|
||||
# Misc
|
||||
|
||||
ctypedef struct uv_timeval_t:
|
||||
long tv_sec
|
||||
long tv_usec
|
||||
|
||||
ctypedef struct uv_rusage_t:
|
||||
uv_timeval_t ru_utime # user CPU time used
|
||||
uv_timeval_t ru_stime # system CPU time used
|
||||
uint64_t ru_maxrss # maximum resident set size
|
||||
uint64_t ru_ixrss # integral shared memory size
|
||||
uint64_t ru_idrss # integral unshared data size
|
||||
uint64_t ru_isrss # integral unshared stack size
|
||||
uint64_t ru_minflt # page reclaims (soft page faults)
|
||||
uint64_t ru_majflt # page faults (hard page faults)
|
||||
uint64_t ru_nswap # swaps
|
||||
uint64_t ru_inblock # block input operations
|
||||
uint64_t ru_oublock # block output operations
|
||||
uint64_t ru_msgsnd # IPC messages sent
|
||||
uint64_t ru_msgrcv # IPC messages received
|
||||
uint64_t ru_nsignals # signals received
|
||||
uint64_t ru_nvcsw # voluntary context switches
|
||||
uint64_t ru_nivcsw # involuntary context switches
|
||||
|
||||
int uv_getrusage(uv_rusage_t* rusage)
|
||||
|
||||
int uv_ip4_addr(const char* ip, int port, system.sockaddr_in* addr)
|
||||
int uv_ip6_addr(const char* ip, int port, system.sockaddr_in6* addr)
|
||||
|
||||
# Memory Allocation
|
||||
|
||||
ctypedef void* (*uv_malloc_func)(size_t size)
|
||||
ctypedef void* (*uv_realloc_func)(void* ptr, size_t size)
|
||||
ctypedef void* (*uv_calloc_func)(size_t count, size_t size)
|
||||
ctypedef void (*uv_free_func)(void* ptr)
|
||||
|
||||
int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
uv_realloc_func realloc_func,
|
||||
uv_calloc_func calloc_func,
|
||||
uv_free_func free_func)
|
||||
|
||||
# Process
|
||||
|
||||
ctypedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status,
|
||||
int term_signal) with gil
|
||||
|
||||
ctypedef enum uv_process_flags:
|
||||
UV_PROCESS_SETUID = 1,
|
||||
UV_PROCESS_SETGID = 2,
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = 4,
|
||||
UV_PROCESS_DETACHED = 8,
|
||||
UV_PROCESS_WINDOWS_HIDE = 16
|
||||
|
||||
ctypedef enum uv_stdio_flags:
|
||||
UV_IGNORE = 0x00,
|
||||
UV_CREATE_PIPE = 0x01,
|
||||
UV_INHERIT_FD = 0x02,
|
||||
UV_INHERIT_STREAM = 0x04,
|
||||
UV_READABLE_PIPE = 0x10,
|
||||
UV_WRITABLE_PIPE = 0x20
|
||||
|
||||
ctypedef union uv_stdio_container_data_u:
|
||||
uv_stream_t* stream
|
||||
int fd
|
||||
|
||||
ctypedef struct uv_stdio_container_t:
|
||||
uv_stdio_flags flags
|
||||
uv_stdio_container_data_u data
|
||||
|
||||
ctypedef struct uv_process_options_t:
|
||||
uv_exit_cb exit_cb
|
||||
char* file
|
||||
char** args
|
||||
char** env
|
||||
char* cwd
|
||||
unsigned int flags
|
||||
int stdio_count
|
||||
uv_stdio_container_t* stdio
|
||||
uid_t uid
|
||||
gid_t gid
|
||||
|
||||
int uv_spawn(uv_loop_t* loop, uv_process_t* handle,
|
||||
const uv_process_options_t* options)
|
||||
|
||||
int uv_process_kill(uv_process_t* handle, int signum)
|
||||
|
||||
unsigned int uv_version()
|
BIN
env/lib/python3.11/site-packages/uvloop/loop.cpython-311-darwin.so
vendored
Executable file
BIN
env/lib/python3.11/site-packages/uvloop/loop.cpython-311-darwin.so
vendored
Executable file
Binary file not shown.
230
env/lib/python3.11/site-packages/uvloop/loop.pxd
vendored
Normal file
230
env/lib/python3.11/site-packages/uvloop/loop.pxd
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
# cython: language_level=3
|
||||
|
||||
|
||||
from .includes cimport uv
|
||||
from .includes cimport system
|
||||
|
||||
from libc.stdint cimport uint64_t, uint32_t, int64_t
|
||||
|
||||
|
||||
include "includes/consts.pxi"
|
||||
|
||||
|
||||
cdef extern from *:
|
||||
ctypedef int vint "volatile int"
|
||||
|
||||
|
||||
cdef class UVHandle
|
||||
cdef class UVSocketHandle(UVHandle)
|
||||
|
||||
cdef class UVAsync(UVHandle)
|
||||
cdef class UVTimer(UVHandle)
|
||||
cdef class UVIdle(UVHandle)
|
||||
|
||||
cdef class UVBaseTransport(UVSocketHandle)
|
||||
|
||||
ctypedef object (*method_t)(object)
|
||||
ctypedef object (*method1_t)(object, object)
|
||||
ctypedef object (*method2_t)(object, object, object)
|
||||
ctypedef object (*method3_t)(object, object, object, object)
|
||||
|
||||
|
||||
cdef class Loop:
|
||||
cdef:
|
||||
uv.uv_loop_t *uvloop
|
||||
|
||||
bint _coroutine_debug_set
|
||||
int _coroutine_origin_tracking_saved_depth
|
||||
|
||||
public slow_callback_duration
|
||||
|
||||
readonly bint _closed
|
||||
bint _debug
|
||||
bint _running
|
||||
bint _stopping
|
||||
|
||||
uint64_t _thread_id
|
||||
|
||||
object _task_factory
|
||||
object _exception_handler
|
||||
object _default_executor
|
||||
object _ready
|
||||
set _queued_streams, _executing_streams
|
||||
Py_ssize_t _ready_len
|
||||
|
||||
set _servers
|
||||
|
||||
object _transports
|
||||
set _processes
|
||||
dict _fd_to_reader_fileobj
|
||||
dict _fd_to_writer_fileobj
|
||||
dict _unix_server_sockets
|
||||
|
||||
set _signals
|
||||
dict _signal_handlers
|
||||
object _ssock
|
||||
object _csock
|
||||
bint _listening_signals
|
||||
int _old_signal_wakeup_id
|
||||
|
||||
set _timers
|
||||
dict _polls
|
||||
|
||||
UVProcess active_process_handler
|
||||
|
||||
UVAsync handler_async
|
||||
UVIdle handler_idle
|
||||
UVCheck handler_check__exec_writes
|
||||
|
||||
object _last_error
|
||||
|
||||
cdef object __weakref__
|
||||
|
||||
object _asyncgens
|
||||
bint _asyncgens_shutdown_called
|
||||
|
||||
bint _executor_shutdown_called
|
||||
|
||||
char _recv_buffer[UV_STREAM_RECV_BUF_SIZE]
|
||||
bint _recv_buffer_in_use
|
||||
|
||||
# DEBUG fields
|
||||
# True when compiled with DEBUG.
|
||||
# Used only in unittests.
|
||||
readonly bint _debug_cc
|
||||
|
||||
readonly object _debug_handles_total
|
||||
readonly object _debug_handles_closed
|
||||
readonly object _debug_handles_current
|
||||
|
||||
readonly uint64_t _debug_uv_handles_total
|
||||
readonly uint64_t _debug_uv_handles_freed
|
||||
|
||||
readonly uint64_t _debug_cb_handles_total
|
||||
readonly uint64_t _debug_cb_handles_count
|
||||
readonly uint64_t _debug_cb_timer_handles_total
|
||||
readonly uint64_t _debug_cb_timer_handles_count
|
||||
|
||||
readonly uint64_t _debug_stream_shutdown_errors_total
|
||||
readonly uint64_t _debug_stream_listen_errors_total
|
||||
|
||||
readonly uint64_t _debug_stream_read_cb_total
|
||||
readonly uint64_t _debug_stream_read_cb_errors_total
|
||||
readonly uint64_t _debug_stream_read_eof_total
|
||||
readonly uint64_t _debug_stream_read_eof_cb_errors_total
|
||||
readonly uint64_t _debug_stream_read_errors_total
|
||||
|
||||
readonly uint64_t _debug_stream_write_tries
|
||||
readonly uint64_t _debug_stream_write_errors_total
|
||||
readonly uint64_t _debug_stream_write_ctx_total
|
||||
readonly uint64_t _debug_stream_write_ctx_cnt
|
||||
readonly uint64_t _debug_stream_write_cb_errors_total
|
||||
|
||||
readonly uint64_t _poll_read_events_total
|
||||
readonly uint64_t _poll_read_cb_errors_total
|
||||
readonly uint64_t _poll_write_events_total
|
||||
readonly uint64_t _poll_write_cb_errors_total
|
||||
|
||||
readonly uint64_t _sock_try_write_total
|
||||
|
||||
readonly uint64_t _debug_exception_handler_cnt
|
||||
|
||||
cdef _init_debug_fields(self)
|
||||
|
||||
cdef _on_wake(self)
|
||||
cdef _on_idle(self)
|
||||
|
||||
cdef __run(self, uv.uv_run_mode)
|
||||
cdef _run(self, uv.uv_run_mode)
|
||||
|
||||
cdef _close(self)
|
||||
cdef _stop(self, exc)
|
||||
cdef uint64_t _time(self)
|
||||
|
||||
cdef inline _queue_write(self, UVStream stream)
|
||||
cdef _exec_queued_writes(self)
|
||||
|
||||
cdef inline _call_soon(self, object callback, object args, object context)
|
||||
cdef inline _append_ready_handle(self, Handle handle)
|
||||
cdef inline _call_soon_handle(self, Handle handle)
|
||||
|
||||
cdef _call_later(self, uint64_t delay, object callback, object args,
|
||||
object context)
|
||||
|
||||
cdef void _handle_exception(self, object ex)
|
||||
|
||||
cdef inline _is_main_thread(self)
|
||||
|
||||
cdef inline _new_future(self)
|
||||
cdef inline _check_signal(self, sig)
|
||||
cdef inline _check_closed(self)
|
||||
cdef inline _check_thread(self)
|
||||
|
||||
cdef _getaddrinfo(self, object host, object port,
|
||||
int family, int type,
|
||||
int proto, int flags,
|
||||
int unpack)
|
||||
|
||||
cdef _getnameinfo(self, system.sockaddr *addr, int flags)
|
||||
|
||||
cdef _track_transport(self, UVBaseTransport transport)
|
||||
cdef _fileobj_to_fd(self, fileobj)
|
||||
cdef _ensure_fd_no_transport(self, fd)
|
||||
|
||||
cdef _track_process(self, UVProcess proc)
|
||||
cdef _untrack_process(self, UVProcess proc)
|
||||
|
||||
cdef _add_reader(self, fd, Handle handle)
|
||||
cdef _has_reader(self, fd)
|
||||
cdef _remove_reader(self, fd)
|
||||
|
||||
cdef _add_writer(self, fd, Handle handle)
|
||||
cdef _has_writer(self, fd)
|
||||
cdef _remove_writer(self, fd)
|
||||
|
||||
cdef _sock_recv(self, fut, sock, n)
|
||||
cdef _sock_recv_into(self, fut, sock, buf)
|
||||
cdef _sock_sendall(self, fut, sock, data)
|
||||
cdef _sock_accept(self, fut, sock)
|
||||
|
||||
cdef _sock_connect(self, sock, address)
|
||||
cdef _sock_connect_cb(self, fut, sock, address)
|
||||
|
||||
cdef _sock_set_reuseport(self, int fd)
|
||||
|
||||
cdef _setup_or_resume_signals(self)
|
||||
cdef _shutdown_signals(self)
|
||||
cdef _pause_signals(self)
|
||||
|
||||
cdef _handle_signal(self, sig)
|
||||
cdef _read_from_self(self)
|
||||
cdef inline _ceval_process_signals(self)
|
||||
cdef _invoke_signals(self, bytes data)
|
||||
|
||||
cdef _set_coroutine_debug(self, bint enabled)
|
||||
|
||||
cdef _print_debug_info(self)
|
||||
|
||||
|
||||
include "cbhandles.pxd"
|
||||
|
||||
include "handles/handle.pxd"
|
||||
include "handles/async_.pxd"
|
||||
include "handles/idle.pxd"
|
||||
include "handles/check.pxd"
|
||||
include "handles/timer.pxd"
|
||||
include "handles/poll.pxd"
|
||||
include "handles/basetransport.pxd"
|
||||
include "handles/stream.pxd"
|
||||
include "handles/streamserver.pxd"
|
||||
include "handles/tcp.pxd"
|
||||
include "handles/pipe.pxd"
|
||||
include "handles/process.pxd"
|
||||
include "handles/fsevent.pxd"
|
||||
|
||||
include "request.pxd"
|
||||
include "sslproto.pxd"
|
||||
|
||||
include "handles/udp.pxd"
|
||||
|
||||
include "server.pxd"
|
297
env/lib/python3.11/site-packages/uvloop/loop.pyi
vendored
Normal file
297
env/lib/python3.11/site-packages/uvloop/loop.pyi
vendored
Normal file
@ -0,0 +1,297 @@
|
||||
import asyncio
|
||||
import ssl
|
||||
import sys
|
||||
from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket
|
||||
from typing import (
|
||||
IO,
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable,
|
||||
Dict,
|
||||
Generator,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
Tuple,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
|
||||
_T = TypeVar('_T')
|
||||
_Context = Dict[str, Any]
|
||||
_ExceptionHandler = Callable[[asyncio.AbstractEventLoop, _Context], Any]
|
||||
_SSLContext = Union[bool, None, ssl.SSLContext]
|
||||
_ProtocolT = TypeVar("_ProtocolT", bound=asyncio.BaseProtocol)
|
||||
|
||||
class Loop:
|
||||
def call_soon(
|
||||
self, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
|
||||
) -> asyncio.Handle: ...
|
||||
def call_soon_threadsafe(
|
||||
self, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
|
||||
) -> asyncio.Handle: ...
|
||||
def call_later(
|
||||
self, delay: float, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
|
||||
) -> asyncio.TimerHandle: ...
|
||||
def call_at(
|
||||
self, when: float, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
|
||||
) -> asyncio.TimerHandle: ...
|
||||
def time(self) -> float: ...
|
||||
def stop(self) -> None: ...
|
||||
def run_forever(self) -> None: ...
|
||||
def close(self) -> None: ...
|
||||
def get_debug(self) -> bool: ...
|
||||
def set_debug(self, enabled: bool) -> None: ...
|
||||
def is_running(self) -> bool: ...
|
||||
def is_closed(self) -> bool: ...
|
||||
def create_future(self) -> asyncio.Future[Any]: ...
|
||||
def create_task(
|
||||
self,
|
||||
coro: Union[Awaitable[_T], Generator[Any, None, _T]],
|
||||
*,
|
||||
name: Optional[str] = ...,
|
||||
) -> asyncio.Task[_T]: ...
|
||||
def set_task_factory(
|
||||
self,
|
||||
factory: Optional[
|
||||
Callable[[asyncio.AbstractEventLoop, Generator[Any, None, _T]], asyncio.Future[_T]]
|
||||
],
|
||||
) -> None: ...
|
||||
def get_task_factory(
|
||||
self,
|
||||
) -> Optional[
|
||||
Callable[[asyncio.AbstractEventLoop, Generator[Any, None, _T]], asyncio.Future[_T]]
|
||||
]: ...
|
||||
@overload
|
||||
def run_until_complete(self, future: Generator[Any, None, _T]) -> _T: ...
|
||||
@overload
|
||||
def run_until_complete(self, future: Awaitable[_T]) -> _T: ...
|
||||
async def getaddrinfo(
|
||||
self,
|
||||
host: Optional[Union[str, bytes]],
|
||||
port: Optional[Union[str, bytes, int]],
|
||||
*,
|
||||
family: int = ...,
|
||||
type: int = ...,
|
||||
proto: int = ...,
|
||||
flags: int = ...,
|
||||
) -> List[
|
||||
Tuple[
|
||||
AddressFamily,
|
||||
SocketKind,
|
||||
int,
|
||||
str,
|
||||
Union[Tuple[str, int], Tuple[str, int, int, int]],
|
||||
]
|
||||
]: ...
|
||||
async def getnameinfo(
|
||||
self,
|
||||
sockaddr: Union[
|
||||
Tuple[str, int],
|
||||
Tuple[str, int, int],
|
||||
Tuple[str, int, int, int]
|
||||
],
|
||||
flags: int = ...,
|
||||
) -> Tuple[str, str]: ...
|
||||
async def start_tls(
|
||||
self,
|
||||
transport: asyncio.BaseTransport,
|
||||
protocol: asyncio.BaseProtocol,
|
||||
sslcontext: ssl.SSLContext,
|
||||
*,
|
||||
server_side: bool = ...,
|
||||
server_hostname: Optional[str] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
) -> asyncio.BaseTransport: ...
|
||||
@overload
|
||||
async def create_server(
|
||||
self,
|
||||
protocol_factory: asyncio.events._ProtocolFactory,
|
||||
host: Optional[Union[str, Sequence[str]]] = ...,
|
||||
port: int = ...,
|
||||
*,
|
||||
family: int = ...,
|
||||
flags: int = ...,
|
||||
sock: None = ...,
|
||||
backlog: int = ...,
|
||||
ssl: _SSLContext = ...,
|
||||
reuse_address: Optional[bool] = ...,
|
||||
reuse_port: Optional[bool] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
start_serving: bool = ...,
|
||||
) -> asyncio.AbstractServer: ...
|
||||
@overload
|
||||
async def create_server(
|
||||
self,
|
||||
protocol_factory: asyncio.events._ProtocolFactory,
|
||||
host: None = ...,
|
||||
port: None = ...,
|
||||
*,
|
||||
family: int = ...,
|
||||
flags: int = ...,
|
||||
sock: socket = ...,
|
||||
backlog: int = ...,
|
||||
ssl: _SSLContext = ...,
|
||||
reuse_address: Optional[bool] = ...,
|
||||
reuse_port: Optional[bool] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
start_serving: bool = ...,
|
||||
) -> asyncio.AbstractServer: ...
|
||||
@overload
|
||||
async def create_connection(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
host: str = ...,
|
||||
port: int = ...,
|
||||
*,
|
||||
ssl: _SSLContext = ...,
|
||||
family: int = ...,
|
||||
proto: int = ...,
|
||||
flags: int = ...,
|
||||
sock: None = ...,
|
||||
local_addr: Optional[Tuple[str, int]] = ...,
|
||||
server_hostname: Optional[str] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
@overload
|
||||
async def create_connection(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
host: None = ...,
|
||||
port: None = ...,
|
||||
*,
|
||||
ssl: _SSLContext = ...,
|
||||
family: int = ...,
|
||||
proto: int = ...,
|
||||
flags: int = ...,
|
||||
sock: socket,
|
||||
local_addr: None = ...,
|
||||
server_hostname: Optional[str] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def create_unix_server(
|
||||
self,
|
||||
protocol_factory: asyncio.events._ProtocolFactory,
|
||||
path: Optional[str] = ...,
|
||||
*,
|
||||
backlog: int = ...,
|
||||
sock: Optional[socket] = ...,
|
||||
ssl: _SSLContext = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
start_serving: bool = ...,
|
||||
) -> asyncio.AbstractServer: ...
|
||||
async def create_unix_connection(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
path: Optional[str] = ...,
|
||||
*,
|
||||
ssl: _SSLContext = ...,
|
||||
sock: Optional[socket] = ...,
|
||||
server_hostname: Optional[str] = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
def default_exception_handler(self, context: _Context) -> None: ...
|
||||
def get_exception_handler(self) -> Optional[_ExceptionHandler]: ...
|
||||
def set_exception_handler(self, handler: Optional[_ExceptionHandler]) -> None: ...
|
||||
def call_exception_handler(self, context: _Context) -> None: ...
|
||||
def add_reader(self, fd: Any, callback: Callable[..., Any], *args: Any) -> None: ...
|
||||
def remove_reader(self, fd: Any) -> None: ...
|
||||
def add_writer(self, fd: Any, callback: Callable[..., Any], *args: Any) -> None: ...
|
||||
def remove_writer(self, fd: Any) -> None: ...
|
||||
async def sock_recv(self, sock: socket, nbytes: int) -> bytes: ...
|
||||
async def sock_recv_into(self, sock: socket, buf: bytearray) -> int: ...
|
||||
async def sock_sendall(self, sock: socket, data: bytes) -> None: ...
|
||||
async def sock_accept(self, sock: socket) -> Tuple[socket, _RetAddress]: ...
|
||||
async def sock_connect(self, sock: socket, address: _Address) -> None: ...
|
||||
async def sock_recvfrom(self, sock: socket, bufsize: int) -> bytes: ...
|
||||
async def sock_recvfrom_into(self, sock: socket, buf: bytearray, nbytes: int = ...) -> int: ...
|
||||
async def sock_sendto(self, sock: socket, data: bytes, address: _Address) -> None: ...
|
||||
async def connect_accepted_socket(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
sock: socket,
|
||||
*,
|
||||
ssl: _SSLContext = ...,
|
||||
ssl_handshake_timeout: Optional[float] = ...,
|
||||
ssl_shutdown_timeout: Optional[float] = ...,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def run_in_executor(
|
||||
self, executor: Any, func: Callable[..., _T], *args: Any
|
||||
) -> _T: ...
|
||||
def set_default_executor(self, executor: Any) -> None: ...
|
||||
async def subprocess_shell(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
cmd: Union[bytes, str],
|
||||
*,
|
||||
stdin: Any = ...,
|
||||
stdout: Any = ...,
|
||||
stderr: Any = ...,
|
||||
**kwargs: Any,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def subprocess_exec(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
*args: Any,
|
||||
stdin: Any = ...,
|
||||
stdout: Any = ...,
|
||||
stderr: Any = ...,
|
||||
**kwargs: Any,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def connect_read_pipe(
|
||||
self, protocol_factory: Callable[[], _ProtocolT], pipe: Any
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def connect_write_pipe(
|
||||
self, protocol_factory: Callable[[], _ProtocolT], pipe: Any
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
def add_signal_handler(
|
||||
self, sig: int, callback: Callable[..., Any], *args: Any
|
||||
) -> None: ...
|
||||
def remove_signal_handler(self, sig: int) -> bool: ...
|
||||
async def create_datagram_endpoint(
|
||||
self,
|
||||
protocol_factory: Callable[[], _ProtocolT],
|
||||
local_addr: Optional[Tuple[str, int]] = ...,
|
||||
remote_addr: Optional[Tuple[str, int]] = ...,
|
||||
*,
|
||||
family: int = ...,
|
||||
proto: int = ...,
|
||||
flags: int = ...,
|
||||
reuse_address: Optional[bool] = ...,
|
||||
reuse_port: Optional[bool] = ...,
|
||||
allow_broadcast: Optional[bool] = ...,
|
||||
sock: Optional[socket] = ...,
|
||||
) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
|
||||
async def shutdown_asyncgens(self) -> None: ...
|
||||
async def shutdown_default_executor(
|
||||
self,
|
||||
timeout: Optional[float] = ...,
|
||||
) -> None: ...
|
||||
# Loop doesn't implement these, but since they are marked as abstract in typeshed,
|
||||
# we have to put them in so mypy thinks the base methods are overridden
|
||||
async def sendfile(
|
||||
self,
|
||||
transport: asyncio.BaseTransport,
|
||||
file: IO[bytes],
|
||||
offset: int = ...,
|
||||
count: Optional[int] = ...,
|
||||
*,
|
||||
fallback: bool = ...,
|
||||
) -> int: ...
|
||||
async def sock_sendfile(
|
||||
self,
|
||||
sock: socket,
|
||||
file: IO[bytes],
|
||||
offset: int = ...,
|
||||
count: Optional[int] = ...,
|
||||
*,
|
||||
fallback: bool = ...
|
||||
) -> int: ...
|
3424
env/lib/python3.11/site-packages/uvloop/loop.pyx
vendored
Normal file
3424
env/lib/python3.11/site-packages/uvloop/loop.pyx
vendored
Normal file
File diff suppressed because it is too large
Load Diff
79
env/lib/python3.11/site-packages/uvloop/lru.pyx
vendored
Normal file
79
env/lib/python3.11/site-packages/uvloop/lru.pyx
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
cdef object _LRU_MARKER = object()
|
||||
|
||||
|
||||
@cython.final
|
||||
cdef class LruCache:
|
||||
|
||||
cdef:
|
||||
object _dict
|
||||
int _maxsize
|
||||
object _dict_move_to_end
|
||||
object _dict_get
|
||||
|
||||
# We use an OrderedDict for LRU implementation. Operations:
|
||||
#
|
||||
# * We use a simple `__setitem__` to push a new entry:
|
||||
# `entries[key] = new_entry`
|
||||
# That will push `new_entry` to the *end* of the entries dict.
|
||||
#
|
||||
# * When we have a cache hit, we call
|
||||
# `entries.move_to_end(key, last=True)`
|
||||
# to move the entry to the *end* of the entries dict.
|
||||
#
|
||||
# * When we need to remove entries to maintain `max_size`, we call
|
||||
# `entries.popitem(last=False)`
|
||||
# to remove an entry from the *beginning* of the entries dict.
|
||||
#
|
||||
# So new entries and hits are always promoted to the end of the
|
||||
# entries dict, whereas the unused one will group in the
|
||||
# beginning of it.
|
||||
|
||||
def __init__(self, *, maxsize):
|
||||
if maxsize <= 0:
|
||||
raise ValueError(
|
||||
f'maxsize is expected to be greater than 0, got {maxsize}')
|
||||
|
||||
self._dict = col_OrderedDict()
|
||||
self._dict_move_to_end = self._dict.move_to_end
|
||||
self._dict_get = self._dict.get
|
||||
self._maxsize = maxsize
|
||||
|
||||
cdef get(self, key, default):
|
||||
o = self._dict_get(key, _LRU_MARKER)
|
||||
if o is _LRU_MARKER:
|
||||
return default
|
||||
self._dict_move_to_end(key) # last=True
|
||||
return o
|
||||
|
||||
cdef inline needs_cleanup(self):
|
||||
return len(self._dict) > self._maxsize
|
||||
|
||||
cdef inline cleanup_one(self):
|
||||
k, _ = self._dict.popitem(last=False)
|
||||
return k
|
||||
|
||||
def __getitem__(self, key):
|
||||
o = self._dict[key]
|
||||
self._dict_move_to_end(key) # last=True
|
||||
return o
|
||||
|
||||
def __setitem__(self, key, o):
|
||||
if key in self._dict:
|
||||
self._dict[key] = o
|
||||
self._dict_move_to_end(key) # last=True
|
||||
else:
|
||||
self._dict[key] = o
|
||||
while self.needs_cleanup():
|
||||
self.cleanup_one()
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._dict[key]
|
||||
|
||||
def __contains__(self, key):
|
||||
return key in self._dict
|
||||
|
||||
def __len__(self):
|
||||
return len(self._dict)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._dict)
|
209
env/lib/python3.11/site-packages/uvloop/pseudosock.pyx
vendored
Normal file
209
env/lib/python3.11/site-packages/uvloop/pseudosock.pyx
vendored
Normal file
@ -0,0 +1,209 @@
|
||||
cdef class PseudoSocket:
|
||||
cdef:
|
||||
int _family
|
||||
int _type
|
||||
int _proto
|
||||
int _fd
|
||||
object _peername
|
||||
object _sockname
|
||||
|
||||
def __init__(self, int family, int type, int proto, int fd):
|
||||
self._family = family
|
||||
self._type = type
|
||||
self._proto = proto
|
||||
self._fd = fd
|
||||
self._peername = None
|
||||
self._sockname = None
|
||||
|
||||
cdef _na(self, what):
|
||||
raise TypeError('transport sockets do not support {}'.format(what))
|
||||
|
||||
cdef _make_sock(self):
|
||||
return socket_socket(self._family, self._type, self._proto, self._fd)
|
||||
|
||||
property family:
|
||||
def __get__(self):
|
||||
try:
|
||||
return socket_AddressFamily(self._family)
|
||||
except ValueError:
|
||||
return self._family
|
||||
|
||||
property type:
|
||||
def __get__(self):
|
||||
try:
|
||||
return socket_SocketKind(self._type)
|
||||
except ValueError:
|
||||
return self._type
|
||||
|
||||
property proto:
|
||||
def __get__(self):
|
||||
return self._proto
|
||||
|
||||
def __repr__(self):
|
||||
s = ("<uvloop.PseudoSocket fd={}, family={!s}, "
|
||||
"type={!s}, proto={}").format(self.fileno(), self.family.name,
|
||||
self.type.name, self.proto)
|
||||
|
||||
if self._fd != -1:
|
||||
try:
|
||||
laddr = self.getsockname()
|
||||
if laddr:
|
||||
s += ", laddr=%s" % str(laddr)
|
||||
except socket_error:
|
||||
pass
|
||||
try:
|
||||
raddr = self.getpeername()
|
||||
if raddr:
|
||||
s += ", raddr=%s" % str(raddr)
|
||||
except socket_error:
|
||||
pass
|
||||
s += '>'
|
||||
return s
|
||||
|
||||
def __getstate__(self):
|
||||
raise TypeError("Cannot serialize socket object")
|
||||
|
||||
def fileno(self):
|
||||
return self._fd
|
||||
|
||||
def dup(self):
|
||||
fd = os_dup(self._fd)
|
||||
sock = socket_socket(self._family, self._type, self._proto, fileno=fd)
|
||||
sock.settimeout(0)
|
||||
return sock
|
||||
|
||||
def get_inheritable(self):
|
||||
return os_get_inheritable(self._fd)
|
||||
|
||||
def set_inheritable(self):
|
||||
os_set_inheritable(self._fd)
|
||||
|
||||
def ioctl(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def getsockopt(self, *args, **kwargs):
|
||||
sock = self._make_sock()
|
||||
try:
|
||||
return sock.getsockopt(*args, **kwargs)
|
||||
finally:
|
||||
sock.detach()
|
||||
|
||||
def setsockopt(self, *args, **kwargs):
|
||||
sock = self._make_sock()
|
||||
try:
|
||||
return sock.setsockopt(*args, **kwargs)
|
||||
finally:
|
||||
sock.detach()
|
||||
|
||||
def getpeername(self):
|
||||
if self._peername is not None:
|
||||
return self._peername
|
||||
|
||||
sock = self._make_sock()
|
||||
try:
|
||||
self._peername = sock.getpeername()
|
||||
return self._peername
|
||||
finally:
|
||||
sock.detach()
|
||||
|
||||
def getsockname(self):
|
||||
if self._sockname is not None:
|
||||
return self._sockname
|
||||
|
||||
sock = self._make_sock()
|
||||
try:
|
||||
self._sockname = sock.getsockname()
|
||||
return self._sockname
|
||||
finally:
|
||||
sock.detach()
|
||||
|
||||
def share(self, process_id):
|
||||
sock = self._make_sock()
|
||||
try:
|
||||
return sock.share(process_id)
|
||||
finally:
|
||||
sock.detach()
|
||||
|
||||
def accept(self):
|
||||
self._na('accept() method')
|
||||
|
||||
def connect(self, *args):
|
||||
self._na('connect() method')
|
||||
|
||||
def connect_ex(self, *args):
|
||||
self._na('connect_ex() method')
|
||||
|
||||
def bind(self, *args):
|
||||
self._na('bind() method')
|
||||
|
||||
def listen(self, *args, **kwargs):
|
||||
self._na('listen() method')
|
||||
|
||||
def makefile(self):
|
||||
self._na('makefile() method')
|
||||
|
||||
def sendfile(self, *args, **kwargs):
|
||||
self._na('sendfile() method')
|
||||
|
||||
def close(self):
|
||||
self._na('close() method')
|
||||
|
||||
def detach(self):
|
||||
self._na('detach() method')
|
||||
|
||||
def shutdown(self, *args):
|
||||
self._na('shutdown() method')
|
||||
|
||||
def sendmsg_afalg(self, *args, **kwargs):
|
||||
self._na('sendmsg_afalg() method')
|
||||
|
||||
def sendmsg(self):
|
||||
self._na('sendmsg() method')
|
||||
|
||||
def sendto(self, *args, **kwargs):
|
||||
self._na('sendto() method')
|
||||
|
||||
def send(self, *args, **kwargs):
|
||||
self._na('send() method')
|
||||
|
||||
def sendall(self, *args, **kwargs):
|
||||
self._na('sendall() method')
|
||||
|
||||
def recv_into(self, *args, **kwargs):
|
||||
self._na('recv_into() method')
|
||||
|
||||
def recvfrom_into(self, *args, **kwargs):
|
||||
self._na('recvfrom_into() method')
|
||||
|
||||
def recvmsg_into(self, *args, **kwargs):
|
||||
self._na('recvmsg_into() method')
|
||||
|
||||
def recvmsg(self, *args, **kwargs):
|
||||
self._na('recvmsg() method')
|
||||
|
||||
def recvfrom(self, *args, **kwargs):
|
||||
self._na('recvfrom() method')
|
||||
|
||||
def recv(self, *args, **kwargs):
|
||||
self._na('recv() method')
|
||||
|
||||
def settimeout(self, value):
|
||||
if value == 0:
|
||||
return
|
||||
raise ValueError(
|
||||
'settimeout(): only 0 timeout is allowed on transport sockets')
|
||||
|
||||
def gettimeout(self):
|
||||
return 0
|
||||
|
||||
def setblocking(self, flag):
|
||||
if not flag:
|
||||
return
|
||||
raise ValueError(
|
||||
'setblocking(): transport sockets cannot be blocking')
|
||||
|
||||
def __enter__(self):
|
||||
self._na('context manager protocol')
|
||||
|
||||
def __exit__(self, *err):
|
||||
self._na('context manager protocol')
|
0
env/lib/python3.11/site-packages/uvloop/py.typed
vendored
Normal file
0
env/lib/python3.11/site-packages/uvloop/py.typed
vendored
Normal file
8
env/lib/python3.11/site-packages/uvloop/request.pxd
vendored
Normal file
8
env/lib/python3.11/site-packages/uvloop/request.pxd
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
cdef class UVRequest:
|
||||
cdef:
|
||||
uv.uv_req_t *request
|
||||
bint done
|
||||
Loop loop
|
||||
|
||||
cdef on_done(self)
|
||||
cdef cancel(self)
|
65
env/lib/python3.11/site-packages/uvloop/request.pyx
vendored
Normal file
65
env/lib/python3.11/site-packages/uvloop/request.pyx
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
cdef class UVRequest:
|
||||
"""A base class for all libuv requests (uv_getaddrinfo_t, etc).
|
||||
|
||||
Important: it's a responsibility of the subclass to call the
|
||||
"on_done" method in the request's callback.
|
||||
|
||||
If "on_done" isn't called, the request object will never die.
|
||||
"""
|
||||
|
||||
def __cinit__(self, Loop loop, *_):
|
||||
self.request = NULL
|
||||
self.loop = loop
|
||||
self.done = 0
|
||||
Py_INCREF(self)
|
||||
|
||||
cdef on_done(self):
|
||||
self.done = 1
|
||||
Py_DECREF(self)
|
||||
|
||||
cdef cancel(self):
|
||||
# Most requests are implemented using a threadpool. It's only
|
||||
# possible to cancel a request when it's still in a threadpool's
|
||||
# queue. Once it's started to execute, we have to wait until
|
||||
# it finishes and calls its callback (and callback *must* call
|
||||
# UVRequest.on_done).
|
||||
|
||||
cdef int err
|
||||
|
||||
if self.done == 1:
|
||||
return
|
||||
|
||||
if UVLOOP_DEBUG:
|
||||
if self.request is NULL:
|
||||
raise RuntimeError(
|
||||
'{}.cancel: .request is NULL'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
if self.request.data is NULL:
|
||||
raise RuntimeError(
|
||||
'{}.cancel: .request.data is NULL'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
if <UVRequest>self.request.data is not self:
|
||||
raise RuntimeError(
|
||||
'{}.cancel: .request.data is not UVRequest'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
# We only can cancel pending requests. Let's try.
|
||||
err = uv.uv_cancel(self.request)
|
||||
if err < 0:
|
||||
if err == uv.UV_EBUSY:
|
||||
# Can't close the request -- it's executing (see the first
|
||||
# comment). Loop will have to wait until the callback
|
||||
# fires.
|
||||
pass
|
||||
elif err == uv.UV_EINVAL:
|
||||
# From libuv docs:
|
||||
#
|
||||
# Only cancellation of uv_fs_t, uv_getaddrinfo_t,
|
||||
# uv_getnameinfo_t and uv_work_t requests is currently
|
||||
# supported.
|
||||
return
|
||||
else:
|
||||
ex = convert_error(err)
|
||||
self.loop._handle_exception(ex)
|
19
env/lib/python3.11/site-packages/uvloop/server.pxd
vendored
Normal file
19
env/lib/python3.11/site-packages/uvloop/server.pxd
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
cdef class Server:
|
||||
cdef:
|
||||
list _servers
|
||||
list _waiters
|
||||
int _active_count
|
||||
Loop _loop
|
||||
bint _serving
|
||||
object _serving_forever_fut
|
||||
object __weakref__
|
||||
|
||||
cdef _add_server(self, UVStreamServer srv)
|
||||
cdef _start_serving(self)
|
||||
cdef _wakeup(self)
|
||||
|
||||
cdef _attach(self)
|
||||
cdef _detach(self)
|
||||
|
||||
cdef _ref(self)
|
||||
cdef _unref(self)
|
136
env/lib/python3.11/site-packages/uvloop/server.pyx
vendored
Normal file
136
env/lib/python3.11/site-packages/uvloop/server.pyx
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
import asyncio
|
||||
|
||||
|
||||
cdef class Server:
|
||||
def __cinit__(self, Loop loop):
|
||||
self._loop = loop
|
||||
self._servers = []
|
||||
self._waiters = []
|
||||
self._active_count = 0
|
||||
self._serving_forever_fut = None
|
||||
|
||||
cdef _add_server(self, UVStreamServer srv):
|
||||
self._servers.append(srv)
|
||||
|
||||
cdef _start_serving(self):
|
||||
if self._serving:
|
||||
return
|
||||
|
||||
self._serving = 1
|
||||
for server in self._servers:
|
||||
(<UVStreamServer>server).listen()
|
||||
|
||||
cdef _wakeup(self):
|
||||
cdef list waiters
|
||||
|
||||
waiters = self._waiters
|
||||
self._waiters = None
|
||||
for waiter in waiters:
|
||||
if not waiter.done():
|
||||
waiter.set_result(waiter)
|
||||
|
||||
cdef _attach(self):
|
||||
assert self._servers is not None
|
||||
self._active_count += 1
|
||||
|
||||
cdef _detach(self):
|
||||
assert self._active_count > 0
|
||||
self._active_count -= 1
|
||||
if self._active_count == 0 and self._servers is None:
|
||||
self._wakeup()
|
||||
|
||||
cdef _ref(self):
|
||||
# Keep the server object alive while it's not explicitly closed.
|
||||
self._loop._servers.add(self)
|
||||
|
||||
cdef _unref(self):
|
||||
self._loop._servers.discard(self)
|
||||
|
||||
# Public API
|
||||
|
||||
@cython.iterable_coroutine
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
@cython.iterable_coroutine
|
||||
async def __aexit__(self, *exc):
|
||||
self.close()
|
||||
await self.wait_closed()
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s sockets=%r>' % (self.__class__.__name__, self.sockets)
|
||||
|
||||
def get_loop(self):
|
||||
return self._loop
|
||||
|
||||
@cython.iterable_coroutine
|
||||
async def wait_closed(self):
|
||||
# Do not remove `self._servers is None` below
|
||||
# because close() method only closes server sockets
|
||||
# and existing client connections are left open.
|
||||
if self._servers is None or self._waiters is None:
|
||||
return
|
||||
waiter = self._loop._new_future()
|
||||
self._waiters.append(waiter)
|
||||
await waiter
|
||||
|
||||
def close(self):
|
||||
cdef list servers
|
||||
|
||||
if self._servers is None:
|
||||
return
|
||||
|
||||
try:
|
||||
servers = self._servers
|
||||
self._servers = None
|
||||
self._serving = 0
|
||||
|
||||
for server in servers:
|
||||
(<UVStreamServer>server)._close()
|
||||
|
||||
if self._active_count == 0:
|
||||
self._wakeup()
|
||||
finally:
|
||||
self._unref()
|
||||
|
||||
def is_serving(self):
|
||||
return self._serving
|
||||
|
||||
@cython.iterable_coroutine
|
||||
async def start_serving(self):
|
||||
self._start_serving()
|
||||
|
||||
@cython.iterable_coroutine
|
||||
async def serve_forever(self):
|
||||
if self._serving_forever_fut is not None:
|
||||
raise RuntimeError(
|
||||
f'server {self!r} is already being awaited on serve_forever()')
|
||||
if self._servers is None:
|
||||
raise RuntimeError(f'server {self!r} is closed')
|
||||
|
||||
self._start_serving()
|
||||
self._serving_forever_fut = self._loop.create_future()
|
||||
|
||||
try:
|
||||
await self._serving_forever_fut
|
||||
except asyncio.CancelledError:
|
||||
try:
|
||||
self.close()
|
||||
await self.wait_closed()
|
||||
finally:
|
||||
raise
|
||||
finally:
|
||||
self._serving_forever_fut = None
|
||||
|
||||
property sockets:
|
||||
def __get__(self):
|
||||
cdef list sockets = []
|
||||
|
||||
# Guard against `self._servers is None`
|
||||
if self._servers:
|
||||
for server in self._servers:
|
||||
sockets.append(
|
||||
(<UVStreamServer>server)._get_socket()
|
||||
)
|
||||
|
||||
return sockets
|
138
env/lib/python3.11/site-packages/uvloop/sslproto.pxd
vendored
Normal file
138
env/lib/python3.11/site-packages/uvloop/sslproto.pxd
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
cdef enum SSLProtocolState:
|
||||
UNWRAPPED = 0
|
||||
DO_HANDSHAKE = 1
|
||||
WRAPPED = 2
|
||||
FLUSHING = 3
|
||||
SHUTDOWN = 4
|
||||
|
||||
|
||||
cdef enum AppProtocolState:
|
||||
# This tracks the state of app protocol (https://git.io/fj59P):
|
||||
#
|
||||
# INIT -cm-> CON_MADE [-dr*->] [-er-> EOF?] -cl-> CON_LOST
|
||||
#
|
||||
# * cm: connection_made()
|
||||
# * dr: data_received()
|
||||
# * er: eof_received()
|
||||
# * cl: connection_lost()
|
||||
|
||||
STATE_INIT = 0
|
||||
STATE_CON_MADE = 1
|
||||
STATE_EOF = 2
|
||||
STATE_CON_LOST = 3
|
||||
|
||||
|
||||
cdef class _SSLProtocolTransport:
|
||||
cdef:
|
||||
Loop _loop
|
||||
SSLProtocol _ssl_protocol
|
||||
bint _closed
|
||||
object context
|
||||
|
||||
|
||||
cdef class SSLProtocol:
|
||||
cdef:
|
||||
bint _server_side
|
||||
str _server_hostname
|
||||
object _sslcontext
|
||||
|
||||
object _extra
|
||||
|
||||
object _write_backlog
|
||||
size_t _write_buffer_size
|
||||
|
||||
object _waiter
|
||||
Loop _loop
|
||||
_SSLProtocolTransport _app_transport
|
||||
bint _app_transport_created
|
||||
|
||||
object _transport
|
||||
object _ssl_handshake_timeout
|
||||
object _ssl_shutdown_timeout
|
||||
|
||||
object _sslobj
|
||||
object _sslobj_read
|
||||
object _sslobj_write
|
||||
object _incoming
|
||||
object _incoming_write
|
||||
object _outgoing
|
||||
object _outgoing_read
|
||||
char* _ssl_buffer
|
||||
size_t _ssl_buffer_len
|
||||
object _ssl_buffer_view
|
||||
SSLProtocolState _state
|
||||
size_t _conn_lost
|
||||
AppProtocolState _app_state
|
||||
|
||||
bint _ssl_writing_paused
|
||||
bint _app_reading_paused
|
||||
|
||||
size_t _incoming_high_water
|
||||
size_t _incoming_low_water
|
||||
bint _ssl_reading_paused
|
||||
|
||||
bint _app_writing_paused
|
||||
size_t _outgoing_high_water
|
||||
size_t _outgoing_low_water
|
||||
|
||||
object _app_protocol
|
||||
bint _app_protocol_is_buffer
|
||||
object _app_protocol_get_buffer
|
||||
object _app_protocol_buffer_updated
|
||||
|
||||
object _handshake_start_time
|
||||
object _handshake_timeout_handle
|
||||
object _shutdown_timeout_handle
|
||||
|
||||
cdef _set_app_protocol(self, app_protocol)
|
||||
cdef _wakeup_waiter(self, exc=*)
|
||||
cdef _get_extra_info(self, name, default=*)
|
||||
cdef _set_state(self, SSLProtocolState new_state)
|
||||
|
||||
# Handshake flow
|
||||
|
||||
cdef _start_handshake(self)
|
||||
cdef _check_handshake_timeout(self)
|
||||
cdef _do_handshake(self)
|
||||
cdef _on_handshake_complete(self, handshake_exc)
|
||||
|
||||
# Shutdown flow
|
||||
|
||||
cdef _start_shutdown(self, object context=*)
|
||||
cdef _check_shutdown_timeout(self)
|
||||
cdef _do_read_into_void(self, object context)
|
||||
cdef _do_flush(self, object context=*)
|
||||
cdef _do_shutdown(self, object context=*)
|
||||
cdef _on_shutdown_complete(self, shutdown_exc)
|
||||
cdef _abort(self, exc)
|
||||
|
||||
# Outgoing flow
|
||||
|
||||
cdef _write_appdata(self, list_of_data, object context)
|
||||
cdef _do_write(self)
|
||||
cdef _process_outgoing(self)
|
||||
|
||||
# Incoming flow
|
||||
|
||||
cdef _do_read(self)
|
||||
cdef _do_read__buffered(self)
|
||||
cdef _do_read__copied(self)
|
||||
cdef _call_eof_received(self, object context=*)
|
||||
|
||||
# Flow control for writes from APP socket
|
||||
|
||||
cdef _control_app_writing(self, object context=*)
|
||||
cdef size_t _get_write_buffer_size(self)
|
||||
cdef _set_write_buffer_limits(self, high=*, low=*)
|
||||
|
||||
# Flow control for reads to APP socket
|
||||
|
||||
cdef _pause_reading(self)
|
||||
cdef _resume_reading(self, object context)
|
||||
|
||||
# Flow control for reads from SSL socket
|
||||
|
||||
cdef _control_ssl_reading(self)
|
||||
cdef _set_read_buffer_limits(self, high=*, low=*)
|
||||
cdef size_t _get_read_buffer_size(self)
|
||||
cdef _fatal_error(self, exc, message=*)
|
950
env/lib/python3.11/site-packages/uvloop/sslproto.pyx
vendored
Normal file
950
env/lib/python3.11/site-packages/uvloop/sslproto.pyx
vendored
Normal file
@ -0,0 +1,950 @@
|
||||
cdef _create_transport_context(server_side, server_hostname):
|
||||
if server_side:
|
||||
raise ValueError('Server side SSL needs a valid SSLContext')
|
||||
|
||||
# Client side may pass ssl=True to use a default
|
||||
# context; in that case the sslcontext passed is None.
|
||||
# The default is secure for client connections.
|
||||
# Python 3.4+: use up-to-date strong settings.
|
||||
sslcontext = ssl_create_default_context()
|
||||
if not server_hostname:
|
||||
sslcontext.check_hostname = False
|
||||
return sslcontext
|
||||
|
||||
|
||||
cdef class _SSLProtocolTransport:
|
||||
|
||||
# TODO:
|
||||
# _sendfile_compatible = constants._SendfileMode.FALLBACK
|
||||
|
||||
def __cinit__(self, Loop loop, ssl_protocol, context):
|
||||
self._loop = loop
|
||||
# SSLProtocol instance
|
||||
self._ssl_protocol = ssl_protocol
|
||||
self._closed = False
|
||||
if context is None:
|
||||
context = Context_CopyCurrent()
|
||||
self.context = context
|
||||
|
||||
def get_extra_info(self, name, default=None):
|
||||
"""Get optional transport information."""
|
||||
return self._ssl_protocol._get_extra_info(name, default)
|
||||
|
||||
def set_protocol(self, protocol):
|
||||
self._ssl_protocol._set_app_protocol(protocol)
|
||||
|
||||
def get_protocol(self):
|
||||
return self._ssl_protocol._app_protocol
|
||||
|
||||
def is_closing(self):
|
||||
return self._closed
|
||||
|
||||
def close(self):
|
||||
"""Close the transport.
|
||||
|
||||
Buffered data will be flushed asynchronously. No more data
|
||||
will be received. After all buffered data is flushed, the
|
||||
protocol's connection_lost() method will (eventually) called
|
||||
with None as its argument.
|
||||
"""
|
||||
self._closed = True
|
||||
self._ssl_protocol._start_shutdown(self.context.copy())
|
||||
|
||||
def __dealloc__(self):
|
||||
if not self._closed:
|
||||
self._closed = True
|
||||
warnings_warn(
|
||||
"unclosed transport <uvloop.loop._SSLProtocolTransport "
|
||||
"object>", ResourceWarning)
|
||||
|
||||
def is_reading(self):
|
||||
return not self._ssl_protocol._app_reading_paused
|
||||
|
||||
def pause_reading(self):
|
||||
"""Pause the receiving end.
|
||||
|
||||
No data will be passed to the protocol's data_received()
|
||||
method until resume_reading() is called.
|
||||
"""
|
||||
self._ssl_protocol._pause_reading()
|
||||
|
||||
def resume_reading(self):
|
||||
"""Resume the receiving end.
|
||||
|
||||
Data received will once again be passed to the protocol's
|
||||
data_received() method.
|
||||
"""
|
||||
self._ssl_protocol._resume_reading(self.context.copy())
|
||||
|
||||
def set_write_buffer_limits(self, high=None, low=None):
|
||||
"""Set the high- and low-water limits for write flow control.
|
||||
|
||||
These two values control when to call the protocol's
|
||||
pause_writing() and resume_writing() methods. If specified,
|
||||
the low-water limit must be less than or equal to the
|
||||
high-water limit. Neither value can be negative.
|
||||
|
||||
The defaults are implementation-specific. If only the
|
||||
high-water limit is given, the low-water limit defaults to an
|
||||
implementation-specific value less than or equal to the
|
||||
high-water limit. Setting high to zero forces low to zero as
|
||||
well, and causes pause_writing() to be called whenever the
|
||||
buffer becomes non-empty. Setting low to zero causes
|
||||
resume_writing() to be called only once the buffer is empty.
|
||||
Use of zero for either limit is generally sub-optimal as it
|
||||
reduces opportunities for doing I/O and computation
|
||||
concurrently.
|
||||
"""
|
||||
self._ssl_protocol._set_write_buffer_limits(high, low)
|
||||
self._ssl_protocol._control_app_writing(self.context.copy())
|
||||
|
||||
def get_write_buffer_limits(self):
|
||||
return (self._ssl_protocol._outgoing_low_water,
|
||||
self._ssl_protocol._outgoing_high_water)
|
||||
|
||||
def get_write_buffer_size(self):
|
||||
"""Return the current size of the write buffers."""
|
||||
return self._ssl_protocol._get_write_buffer_size()
|
||||
|
||||
def set_read_buffer_limits(self, high=None, low=None):
|
||||
"""Set the high- and low-water limits for read flow control.
|
||||
|
||||
These two values control when to call the upstream transport's
|
||||
pause_reading() and resume_reading() methods. If specified,
|
||||
the low-water limit must be less than or equal to the
|
||||
high-water limit. Neither value can be negative.
|
||||
|
||||
The defaults are implementation-specific. If only the
|
||||
high-water limit is given, the low-water limit defaults to an
|
||||
implementation-specific value less than or equal to the
|
||||
high-water limit. Setting high to zero forces low to zero as
|
||||
well, and causes pause_reading() to be called whenever the
|
||||
buffer becomes non-empty. Setting low to zero causes
|
||||
resume_reading() to be called only once the buffer is empty.
|
||||
Use of zero for either limit is generally sub-optimal as it
|
||||
reduces opportunities for doing I/O and computation
|
||||
concurrently.
|
||||
"""
|
||||
self._ssl_protocol._set_read_buffer_limits(high, low)
|
||||
self._ssl_protocol._control_ssl_reading()
|
||||
|
||||
def get_read_buffer_limits(self):
|
||||
return (self._ssl_protocol._incoming_low_water,
|
||||
self._ssl_protocol._incoming_high_water)
|
||||
|
||||
def get_read_buffer_size(self):
|
||||
"""Return the current size of the read buffer."""
|
||||
return self._ssl_protocol._get_read_buffer_size()
|
||||
|
||||
@property
|
||||
def _protocol_paused(self):
|
||||
# Required for sendfile fallback pause_writing/resume_writing logic
|
||||
return self._ssl_protocol._app_writing_paused
|
||||
|
||||
def write(self, data):
|
||||
"""Write some data bytes to the transport.
|
||||
|
||||
This does not block; it buffers the data and arranges for it
|
||||
to be sent out asynchronously.
|
||||
"""
|
||||
if not isinstance(data, (bytes, bytearray, memoryview)):
|
||||
raise TypeError(f"data: expecting a bytes-like instance, "
|
||||
f"got {type(data).__name__}")
|
||||
if not data:
|
||||
return
|
||||
self._ssl_protocol._write_appdata((data,), self.context.copy())
|
||||
|
||||
def writelines(self, list_of_data):
|
||||
"""Write a list (or any iterable) of data bytes to the transport.
|
||||
|
||||
The default implementation concatenates the arguments and
|
||||
calls write() on the result.
|
||||
"""
|
||||
self._ssl_protocol._write_appdata(list_of_data, self.context.copy())
|
||||
|
||||
def write_eof(self):
|
||||
"""Close the write end after flushing buffered data.
|
||||
|
||||
This raises :exc:`NotImplementedError` right now.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def can_write_eof(self):
|
||||
"""Return True if this transport supports write_eof(), False if not."""
|
||||
return False
|
||||
|
||||
def abort(self):
|
||||
"""Close the transport immediately.
|
||||
|
||||
Buffered data will be lost. No more data will be received.
|
||||
The protocol's connection_lost() method will (eventually) be
|
||||
called with None as its argument.
|
||||
"""
|
||||
self._force_close(None)
|
||||
|
||||
def _force_close(self, exc):
|
||||
self._closed = True
|
||||
self._ssl_protocol._abort(exc)
|
||||
|
||||
def _test__append_write_backlog(self, data):
|
||||
# for test only
|
||||
self._ssl_protocol._write_backlog.append(data)
|
||||
self._ssl_protocol._write_buffer_size += len(data)
|
||||
|
||||
|
||||
cdef class SSLProtocol:
|
||||
"""SSL protocol.
|
||||
|
||||
Implementation of SSL on top of a socket using incoming and outgoing
|
||||
buffers which are ssl.MemoryBIO objects.
|
||||
"""
|
||||
|
||||
def __cinit__(self, *args, **kwargs):
|
||||
self._ssl_buffer_len = SSL_READ_MAX_SIZE
|
||||
self._ssl_buffer = <char*>PyMem_RawMalloc(self._ssl_buffer_len)
|
||||
if not self._ssl_buffer:
|
||||
raise MemoryError()
|
||||
self._ssl_buffer_view = PyMemoryView_FromMemory(
|
||||
self._ssl_buffer, self._ssl_buffer_len, PyBUF_WRITE)
|
||||
|
||||
def __dealloc__(self):
|
||||
self._ssl_buffer_view = None
|
||||
PyMem_RawFree(self._ssl_buffer)
|
||||
self._ssl_buffer = NULL
|
||||
self._ssl_buffer_len = 0
|
||||
|
||||
def __init__(self, loop, app_protocol, sslcontext, waiter,
|
||||
server_side=False, server_hostname=None,
|
||||
call_connection_made=True,
|
||||
ssl_handshake_timeout=None,
|
||||
ssl_shutdown_timeout=None):
|
||||
if ssl_handshake_timeout is None:
|
||||
ssl_handshake_timeout = SSL_HANDSHAKE_TIMEOUT
|
||||
elif ssl_handshake_timeout <= 0:
|
||||
raise ValueError(
|
||||
f"ssl_handshake_timeout should be a positive number, "
|
||||
f"got {ssl_handshake_timeout}")
|
||||
if ssl_shutdown_timeout is None:
|
||||
ssl_shutdown_timeout = SSL_SHUTDOWN_TIMEOUT
|
||||
elif ssl_shutdown_timeout <= 0:
|
||||
raise ValueError(
|
||||
f"ssl_shutdown_timeout should be a positive number, "
|
||||
f"got {ssl_shutdown_timeout}")
|
||||
|
||||
if not sslcontext:
|
||||
sslcontext = _create_transport_context(
|
||||
server_side, server_hostname)
|
||||
|
||||
self._server_side = server_side
|
||||
if server_hostname and not server_side:
|
||||
self._server_hostname = server_hostname
|
||||
else:
|
||||
self._server_hostname = None
|
||||
self._sslcontext = sslcontext
|
||||
# SSL-specific extra info. More info are set when the handshake
|
||||
# completes.
|
||||
self._extra = dict(sslcontext=sslcontext)
|
||||
|
||||
# App data write buffering
|
||||
self._write_backlog = col_deque()
|
||||
self._write_buffer_size = 0
|
||||
|
||||
self._waiter = waiter
|
||||
self._loop = loop
|
||||
self._set_app_protocol(app_protocol)
|
||||
self._app_transport = None
|
||||
self._app_transport_created = False
|
||||
# transport, ex: SelectorSocketTransport
|
||||
self._transport = None
|
||||
self._ssl_handshake_timeout = ssl_handshake_timeout
|
||||
self._ssl_shutdown_timeout = ssl_shutdown_timeout
|
||||
# SSL and state machine
|
||||
self._sslobj = None
|
||||
self._incoming = ssl_MemoryBIO()
|
||||
self._incoming_write = self._incoming.write
|
||||
self._outgoing = ssl_MemoryBIO()
|
||||
self._outgoing_read = self._outgoing.read
|
||||
self._state = UNWRAPPED
|
||||
self._conn_lost = 0 # Set when connection_lost called
|
||||
if call_connection_made:
|
||||
self._app_state = STATE_INIT
|
||||
else:
|
||||
self._app_state = STATE_CON_MADE
|
||||
|
||||
# Flow Control
|
||||
|
||||
self._ssl_writing_paused = False
|
||||
|
||||
self._app_reading_paused = False
|
||||
|
||||
self._ssl_reading_paused = False
|
||||
self._incoming_high_water = 0
|
||||
self._incoming_low_water = 0
|
||||
self._set_read_buffer_limits()
|
||||
|
||||
self._app_writing_paused = False
|
||||
self._outgoing_high_water = 0
|
||||
self._outgoing_low_water = 0
|
||||
self._set_write_buffer_limits()
|
||||
|
||||
cdef _set_app_protocol(self, app_protocol):
|
||||
self._app_protocol = app_protocol
|
||||
if (hasattr(app_protocol, 'get_buffer') and
|
||||
not isinstance(app_protocol, aio_Protocol)):
|
||||
self._app_protocol_get_buffer = app_protocol.get_buffer
|
||||
self._app_protocol_buffer_updated = app_protocol.buffer_updated
|
||||
self._app_protocol_is_buffer = True
|
||||
else:
|
||||
self._app_protocol_is_buffer = False
|
||||
|
||||
cdef _wakeup_waiter(self, exc=None):
|
||||
if self._waiter is None:
|
||||
return
|
||||
if not self._waiter.cancelled():
|
||||
if exc is not None:
|
||||
self._waiter.set_exception(exc)
|
||||
else:
|
||||
self._waiter.set_result(None)
|
||||
self._waiter = None
|
||||
|
||||
def _get_app_transport(self, context=None):
|
||||
if self._app_transport is None:
|
||||
if self._app_transport_created:
|
||||
raise RuntimeError('Creating _SSLProtocolTransport twice')
|
||||
self._app_transport = _SSLProtocolTransport(self._loop, self,
|
||||
context)
|
||||
self._app_transport_created = True
|
||||
return self._app_transport
|
||||
|
||||
def connection_made(self, transport):
|
||||
"""Called when the low-level connection is made.
|
||||
|
||||
Start the SSL handshake.
|
||||
"""
|
||||
self._transport = transport
|
||||
self._start_handshake()
|
||||
|
||||
def connection_lost(self, exc):
|
||||
"""Called when the low-level connection is lost or closed.
|
||||
|
||||
The argument is an exception object or None (the latter
|
||||
meaning a regular EOF is received or the connection was
|
||||
aborted or closed).
|
||||
"""
|
||||
self._write_backlog.clear()
|
||||
self._outgoing_read()
|
||||
self._conn_lost += 1
|
||||
|
||||
# Just mark the app transport as closed so that its __dealloc__
|
||||
# doesn't complain.
|
||||
if self._app_transport is not None:
|
||||
self._app_transport._closed = True
|
||||
|
||||
if self._state != DO_HANDSHAKE:
|
||||
if self._app_state == STATE_CON_MADE or \
|
||||
self._app_state == STATE_EOF:
|
||||
self._app_state = STATE_CON_LOST
|
||||
self._loop.call_soon(self._app_protocol.connection_lost, exc)
|
||||
self._set_state(UNWRAPPED)
|
||||
self._transport = None
|
||||
self._app_transport = None
|
||||
self._app_protocol = None
|
||||
self._wakeup_waiter(exc)
|
||||
|
||||
if self._shutdown_timeout_handle:
|
||||
self._shutdown_timeout_handle.cancel()
|
||||
self._shutdown_timeout_handle = None
|
||||
if self._handshake_timeout_handle:
|
||||
self._handshake_timeout_handle.cancel()
|
||||
self._handshake_timeout_handle = None
|
||||
|
||||
def get_buffer(self, n):
|
||||
cdef size_t want = n
|
||||
if want > SSL_READ_MAX_SIZE:
|
||||
want = SSL_READ_MAX_SIZE
|
||||
if self._ssl_buffer_len < want:
|
||||
self._ssl_buffer = <char*>PyMem_RawRealloc(self._ssl_buffer, want)
|
||||
if not self._ssl_buffer:
|
||||
raise MemoryError()
|
||||
self._ssl_buffer_len = want
|
||||
self._ssl_buffer_view = PyMemoryView_FromMemory(
|
||||
self._ssl_buffer, want, PyBUF_WRITE)
|
||||
return self._ssl_buffer_view
|
||||
|
||||
def buffer_updated(self, nbytes):
|
||||
self._incoming_write(PyMemoryView_FromMemory(
|
||||
self._ssl_buffer, nbytes, PyBUF_WRITE))
|
||||
|
||||
if self._state == DO_HANDSHAKE:
|
||||
self._do_handshake()
|
||||
|
||||
elif self._state == WRAPPED:
|
||||
self._do_read()
|
||||
|
||||
elif self._state == FLUSHING:
|
||||
self._do_flush()
|
||||
|
||||
elif self._state == SHUTDOWN:
|
||||
self._do_shutdown()
|
||||
|
||||
def eof_received(self):
|
||||
"""Called when the other end of the low-level stream
|
||||
is half-closed.
|
||||
|
||||
If this returns a false value (including None), the transport
|
||||
will close itself. If it returns a true value, closing the
|
||||
transport is up to the protocol.
|
||||
"""
|
||||
try:
|
||||
if self._loop.get_debug():
|
||||
aio_logger.debug("%r received EOF", self)
|
||||
|
||||
if self._state == DO_HANDSHAKE:
|
||||
self._on_handshake_complete(ConnectionResetError)
|
||||
|
||||
elif self._state == WRAPPED or self._state == FLUSHING:
|
||||
# We treat a low-level EOF as a critical situation similar to a
|
||||
# broken connection - just send whatever is in the buffer and
|
||||
# close. No application level eof_received() is called -
|
||||
# because we don't want the user to think that this is a
|
||||
# graceful shutdown triggered by SSL "close_notify".
|
||||
self._set_state(SHUTDOWN)
|
||||
self._on_shutdown_complete(None)
|
||||
|
||||
elif self._state == SHUTDOWN:
|
||||
self._on_shutdown_complete(None)
|
||||
|
||||
except Exception:
|
||||
self._transport.close()
|
||||
raise
|
||||
|
||||
cdef _get_extra_info(self, name, default=None):
|
||||
if name == 'uvloop.sslproto':
|
||||
return self
|
||||
elif name in self._extra:
|
||||
return self._extra[name]
|
||||
elif self._transport is not None:
|
||||
return self._transport.get_extra_info(name, default)
|
||||
else:
|
||||
return default
|
||||
|
||||
cdef _set_state(self, SSLProtocolState new_state):
|
||||
cdef bint allowed = False
|
||||
|
||||
if new_state == UNWRAPPED:
|
||||
allowed = True
|
||||
|
||||
elif self._state == UNWRAPPED and new_state == DO_HANDSHAKE:
|
||||
allowed = True
|
||||
|
||||
elif self._state == DO_HANDSHAKE and new_state == WRAPPED:
|
||||
allowed = True
|
||||
|
||||
elif self._state == WRAPPED and new_state == FLUSHING:
|
||||
allowed = True
|
||||
|
||||
elif self._state == WRAPPED and new_state == SHUTDOWN:
|
||||
allowed = True
|
||||
|
||||
elif self._state == FLUSHING and new_state == SHUTDOWN:
|
||||
allowed = True
|
||||
|
||||
if allowed:
|
||||
self._state = new_state
|
||||
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'cannot switch state from {} to {}'.format(
|
||||
self._state, new_state))
|
||||
|
||||
# Handshake flow
|
||||
|
||||
cdef _start_handshake(self):
|
||||
if self._loop.get_debug():
|
||||
aio_logger.debug("%r starts SSL handshake", self)
|
||||
self._handshake_start_time = self._loop.time()
|
||||
else:
|
||||
self._handshake_start_time = None
|
||||
|
||||
self._set_state(DO_HANDSHAKE)
|
||||
|
||||
# start handshake timeout count down
|
||||
self._handshake_timeout_handle = \
|
||||
self._loop.call_later(self._ssl_handshake_timeout,
|
||||
lambda: self._check_handshake_timeout())
|
||||
|
||||
try:
|
||||
self._sslobj = self._sslcontext.wrap_bio(
|
||||
self._incoming, self._outgoing,
|
||||
server_side=self._server_side,
|
||||
server_hostname=self._server_hostname)
|
||||
self._sslobj_read = self._sslobj.read
|
||||
self._sslobj_write = self._sslobj.write
|
||||
except Exception as ex:
|
||||
self._on_handshake_complete(ex)
|
||||
else:
|
||||
self._do_handshake()
|
||||
|
||||
cdef _check_handshake_timeout(self):
|
||||
if self._state == DO_HANDSHAKE:
|
||||
msg = (
|
||||
f"SSL handshake is taking longer than "
|
||||
f"{self._ssl_handshake_timeout} seconds: "
|
||||
f"aborting the connection"
|
||||
)
|
||||
self._fatal_error(ConnectionAbortedError(msg))
|
||||
|
||||
cdef _do_handshake(self):
|
||||
try:
|
||||
self._sslobj.do_handshake()
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
self._process_outgoing()
|
||||
except ssl_SSLError as exc:
|
||||
self._on_handshake_complete(exc)
|
||||
else:
|
||||
self._on_handshake_complete(None)
|
||||
|
||||
cdef _on_handshake_complete(self, handshake_exc):
|
||||
if self._handshake_timeout_handle is not None:
|
||||
self._handshake_timeout_handle.cancel()
|
||||
self._handshake_timeout_handle = None
|
||||
|
||||
sslobj = self._sslobj
|
||||
try:
|
||||
if handshake_exc is None:
|
||||
self._set_state(WRAPPED)
|
||||
else:
|
||||
raise handshake_exc
|
||||
|
||||
peercert = sslobj.getpeercert()
|
||||
except Exception as exc:
|
||||
self._set_state(UNWRAPPED)
|
||||
if isinstance(exc, ssl_CertificateError):
|
||||
msg = 'SSL handshake failed on verifying the certificate'
|
||||
else:
|
||||
msg = 'SSL handshake failed'
|
||||
self._fatal_error(exc, msg)
|
||||
self._wakeup_waiter(exc)
|
||||
return
|
||||
|
||||
if self._loop.get_debug():
|
||||
dt = self._loop.time() - self._handshake_start_time
|
||||
aio_logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
|
||||
|
||||
# Add extra info that becomes available after handshake.
|
||||
self._extra.update(peercert=peercert,
|
||||
cipher=sslobj.cipher(),
|
||||
compression=sslobj.compression(),
|
||||
ssl_object=sslobj)
|
||||
if self._app_state == STATE_INIT:
|
||||
self._app_state = STATE_CON_MADE
|
||||
self._app_protocol.connection_made(self._get_app_transport())
|
||||
self._wakeup_waiter()
|
||||
|
||||
# We should wakeup user code before sending the first data below. In
|
||||
# case of `start_tls()`, the user can only get the SSLTransport in the
|
||||
# wakeup callback, because `connection_made()` is not called again.
|
||||
# We should schedule the first data later than the wakeup callback so
|
||||
# that the user get a chance to e.g. check ALPN with the transport
|
||||
# before having to handle the first data.
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle(self._loop,
|
||||
"SSLProtocol._do_read",
|
||||
<method_t> self._do_read,
|
||||
None, # current context is good
|
||||
self))
|
||||
|
||||
# Shutdown flow
|
||||
|
||||
cdef _start_shutdown(self, object context=None):
|
||||
if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
|
||||
return
|
||||
# we don't need the context for _abort or the timeout, because
|
||||
# TCP transport._force_close() should be able to call
|
||||
# connection_lost() in the right context
|
||||
if self._app_transport is not None:
|
||||
self._app_transport._closed = True
|
||||
if self._state == DO_HANDSHAKE:
|
||||
self._abort(None)
|
||||
else:
|
||||
self._set_state(FLUSHING)
|
||||
self._shutdown_timeout_handle = \
|
||||
self._loop.call_later(self._ssl_shutdown_timeout,
|
||||
lambda: self._check_shutdown_timeout())
|
||||
self._do_flush(context)
|
||||
|
||||
cdef _check_shutdown_timeout(self):
|
||||
if self._state in (FLUSHING, SHUTDOWN):
|
||||
self._transport._force_close(
|
||||
aio_TimeoutError('SSL shutdown timed out'))
|
||||
|
||||
cdef _do_read_into_void(self, object context):
|
||||
"""Consume and discard incoming application data.
|
||||
|
||||
If close_notify is received for the first time, call eof_received.
|
||||
"""
|
||||
cdef:
|
||||
bint close_notify = False
|
||||
try:
|
||||
while True:
|
||||
if not self._sslobj_read(SSL_READ_MAX_SIZE):
|
||||
close_notify = True
|
||||
break
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
pass
|
||||
except ssl_SSLZeroReturnError:
|
||||
close_notify = True
|
||||
if close_notify:
|
||||
self._call_eof_received(context)
|
||||
|
||||
cdef _do_flush(self, object context=None):
|
||||
"""Flush the write backlog, discarding new data received.
|
||||
|
||||
We don't send close_notify in FLUSHING because we still want to send
|
||||
the remaining data over SSL, even if we received a close_notify. Also,
|
||||
no application-level resume_writing() or pause_writing() will be called
|
||||
in FLUSHING, as we could fully manage the flow control internally.
|
||||
"""
|
||||
try:
|
||||
self._do_read_into_void(context)
|
||||
self._do_write()
|
||||
self._process_outgoing()
|
||||
self._control_ssl_reading()
|
||||
except Exception as ex:
|
||||
self._on_shutdown_complete(ex)
|
||||
else:
|
||||
if not self._get_write_buffer_size():
|
||||
self._set_state(SHUTDOWN)
|
||||
self._do_shutdown(context)
|
||||
|
||||
cdef _do_shutdown(self, object context=None):
|
||||
"""Send close_notify and wait for the same from the peer."""
|
||||
try:
|
||||
# we must skip all application data (if any) before unwrap
|
||||
self._do_read_into_void(context)
|
||||
try:
|
||||
self._sslobj.unwrap()
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
self._process_outgoing()
|
||||
else:
|
||||
self._process_outgoing()
|
||||
if not self._get_write_buffer_size():
|
||||
self._on_shutdown_complete(None)
|
||||
except Exception as ex:
|
||||
self._on_shutdown_complete(ex)
|
||||
|
||||
cdef _on_shutdown_complete(self, shutdown_exc):
|
||||
if self._shutdown_timeout_handle is not None:
|
||||
self._shutdown_timeout_handle.cancel()
|
||||
self._shutdown_timeout_handle = None
|
||||
|
||||
# we don't need the context here because TCP transport.close() should
|
||||
# be able to call connection_made() in the right context
|
||||
if shutdown_exc:
|
||||
self._fatal_error(shutdown_exc, 'Error occurred during shutdown')
|
||||
else:
|
||||
self._transport.close()
|
||||
|
||||
cdef _abort(self, exc):
|
||||
self._set_state(UNWRAPPED)
|
||||
if self._transport is not None:
|
||||
self._transport._force_close(exc)
|
||||
|
||||
# Outgoing flow
|
||||
|
||||
cdef _write_appdata(self, list_of_data, object context):
|
||||
if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
|
||||
if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
|
||||
aio_logger.warning('SSL connection is closed')
|
||||
self._conn_lost += 1
|
||||
return
|
||||
|
||||
for data in list_of_data:
|
||||
self._write_backlog.append(data)
|
||||
self._write_buffer_size += len(data)
|
||||
|
||||
try:
|
||||
if self._state == WRAPPED:
|
||||
self._do_write()
|
||||
self._process_outgoing()
|
||||
self._control_app_writing(context)
|
||||
|
||||
except Exception as ex:
|
||||
self._fatal_error(ex, 'Fatal error on SSL protocol')
|
||||
|
||||
cdef _do_write(self):
|
||||
"""Do SSL write, consumes write backlog and fills outgoing BIO."""
|
||||
cdef size_t data_len, count
|
||||
try:
|
||||
while self._write_backlog:
|
||||
data = self._write_backlog[0]
|
||||
count = self._sslobj_write(data)
|
||||
data_len = len(data)
|
||||
if count < data_len:
|
||||
if not PyMemoryView_Check(data):
|
||||
data = PyMemoryView_FromObject(data)
|
||||
self._write_backlog[0] = data[count:]
|
||||
self._write_buffer_size -= count
|
||||
else:
|
||||
del self._write_backlog[0]
|
||||
self._write_buffer_size -= data_len
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
pass
|
||||
|
||||
cdef _process_outgoing(self):
|
||||
"""Send bytes from the outgoing BIO."""
|
||||
if not self._ssl_writing_paused:
|
||||
data = self._outgoing_read()
|
||||
if len(data):
|
||||
self._transport.write(data)
|
||||
|
||||
# Incoming flow
|
||||
|
||||
cdef _do_read(self):
|
||||
if self._state != WRAPPED:
|
||||
return
|
||||
try:
|
||||
if not self._app_reading_paused:
|
||||
if self._app_protocol_is_buffer:
|
||||
self._do_read__buffered()
|
||||
else:
|
||||
self._do_read__copied()
|
||||
if self._write_backlog:
|
||||
self._do_write()
|
||||
self._process_outgoing()
|
||||
self._control_app_writing()
|
||||
self._control_ssl_reading()
|
||||
except Exception as ex:
|
||||
self._fatal_error(ex, 'Fatal error on SSL protocol')
|
||||
|
||||
cdef _do_read__buffered(self):
|
||||
cdef:
|
||||
Py_buffer pybuf
|
||||
bint pybuf_inited = False
|
||||
size_t wants, offset = 0
|
||||
int count = 1
|
||||
object buf
|
||||
|
||||
buf = self._app_protocol_get_buffer(self._get_read_buffer_size())
|
||||
wants = len(buf)
|
||||
|
||||
try:
|
||||
count = self._sslobj_read(wants, buf)
|
||||
|
||||
if count > 0:
|
||||
offset = count
|
||||
if offset < wants:
|
||||
PyObject_GetBuffer(buf, &pybuf, PyBUF_WRITABLE)
|
||||
pybuf_inited = True
|
||||
while offset < wants:
|
||||
buf = PyMemoryView_FromMemory(
|
||||
(<char*>pybuf.buf) + offset,
|
||||
wants - offset,
|
||||
PyBUF_WRITE)
|
||||
count = self._sslobj_read(wants - offset, buf)
|
||||
if count > 0:
|
||||
offset += count
|
||||
else:
|
||||
break
|
||||
else:
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle(self._loop,
|
||||
"SSLProtocol._do_read",
|
||||
<method_t>self._do_read,
|
||||
None, # current context is good
|
||||
self))
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
pass
|
||||
finally:
|
||||
if pybuf_inited:
|
||||
PyBuffer_Release(&pybuf)
|
||||
if offset > 0:
|
||||
self._app_protocol_buffer_updated(offset)
|
||||
if not count:
|
||||
# close_notify
|
||||
self._call_eof_received()
|
||||
self._start_shutdown()
|
||||
|
||||
cdef _do_read__copied(self):
|
||||
cdef:
|
||||
list data
|
||||
bytes first, chunk = b'1'
|
||||
bint zero = True, one = False
|
||||
|
||||
try:
|
||||
while True:
|
||||
chunk = self._sslobj_read(SSL_READ_MAX_SIZE)
|
||||
if not chunk:
|
||||
break
|
||||
if zero:
|
||||
zero = False
|
||||
one = True
|
||||
first = chunk
|
||||
elif one:
|
||||
one = False
|
||||
data = [first, chunk]
|
||||
else:
|
||||
data.append(chunk)
|
||||
except ssl_SSLAgainErrors as exc:
|
||||
pass
|
||||
if one:
|
||||
self._app_protocol.data_received(first)
|
||||
elif not zero:
|
||||
self._app_protocol.data_received(b''.join(data))
|
||||
if not chunk:
|
||||
# close_notify
|
||||
self._call_eof_received()
|
||||
self._start_shutdown()
|
||||
|
||||
cdef _call_eof_received(self, object context=None):
|
||||
if self._app_state == STATE_CON_MADE:
|
||||
self._app_state = STATE_EOF
|
||||
try:
|
||||
if context is None:
|
||||
# If the caller didn't provide a context, we assume the
|
||||
# caller is already in the right context, which is usually
|
||||
# inside the upstream callbacks like buffer_updated()
|
||||
keep_open = self._app_protocol.eof_received()
|
||||
else:
|
||||
keep_open = run_in_context(
|
||||
context, self._app_protocol.eof_received,
|
||||
)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as ex:
|
||||
self._fatal_error(ex, 'Error calling eof_received()')
|
||||
else:
|
||||
if keep_open:
|
||||
aio_logger.warning('returning true from eof_received() '
|
||||
'has no effect when using ssl')
|
||||
|
||||
# Flow control for writes from APP socket
|
||||
|
||||
cdef _control_app_writing(self, object context=None):
|
||||
cdef size_t size = self._get_write_buffer_size()
|
||||
if size >= self._outgoing_high_water and not self._app_writing_paused:
|
||||
self._app_writing_paused = True
|
||||
try:
|
||||
if context is None:
|
||||
# If the caller didn't provide a context, we assume the
|
||||
# caller is already in the right context, which is usually
|
||||
# inside the upstream callbacks like buffer_updated()
|
||||
self._app_protocol.pause_writing()
|
||||
else:
|
||||
run_in_context(context, self._app_protocol.pause_writing)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as exc:
|
||||
self._loop.call_exception_handler({
|
||||
'message': 'protocol.pause_writing() failed',
|
||||
'exception': exc,
|
||||
'transport': self._app_transport,
|
||||
'protocol': self,
|
||||
})
|
||||
elif size <= self._outgoing_low_water and self._app_writing_paused:
|
||||
self._app_writing_paused = False
|
||||
try:
|
||||
if context is None:
|
||||
# If the caller didn't provide a context, we assume the
|
||||
# caller is already in the right context, which is usually
|
||||
# inside the upstream callbacks like resume_writing()
|
||||
self._app_protocol.resume_writing()
|
||||
else:
|
||||
run_in_context(context, self._app_protocol.resume_writing)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except BaseException as exc:
|
||||
self._loop.call_exception_handler({
|
||||
'message': 'protocol.resume_writing() failed',
|
||||
'exception': exc,
|
||||
'transport': self._app_transport,
|
||||
'protocol': self,
|
||||
})
|
||||
|
||||
cdef size_t _get_write_buffer_size(self):
|
||||
return self._outgoing.pending + self._write_buffer_size
|
||||
|
||||
cdef _set_write_buffer_limits(self, high=None, low=None):
|
||||
high, low = add_flowcontrol_defaults(
|
||||
high, low, FLOW_CONTROL_HIGH_WATER_SSL_WRITE)
|
||||
self._outgoing_high_water = high
|
||||
self._outgoing_low_water = low
|
||||
|
||||
# Flow control for reads to APP socket
|
||||
|
||||
cdef _pause_reading(self):
|
||||
self._app_reading_paused = True
|
||||
|
||||
cdef _resume_reading(self, object context):
|
||||
if self._app_reading_paused:
|
||||
self._app_reading_paused = False
|
||||
if self._state == WRAPPED:
|
||||
self._loop._call_soon_handle(
|
||||
new_MethodHandle(self._loop,
|
||||
"SSLProtocol._do_read",
|
||||
<method_t>self._do_read,
|
||||
context,
|
||||
self))
|
||||
|
||||
# Flow control for reads from SSL socket
|
||||
|
||||
cdef _control_ssl_reading(self):
|
||||
cdef size_t size = self._get_read_buffer_size()
|
||||
if size >= self._incoming_high_water and not self._ssl_reading_paused:
|
||||
self._ssl_reading_paused = True
|
||||
self._transport.pause_reading()
|
||||
elif size <= self._incoming_low_water and self._ssl_reading_paused:
|
||||
self._ssl_reading_paused = False
|
||||
self._transport.resume_reading()
|
||||
|
||||
cdef _set_read_buffer_limits(self, high=None, low=None):
|
||||
high, low = add_flowcontrol_defaults(
|
||||
high, low, FLOW_CONTROL_HIGH_WATER_SSL_READ)
|
||||
self._incoming_high_water = high
|
||||
self._incoming_low_water = low
|
||||
|
||||
cdef size_t _get_read_buffer_size(self):
|
||||
return self._incoming.pending
|
||||
|
||||
# Flow control for writes to SSL socket
|
||||
|
||||
def pause_writing(self):
|
||||
"""Called when the low-level transport's buffer goes over
|
||||
the high-water mark.
|
||||
"""
|
||||
assert not self._ssl_writing_paused
|
||||
self._ssl_writing_paused = True
|
||||
|
||||
def resume_writing(self):
|
||||
"""Called when the low-level transport's buffer drains below
|
||||
the low-water mark.
|
||||
"""
|
||||
assert self._ssl_writing_paused
|
||||
self._ssl_writing_paused = False
|
||||
|
||||
if self._state == WRAPPED:
|
||||
self._process_outgoing()
|
||||
self._control_app_writing()
|
||||
|
||||
elif self._state == FLUSHING:
|
||||
self._do_flush()
|
||||
|
||||
elif self._state == SHUTDOWN:
|
||||
self._do_shutdown()
|
||||
|
||||
cdef _fatal_error(self, exc, message='Fatal error on transport'):
|
||||
if self._app_transport:
|
||||
self._app_transport._force_close(exc)
|
||||
elif self._transport:
|
||||
self._transport._force_close(exc)
|
||||
|
||||
if isinstance(exc, OSError):
|
||||
if self._loop.get_debug():
|
||||
aio_logger.debug("%r: %s", self, message, exc_info=True)
|
||||
elif not isinstance(exc, aio_CancelledError):
|
||||
self._loop.call_exception_handler({
|
||||
'message': message,
|
||||
'exception': exc,
|
||||
'transport': self._transport,
|
||||
'protocol': self,
|
||||
})
|
Reference in New Issue
Block a user