summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/uvloop
diff options
context:
space:
mode:
Diffstat (limited to 'venv/lib/python3.11/site-packages/uvloop')
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/__init__.py168
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pycbin0 -> 7929 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pycbin0 -> 366 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pycbin0 -> 31881 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pycbin0 -> 213 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/_noop.py3
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/_testbase.py550
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/_version.py13
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd39
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx434
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/dns.pyx471
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/errors.pyx113
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd11
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx56
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd54
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx293
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/check.pxd14
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/check.pyx72
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd12
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx116
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd48
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx395
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd14
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx72
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd33
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx226
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd25
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx233
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/process.pxd80
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/process.pyx792
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd50
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx1015
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd26
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx150
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd26
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx228
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/timer.pxd18
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/timer.pyx89
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/udp.pxd22
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/handles/udp.pyx409
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/__init__.py23
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pycbin0 -> 749 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/consts.pxi25
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/debug.pxd3
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd23
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/python.pxd31
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi175
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/system.pxd96
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/includes/uv.pxd506
-rwxr-xr-xvenv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.sobin0 -> 11727344 bytes
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/loop.pxd229
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/loop.pyi297
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/loop.pyx3403
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/lru.pyx79
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/pseudosock.pyx209
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/py.typed0
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/request.pxd8
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/request.pyx65
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/server.pxd19
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/server.pyx136
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/sslproto.pxd138
-rw-r--r--venv/lib/python3.11/site-packages/uvloop/sslproto.pyx950
62 files changed, 12785 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/uvloop/__init__.py b/venv/lib/python3.11/site-packages/uvloop/__init__.py
new file mode 100644
index 0000000..9bb6592
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/__init__.py
@@ -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:
+ ...
diff --git a/venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..ebc913e
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc
new file mode 100644
index 0000000..155eaae
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc
new file mode 100644
index 0000000..ca115de
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc
new file mode 100644
index 0000000..e31e416
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/_noop.py b/venv/lib/python3.11/site-packages/uvloop/_noop.py
new file mode 100644
index 0000000..bfc14dc
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/_noop.py
@@ -0,0 +1,3 @@
+def noop() -> None:
+ """Empty function to invoke CPython ceval loop."""
+ return
diff --git a/venv/lib/python3.11/site-packages/uvloop/_testbase.py b/venv/lib/python3.11/site-packages/uvloop/_testbase.py
new file mode 100644
index 0000000..c4a7595
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/_testbase.py
@@ -0,0 +1,550 @@
+"""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'):
+ 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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/_version.py b/venv/lib/python3.11/site-packages/uvloop/_version.py
new file mode 100644
index 0000000..0667c6a
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/_version.py
@@ -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.19.0'
diff --git a/venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd b/venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd
new file mode 100644
index 0000000..e594b13
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx b/venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx
new file mode 100644
index 0000000..2914b42
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx
@@ -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
diff --git a/venv/lib/python3.11/site-packages/uvloop/dns.pyx b/venv/lib/python3.11/site-packages/uvloop/dns.pyx
new file mode 100644
index 0000000..7aad631
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/dns.pyx
@@ -0,0 +1,471 @@
+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):
+ 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
+ else:
+ chost = <char*>host
+
+ if port is None:
+ cport = NULL
+ else:
+ cport = <char*>port
+
+ if cport is NULL and chost is NULL:
+ self.on_done()
+ msg = system.gai_strerror(socket_EAI_NONAME).decode('utf-8')
+ ex = socket_gaierror(socket_EAI_NONAME, msg)
+ callback(ex)
+ return
+
+ 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()
+ callback(convert_error(err))
+
+
+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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/errors.pyx b/venv/lib/python3.11/site-packages/uvloop/errors.pyx
new file mode 100644
index 0000000..d810d65
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/errors.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd
new file mode 100644
index 0000000..5f0d820
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx
new file mode 100644
index 0000000..5c740cf
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd
new file mode 100644
index 0000000..ba356a7
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx
new file mode 100644
index 0000000..28b3079
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx
@@ -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
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/check.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/check.pxd
new file mode 100644
index 0000000..86cfd8f
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/check.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/check.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/check.pyx
new file mode 100644
index 0000000..1a61c4e
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/check.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd
new file mode 100644
index 0000000..3a32428
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx
new file mode 100644
index 0000000..6ed6433
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd
new file mode 100644
index 0000000..5af1c14
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx
new file mode 100644
index 0000000..6efe375
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx
@@ -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):
+ 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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd
new file mode 100644
index 0000000..cf7b19f
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx
new file mode 100644
index 0000000..91c641f
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd
new file mode 100644
index 0000000..56fc265
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx
new file mode 100644
index 0000000..195576c
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx
@@ -0,0 +1,226 @@
+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_file>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
+
+
+@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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd
new file mode 100644
index 0000000..d07030b
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd
@@ -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)
+
+ 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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx
new file mode 100644
index 0000000..fca5981
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx
@@ -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):
+ 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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/process.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/process.pxd
new file mode 100644
index 0000000..970abcf
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/process.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/process.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/process.pyx
new file mode 100644
index 0000000..63b982a
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/process.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd
new file mode 100644
index 0000000..8ca8743
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx
new file mode 100644
index 0000000..d4e02e3
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx
@@ -0,0 +1,1015 @@
+DEF __PREALLOCED_BUFS = 4
+
+
+@cython.no_gc_clear
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class _StreamWriteContext:
+ # used to hold additional write request information for uv_write
+
+ cdef:
+ uv.uv_write_t req
+
+ list buffers
+
+ uv.uv_buf_t uv_bufs_sml[__PREALLOCED_BUFS]
+ Py_buffer py_bufs_sml[__PREALLOCED_BUFS]
+ bint py_bufs_sml_inuse
+
+ uv.uv_buf_t* uv_bufs
+ Py_buffer* py_bufs
+ size_t py_bufs_len
+
+ uv.uv_buf_t* uv_bufs_start
+ size_t uv_bufs_len
+
+ UVStream stream
+
+ bint closed
+
+ cdef free_bufs(self):
+ cdef size_t i
+
+ if self.uv_bufs is not NULL:
+ PyMem_RawFree(self.uv_bufs)
+ self.uv_bufs = NULL
+ if UVLOOP_DEBUG:
+ if self.py_bufs_sml_inuse:
+ raise RuntimeError(
+ '_StreamWriteContext.close: uv_bufs != NULL and '
+ 'py_bufs_sml_inuse is True')
+
+ if self.py_bufs is not NULL:
+ for i from 0 <= i < self.py_bufs_len:
+ PyBuffer_Release(&self.py_bufs[i])
+ PyMem_RawFree(self.py_bufs)
+ self.py_bufs = NULL
+ if UVLOOP_DEBUG:
+ if self.py_bufs_sml_inuse:
+ raise RuntimeError(
+ '_StreamWriteContext.close: py_bufs != NULL and '
+ 'py_bufs_sml_inuse is True')
+
+ if self.py_bufs_sml_inuse:
+ for i from 0 <= i < self.py_bufs_len:
+ PyBuffer_Release(&self.py_bufs_sml[i])
+ self.py_bufs_sml_inuse = 0
+
+ self.py_bufs_len = 0
+ self.buffers = None
+
+ cdef close(self):
+ if self.closed:
+ return
+ self.closed = 1
+ self.free_bufs()
+ Py_DECREF(self)
+
+ cdef advance_uv_buf(self, size_t sent):
+ # Advance the pointer to first uv_buf and the
+ # pointer to first byte in that buffer.
+ #
+ # We do this after a "uv_try_write" call, which
+ # sometimes sends only a portion of data.
+ # We then call "advance_uv_buf" on the write
+ # context, and reuse it in a "uv_write" call.
+
+ cdef:
+ uv.uv_buf_t* buf
+ size_t idx
+
+ for idx from 0 <= idx < self.uv_bufs_len:
+ buf = &self.uv_bufs_start[idx]
+ if buf.len > sent:
+ buf.len -= sent
+ buf.base = buf.base + sent
+ self.uv_bufs_start = buf
+ self.uv_bufs_len -= idx
+ return
+ else:
+ sent -= self.uv_bufs_start[idx].len
+
+ if UVLOOP_DEBUG:
+ if sent < 0:
+ raise RuntimeError('fatal: sent < 0 in advance_uv_buf')
+
+ raise RuntimeError('fatal: Could not advance _StreamWriteContext')
+
+ @staticmethod
+ cdef _StreamWriteContext new(UVStream stream, list buffers):
+ cdef:
+ _StreamWriteContext ctx
+ int uv_bufs_idx = 0
+ size_t py_bufs_len = 0
+ int i
+
+ Py_buffer* p_pybufs
+ uv.uv_buf_t* p_uvbufs
+
+ ctx = _StreamWriteContext.__new__(_StreamWriteContext)
+ ctx.stream = None
+ ctx.closed = 1
+ ctx.py_bufs_len = 0
+ ctx.py_bufs_sml_inuse = 0
+ ctx.uv_bufs = NULL
+ ctx.py_bufs = NULL
+ ctx.buffers = buffers
+ ctx.stream = stream
+
+ if len(buffers) <= __PREALLOCED_BUFS:
+ # We've got a small number of buffers to write, don't
+ # need to use malloc.
+ ctx.py_bufs_sml_inuse = 1
+ p_pybufs = <Py_buffer*>&ctx.py_bufs_sml
+ p_uvbufs = <uv.uv_buf_t*>&ctx.uv_bufs_sml
+
+ else:
+ for buf in buffers:
+ if UVLOOP_DEBUG:
+ if not isinstance(buf, (bytes, bytearray, memoryview)):
+ raise RuntimeError(
+ 'invalid data in writebuf: an instance of '
+ 'bytes, bytearray or memoryview was expected, '
+ 'got {}'.format(type(buf)))
+
+ if not PyBytes_CheckExact(buf):
+ py_bufs_len += 1
+
+ if py_bufs_len > 0:
+ ctx.py_bufs = <Py_buffer*>PyMem_RawMalloc(
+ py_bufs_len * sizeof(Py_buffer))
+ if ctx.py_bufs is NULL:
+ raise MemoryError()
+
+ ctx.uv_bufs = <uv.uv_buf_t*>PyMem_RawMalloc(
+ len(buffers) * sizeof(uv.uv_buf_t))
+ if ctx.uv_bufs is NULL:
+ raise MemoryError()
+
+ p_pybufs = ctx.py_bufs
+ p_uvbufs = ctx.uv_bufs
+
+ py_bufs_len = 0
+ for buf in buffers:
+ if PyBytes_CheckExact(buf):
+ # We can only use this hack for bytes since it's
+ # immutable. For everything else it is only safe to
+ # use buffer protocol.
+ p_uvbufs[uv_bufs_idx].base = PyBytes_AS_STRING(buf)
+ p_uvbufs[uv_bufs_idx].len = Py_SIZE(buf)
+
+ else:
+ try:
+ PyObject_GetBuffer(
+ buf, &p_pybufs[py_bufs_len], PyBUF_SIMPLE)
+ except Exception:
+ # This shouldn't ever happen, as `UVStream._buffer_write`
+ # casts non-bytes objects to `memoryviews`.
+ ctx.py_bufs_len = py_bufs_len
+ ctx.free_bufs()
+ raise
+
+ p_uvbufs[uv_bufs_idx].base = <char*>p_pybufs[py_bufs_len].buf
+ p_uvbufs[uv_bufs_idx].len = p_pybufs[py_bufs_len].len
+
+ py_bufs_len += 1
+
+ uv_bufs_idx += 1
+
+ ctx.uv_bufs_start = p_uvbufs
+ ctx.uv_bufs_len = uv_bufs_idx
+
+ ctx.py_bufs_len = py_bufs_len
+ ctx.req.data = <void*> ctx
+
+ if UVLOOP_DEBUG:
+ stream._loop._debug_stream_write_ctx_total += 1
+ stream._loop._debug_stream_write_ctx_cnt += 1
+
+ # Do incref after everything else is done.
+ # Under no circumstances we want `ctx` to be GCed while
+ # libuv is still working with `ctx.uv_bufs`.
+ Py_INCREF(ctx)
+ ctx.closed = 0
+ return ctx
+
+ def __dealloc__(self):
+ if not self.closed:
+ # Because we do an INCREF in _StreamWriteContext.new,
+ # __dealloc__ shouldn't ever happen with `self.closed == 1`
+ raise RuntimeError(
+ 'open _StreamWriteContext is being deallocated')
+
+ if UVLOOP_DEBUG:
+ if self.stream is not None:
+ self.stream._loop._debug_stream_write_ctx_cnt -= 1
+ self.stream = None
+
+
+@cython.no_gc_clear
+cdef class UVStream(UVBaseTransport):
+
+ def __cinit__(self):
+ self.__shutting_down = 0
+ self.__reading = 0
+ self.__read_error_close = 0
+ self.__buffered = 0
+ self._eof = 0
+ self._buffer = []
+ self._buffer_size = 0
+
+ self._protocol_get_buffer = None
+ self._protocol_buffer_updated = None
+
+ self._read_pybuf_acquired = False
+
+ cdef _set_protocol(self, object protocol):
+ if protocol is None:
+ raise TypeError('protocol is required')
+
+ UVBaseTransport._set_protocol(self, protocol)
+
+ if (hasattr(protocol, 'get_buffer') and
+ not isinstance(protocol, aio_Protocol)):
+ try:
+ self._protocol_get_buffer = protocol.get_buffer
+ self._protocol_buffer_updated = protocol.buffer_updated
+ self.__buffered = 1
+ except AttributeError:
+ pass
+ else:
+ self.__buffered = 0
+
+ cdef _clear_protocol(self):
+ UVBaseTransport._clear_protocol(self)
+ self._protocol_get_buffer = None
+ self._protocol_buffer_updated = None
+ self.__buffered = 0
+
+ cdef inline _shutdown(self):
+ cdef int err
+
+ if self.__shutting_down:
+ return
+ self.__shutting_down = 1
+
+ self._ensure_alive()
+
+ self._shutdown_req.data = <void*> self
+ err = uv.uv_shutdown(&self._shutdown_req,
+ <uv.uv_stream_t*> self._handle,
+ __uv_stream_on_shutdown)
+ if err < 0:
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ return
+
+ cdef inline _accept(self, UVStream server):
+ cdef int err
+ self._ensure_alive()
+
+ err = uv.uv_accept(<uv.uv_stream_t*>server._handle,
+ <uv.uv_stream_t*>self._handle)
+ if err < 0:
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ return
+
+ self._on_accept()
+
+ cdef inline _close_on_read_error(self):
+ self.__read_error_close = 1
+
+ cdef bint _is_reading(self):
+ return self.__reading
+
+ cdef _start_reading(self):
+ cdef int err
+
+ if self._closing:
+ return
+
+ self._ensure_alive()
+
+ if self.__reading:
+ return
+
+ if self.__buffered:
+ err = uv.uv_read_start(<uv.uv_stream_t*>self._handle,
+ __uv_stream_buffered_alloc,
+ __uv_stream_buffered_on_read)
+ else:
+ err = uv.uv_read_start(<uv.uv_stream_t*>self._handle,
+ __loop_alloc_buffer,
+ __uv_stream_on_read)
+ if err < 0:
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ return
+ else:
+ # UVStream must live until the read callback is called
+ self.__reading_started()
+
+ cdef inline __reading_started(self):
+ if self.__reading:
+ return
+ self.__reading = 1
+ Py_INCREF(self)
+
+ cdef inline __reading_stopped(self):
+ if not self.__reading:
+ return
+ self.__reading = 0
+ Py_DECREF(self)
+
+ cdef _stop_reading(self):
+ cdef int err
+
+ if not self.__reading:
+ return
+
+ self._ensure_alive()
+
+ # From libuv docs:
+ # This function is idempotent and may be safely
+ # called on a stopped stream.
+ err = uv.uv_read_stop(<uv.uv_stream_t*>self._handle)
+ if err < 0:
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ return
+ else:
+ self.__reading_stopped()
+
+ cdef inline _try_write(self, object data):
+ cdef:
+ ssize_t written
+ bint used_buf = 0
+ Py_buffer py_buf
+ void* buf
+ size_t blen
+ int saved_errno
+ int fd
+
+ if (<uv.uv_stream_t*>self._handle).write_queue_size != 0:
+ raise RuntimeError(
+ 'UVStream._try_write called with data in uv buffers')
+
+ if PyBytes_CheckExact(data):
+ # We can only use this hack for bytes since it's
+ # immutable. For everything else it is only safe to
+ # use buffer protocol.
+ buf = <void*>PyBytes_AS_STRING(data)
+ blen = Py_SIZE(data)
+ else:
+ PyObject_GetBuffer(data, &py_buf, PyBUF_SIMPLE)
+ used_buf = 1
+ buf = py_buf.buf
+ blen = py_buf.len
+
+ if blen == 0:
+ # Empty data, do nothing.
+ return 0
+
+ fd = self._fileno()
+ # Use `unistd.h/write` directly, it's faster than
+ # uv_try_write -- less layers of code. The error
+ # checking logic is copied from libuv.
+ written = system.write(fd, buf, blen)
+ while written == -1 and (
+ errno.errno == errno.EINTR or
+ (system.PLATFORM_IS_APPLE and
+ errno.errno == errno.EPROTOTYPE)):
+ # From libuv code (unix/stream.c):
+ # Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ # EPROTOTYPE can be returned while trying to write to a socket
+ # that is shutting down. If we retry the write, we should get
+ # the expected EPIPE instead.
+ written = system.write(fd, buf, blen)
+ saved_errno = errno.errno
+
+ if used_buf:
+ PyBuffer_Release(&py_buf)
+
+ if written < 0:
+ if saved_errno == errno.EAGAIN or \
+ saved_errno == system.EWOULDBLOCK:
+ return -1
+ else:
+ exc = convert_error(-saved_errno)
+ self._fatal_error(exc, True)
+ return
+
+ if UVLOOP_DEBUG:
+ self._loop._debug_stream_write_tries += 1
+
+ if <size_t>written == blen:
+ return 0
+
+ return written
+
+ cdef inline _buffer_write(self, object data):
+ cdef int dlen
+
+ if not PyBytes_CheckExact(data):
+ data = memoryview(data).cast('b')
+
+ dlen = len(data)
+ if not dlen:
+ return
+
+ self._buffer_size += dlen
+ self._buffer.append(data)
+
+ cdef inline _initiate_write(self):
+ if (not self._protocol_paused and
+ (<uv.uv_stream_t*>self._handle).write_queue_size == 0 and
+ self._buffer_size > self._high_water):
+ # Fast-path. If:
+ # - the protocol isn't yet paused,
+ # - there is no data in libuv buffers for this stream,
+ # - the protocol will be paused if we continue to buffer data
+ #
+ # Then:
+ # - Try to write all buffered data right now.
+ all_sent = self._exec_write()
+ if UVLOOP_DEBUG:
+ if self._buffer_size != 0 or self._buffer != []:
+ raise RuntimeError(
+ '_buffer_size is not 0 after a successful _exec_write')
+
+ # There is no need to call `_queue_write` anymore,
+ # as `uv_write` should be called already.
+
+ if not all_sent:
+ # If not all of the data was sent successfully,
+ # we might need to pause the protocol.
+ self._maybe_pause_protocol()
+
+ elif self._buffer_size > 0:
+ self._maybe_pause_protocol()
+ self._loop._queue_write(self)
+
+ cdef inline _exec_write(self):
+ cdef:
+ int err
+ int buf_len
+ _StreamWriteContext ctx = None
+
+ if self._closed:
+ # If the handle is closed, just return, it's too
+ # late to do anything.
+ return
+
+ buf_len = len(self._buffer)
+ if not buf_len:
+ return
+
+ if (<uv.uv_stream_t*>self._handle).write_queue_size == 0:
+ # libuv internal write buffers for this stream are empty.
+ if buf_len == 1:
+ # If we only have one piece of data to send, let's
+ # use our fast implementation of try_write.
+ data = self._buffer[0]
+ sent = self._try_write(data)
+
+ if sent is None:
+ # A `self._fatal_error` was called.
+ # It might not raise an exception under some
+ # conditions.
+ self._buffer_size = 0
+ self._buffer.clear()
+ if not self._closing:
+ # This should never happen.
+ raise RuntimeError(
+ 'stream is open after UVStream._try_write '
+ 'returned None')
+ return
+
+ if sent == 0:
+ # All data was successfully written.
+ self._buffer_size = 0
+ self._buffer.clear()
+ # on_write will call "maybe_resume_protocol".
+ self._on_write()
+ return True
+
+ if sent > 0:
+ if UVLOOP_DEBUG:
+ if sent == len(data):
+ raise RuntimeError(
+ '_try_write sent all data and returned '
+ 'non-zero')
+
+ if PyBytes_CheckExact(data):
+ # Cast bytes to memoryview to avoid copying
+ # data that wasn't sent.
+ data = memoryview(data)
+ data = data[sent:]
+
+ self._buffer_size -= sent
+ self._buffer[0] = data
+
+ # At this point it's either data was sent partially,
+ # or an EAGAIN has happened.
+
+ else:
+ ctx = _StreamWriteContext.new(self, self._buffer)
+
+ err = uv.uv_try_write(<uv.uv_stream_t*>self._handle,
+ ctx.uv_bufs_start,
+ ctx.uv_bufs_len)
+
+ if err > 0:
+ # Some data was successfully sent.
+
+ if <size_t>err == self._buffer_size:
+ # Everything was sent.
+ ctx.close()
+ self._buffer.clear()
+ self._buffer_size = 0
+ # on_write will call "maybe_resume_protocol".
+ self._on_write()
+ return True
+
+ try:
+ # Advance pointers to uv_bufs in `ctx`,
+ # we will reuse it soon for a uv_write
+ # call.
+ ctx.advance_uv_buf(<ssize_t>err)
+ except Exception as ex: # This should never happen.
+ # Let's try to close the `ctx` anyways.
+ ctx.close()
+ self._fatal_error(ex, True)
+ self._buffer.clear()
+ self._buffer_size = 0
+ return
+
+ elif err != uv.UV_EAGAIN:
+ ctx.close()
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ self._buffer.clear()
+ self._buffer_size = 0
+ return
+
+ # fall through
+
+ if ctx is None:
+ ctx = _StreamWriteContext.new(self, self._buffer)
+
+ err = uv.uv_write(&ctx.req,
+ <uv.uv_stream_t*>self._handle,
+ ctx.uv_bufs_start,
+ ctx.uv_bufs_len,
+ __uv_stream_on_write)
+
+ self._buffer_size = 0
+ # Can't use `_buffer.clear()` here: `ctx` holds a reference to
+ # the `_buffer`.
+ self._buffer = []
+
+ if err < 0:
+ # close write context
+ ctx.close()
+
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ return
+
+ self._maybe_resume_protocol()
+
+ cdef size_t _get_write_buffer_size(self):
+ if self._handle is NULL:
+ return 0
+ return ((<uv.uv_stream_t*>self._handle).write_queue_size +
+ self._buffer_size)
+
+ cdef _close(self):
+ try:
+ if self._read_pybuf_acquired:
+ # Should never happen. libuv always calls uv_alloc/uv_read
+ # in pairs.
+ self._loop.call_exception_handler({
+ 'transport': self,
+ 'message': 'XXX: an allocated buffer in transport._close()'
+ })
+ self._read_pybuf_acquired = 0
+ PyBuffer_Release(&self._read_pybuf)
+
+ self._stop_reading()
+ finally:
+ UVSocketHandle._close(<UVHandle>self)
+
+ cdef inline _on_accept(self):
+ # Ultimately called by __uv_stream_on_listen.
+ self._init_protocol()
+
+ cdef inline _on_eof(self):
+ # Any exception raised here will be caught in
+ # __uv_stream_on_read.
+
+ try:
+ meth = self._protocol.eof_received
+ except AttributeError:
+ keep_open = False
+ else:
+ keep_open = run_in_context(self.context, meth)
+
+ if keep_open:
+ # We're keeping the connection open so the
+ # protocol can write more, but we still can't
+ # receive more, so remove the reader callback.
+ self._stop_reading()
+ else:
+ self.close()
+
+ cdef inline _on_write(self):
+ self._maybe_resume_protocol()
+ if not self._get_write_buffer_size():
+ if self._closing:
+ self._schedule_call_connection_lost(None)
+ elif self._eof:
+ self._shutdown()
+
+ cdef inline _init(self, Loop loop, object protocol, Server server,
+ object waiter, object context):
+ self.context = context
+ self._set_protocol(protocol)
+ self._start_init(loop)
+
+ if server is not None:
+ self._set_server(server)
+
+ if waiter is not None:
+ self._set_waiter(waiter)
+
+ cdef inline _on_connect(self, object exc):
+ # Called from __tcp_connect_callback (tcp.pyx) and
+ # __pipe_connect_callback (pipe.pyx).
+ if exc is None:
+ self._init_protocol()
+ else:
+ if self._waiter is None:
+ self._fatal_error(exc, False, "connect failed")
+ elif self._waiter.cancelled():
+ # Connect call was cancelled; just close the transport
+ # silently.
+ self._close()
+ elif self._waiter.done():
+ self._fatal_error(exc, False, "connect failed")
+ else:
+ self._waiter.set_exception(exc)
+ self._close()
+
+ # === Public API ===
+
+ def __repr__(self):
+ return '<{} closed={} reading={} {:#x}>'.format(
+ self.__class__.__name__,
+ self._closed,
+ self.__reading,
+ id(self))
+
+ def write(self, object buf):
+ self._ensure_alive()
+
+ if self._eof:
+ raise RuntimeError('Cannot call write() after write_eof()')
+ if not buf:
+ return
+ if self._conn_lost:
+ self._conn_lost += 1
+ return
+ self._buffer_write(buf)
+ self._initiate_write()
+
+ def writelines(self, bufs):
+ self._ensure_alive()
+
+ if self._eof:
+ raise RuntimeError('Cannot call writelines() after write_eof()')
+ if self._conn_lost:
+ self._conn_lost += 1
+ return
+ for buf in bufs:
+ self._buffer_write(buf)
+ self._initiate_write()
+
+ def write_eof(self):
+ self._ensure_alive()
+
+ if self._eof:
+ return
+
+ self._eof = 1
+ if not self._get_write_buffer_size():
+ self._shutdown()
+
+ def can_write_eof(self):
+ return True
+
+ def is_reading(self):
+ return self._is_reading()
+
+ def pause_reading(self):
+ if self._closing or not self._is_reading():
+ return
+ self._stop_reading()
+
+ def resume_reading(self):
+ if self._is_reading() or self._closing:
+ return
+ self._start_reading()
+
+
+cdef void __uv_stream_on_shutdown(uv.uv_shutdown_t* req,
+ int status) noexcept with gil:
+
+ # callback for uv_shutdown
+
+ if req.data is NULL:
+ aio_logger.error(
+ 'UVStream.shutdown callback called with NULL req.data, status=%r',
+ status)
+ return
+
+ cdef UVStream stream = <UVStream> req.data
+
+ if status < 0 and status != uv.UV_ECANCELED:
+ # From libuv source code:
+ # The ECANCELED error code is a lie, the shutdown(2) syscall is a
+ # fait accompli at this point. Maybe we should revisit this in
+ # v0.11. A possible reason for leaving it unchanged is that it
+ # informs the callee that the handle has been destroyed.
+
+ if UVLOOP_DEBUG:
+ stream._loop._debug_stream_shutdown_errors_total += 1
+
+ exc = convert_error(status)
+ stream._fatal_error(
+ exc, False, "error status in uv_stream_t.shutdown callback")
+ return
+
+
+cdef inline bint __uv_stream_on_read_common(
+ UVStream sc,
+ Loop loop,
+ ssize_t nread,
+):
+ if sc._closed:
+ # The stream was closed, there is no reason to
+ # do any work now.
+ sc.__reading_stopped() # Just in case.
+ return True
+
+ if nread == uv.UV_EOF:
+ # From libuv docs:
+ # The callee is responsible for stopping closing the stream
+ # when an error happens by calling uv_read_stop() or uv_close().
+ # Trying to read from the stream again is undefined.
+ try:
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_eof_total += 1
+
+ sc._stop_reading()
+ sc._on_eof()
+ except BaseException as ex:
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_eof_cb_errors_total += 1
+
+ sc._fatal_error(ex, False)
+ finally:
+ return True
+
+ if nread == 0:
+ # From libuv docs:
+ # nread might be 0, which does not indicate an error or EOF.
+ # This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
+ return True
+
+ if nread < 0:
+ # From libuv docs:
+ # The callee is responsible for stopping closing the stream
+ # when an error happens by calling uv_read_stop() or uv_close().
+ # Trying to read from the stream again is undefined.
+ #
+ # Therefore, we're closing the stream. Since "UVHandle._close()"
+ # doesn't raise exceptions unless uvloop is built with DEBUG=1,
+ # we don't need try...finally here.
+
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_errors_total += 1
+
+ if sc.__read_error_close:
+ # Used for getting notified when a pipe is closed.
+ # See WriteUnixTransport for the explanation.
+ sc._on_eof()
+ return True
+
+ exc = convert_error(nread)
+ sc._fatal_error(
+ exc, False, "error status in uv_stream_t.read callback")
+ return True
+
+ return False
+
+
+cdef inline void __uv_stream_on_read_impl(
+ uv.uv_stream_t* stream,
+ ssize_t nread,
+ const uv.uv_buf_t* buf,
+):
+ cdef:
+ UVStream sc = <UVStream>stream.data
+ Loop loop = sc._loop
+
+ # 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 __uv_stream_on_read_common(sc, loop, nread):
+ return
+
+ try:
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_cb_total += 1
+
+ run_in_context1(
+ sc.context,
+ sc._protocol_data_received,
+ loop._recv_buffer[:nread],
+ )
+ except BaseException as exc:
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_cb_errors_total += 1
+
+ sc._fatal_error(exc, False)
+
+
+cdef inline void __uv_stream_on_write_impl(
+ uv.uv_write_t* req,
+ int status,
+):
+ cdef:
+ _StreamWriteContext ctx = <_StreamWriteContext> req.data
+ UVStream stream = <UVStream>ctx.stream
+
+ ctx.close()
+
+ if stream._closed:
+ # The stream was closed, there is nothing to do.
+ # Even if there is an error, like EPIPE, there
+ # is no reason to report it.
+ return
+
+ if status < 0:
+ if UVLOOP_DEBUG:
+ stream._loop._debug_stream_write_errors_total += 1
+
+ exc = convert_error(status)
+ stream._fatal_error(
+ exc, False, "error status in uv_stream_t.write callback")
+ return
+
+ try:
+ stream._on_write()
+ except BaseException as exc:
+ if UVLOOP_DEBUG:
+ stream._loop._debug_stream_write_cb_errors_total += 1
+
+ stream._fatal_error(exc, False)
+
+
+cdef void __uv_stream_on_read(
+ uv.uv_stream_t* stream,
+ ssize_t nread,
+ const uv.uv_buf_t* buf,
+) noexcept with gil:
+
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
+ "UVStream read callback") == 0:
+ return
+
+ # Don't need try-finally, __uv_stream_on_read_impl is void
+ __uv_stream_on_read_impl(stream, nread, buf)
+
+
+cdef void __uv_stream_on_write(
+ uv.uv_write_t* req,
+ int status,
+) noexcept with gil:
+
+ if UVLOOP_DEBUG:
+ if req.data is NULL:
+ aio_logger.error(
+ 'UVStream.write callback called with NULL req.data, status=%r',
+ status)
+ return
+
+ # Don't need try-finally, __uv_stream_on_write_impl is void
+ __uv_stream_on_write_impl(req, status)
+
+
+cdef void __uv_stream_buffered_alloc(
+ uv.uv_handle_t* stream,
+ size_t suggested_size,
+ uv.uv_buf_t* uvbuf,
+) noexcept with gil:
+
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
+ "UVStream alloc buffer callback") == 0:
+ return
+
+ cdef:
+ UVStream sc = <UVStream>stream.data
+ Loop loop = sc._loop
+ Py_buffer* pybuf = &sc._read_pybuf
+ int got_buf = 0
+
+ if sc._read_pybuf_acquired:
+ uvbuf.len = 0
+ uvbuf.base = NULL
+ return
+
+ sc._read_pybuf_acquired = 0
+ try:
+ buf = run_in_context1(
+ sc.context,
+ sc._protocol_get_buffer,
+ suggested_size,
+ )
+ PyObject_GetBuffer(buf, pybuf, PyBUF_WRITABLE)
+ got_buf = 1
+ except BaseException as exc:
+ # Can't call 'sc._fatal_error' or 'sc._close', libuv will SF.
+ # We'll do it later in __uv_stream_buffered_on_read when we
+ # receive UV_ENOBUFS.
+ uvbuf.len = 0
+ uvbuf.base = NULL
+ return
+
+ if not pybuf.len:
+ uvbuf.len = 0
+ uvbuf.base = NULL
+ if got_buf:
+ PyBuffer_Release(pybuf)
+ return
+
+ sc._read_pybuf_acquired = 1
+ uvbuf.base = <char*>pybuf.buf
+ uvbuf.len = pybuf.len
+
+
+cdef void __uv_stream_buffered_on_read(
+ uv.uv_stream_t* stream,
+ ssize_t nread,
+ const uv.uv_buf_t* buf,
+) noexcept with gil:
+
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
+ "UVStream buffered read callback") == 0:
+ return
+
+ cdef:
+ UVStream sc = <UVStream>stream.data
+ Loop loop = sc._loop
+ Py_buffer* pybuf = &sc._read_pybuf
+
+ if nread == uv.UV_ENOBUFS:
+ sc._fatal_error(
+ RuntimeError(
+ 'unhandled error (or an empty buffer) in get_buffer()'),
+ False)
+ return
+
+ try:
+ if nread > 0 and not sc._read_pybuf_acquired:
+ # From libuv docs:
+ # nread is > 0 if there is data available or < 0 on error. When
+ # we’ve reached EOF, nread will be set to UV_EOF. When
+ # nread < 0, the buf parameter might not point to a valid
+ # buffer; in that case buf.len and buf.base are both set to 0.
+ raise RuntimeError(
+ f'no python buffer is allocated in on_read; nread={nread}')
+
+ if nread == 0:
+ # From libuv docs:
+ # nread might be 0, which does not indicate an error or EOF.
+ # This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
+ return
+
+ if __uv_stream_on_read_common(sc, loop, nread):
+ return
+
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_cb_total += 1
+
+ run_in_context1(sc.context, sc._protocol_buffer_updated, nread)
+ except BaseException as exc:
+ if UVLOOP_DEBUG:
+ loop._debug_stream_read_cb_errors_total += 1
+
+ sc._fatal_error(exc, False)
+ finally:
+ sc._read_pybuf_acquired = 0
+ PyBuffer_Release(pybuf)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd
new file mode 100644
index 0000000..a004efd
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx
new file mode 100644
index 0000000..9993317
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd
new file mode 100644
index 0000000..8d388ef
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx
new file mode 100644
index 0000000..d5fe827
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx
@@ -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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/timer.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/timer.pxd
new file mode 100644
index 0000000..fda23b6
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/timer.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/timer.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/timer.pyx
new file mode 100644
index 0000000..86d46ef
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/timer.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/udp.pxd b/venv/lib/python3.11/site-packages/uvloop/handles/udp.pxd
new file mode 100644
index 0000000..daa9a1b
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/udp.pxd
@@ -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=*)
diff --git a/venv/lib/python3.11/site-packages/uvloop/handles/udp.pyx b/venv/lib/python3.11/site-packages/uvloop/handles/udp.pyx
new file mode 100644
index 0000000..bbe60d5
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/handles/udp.pyx
@@ -0,0 +1,409 @@
+@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)
+ self._fatal_error(exc, True)
+ else:
+ self._maybe_pause_protocol()
+
+ else:
+ if err < 0:
+ exc = convert_error(err)
+ self._fatal_error(exc, True)
+ else:
+ self._on_sent(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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/__init__.py b/venv/lib/python3.11/site-packages/uvloop/includes/__init__.py
new file mode 100644
index 0000000..2ccf9ca
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/__init__.py
@@ -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
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..a4464aa
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/consts.pxi b/venv/lib/python3.11/site-packages/uvloop/includes/consts.pxi
new file mode 100644
index 0000000..f765053
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/consts.pxi
@@ -0,0 +1,25 @@
+DEF UV_STREAM_RECV_BUF_SIZE = 256000 # 250kb
+
+DEF FLOW_CONTROL_HIGH_WATER = 64 # KiB
+DEF FLOW_CONTROL_HIGH_WATER_SSL_READ = 256 # KiB
+DEF FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512 # KiB
+
+DEF DEFAULT_FREELIST_SIZE = 250
+DEF DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE = 2048
+
+DEF DEBUG_STACK_DEPTH = 10
+
+
+DEF __PROCESS_DEBUG_SLEEP_AFTER_FORK = 1
+
+
+DEF LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
+
+
+# Number of seconds to wait for SSL handshake to complete
+# The default timeout matches that of Nginx.
+DEF SSL_HANDSHAKE_TIMEOUT = 60.0
+# Number of seconds to wait for SSL shutdown to complete
+# The default timeout mimics lingering_time
+DEF SSL_SHUTDOWN_TIMEOUT = 30.0
+DEF SSL_READ_MAX_SIZE = 256 * 1024
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/debug.pxd b/venv/lib/python3.11/site-packages/uvloop/includes/debug.pxd
new file mode 100644
index 0000000..a825def
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/debug.pxd
@@ -0,0 +1,3 @@
+cdef extern from "includes/debug.h":
+
+ cdef int UVLOOP_DEBUG
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd b/venv/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd
new file mode 100644
index 0000000..f22f1a7
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/flowcontrol.pxd
@@ -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
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/python.pxd b/venv/lib/python3.11/site-packages/uvloop/includes/python.pxd
new file mode 100644
index 0000000..454d5c7
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/python.pxd
@@ -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
+
+ void _Py_RestoreSignals()
+
+ 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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi b/venv/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi
new file mode 100644
index 0000000..e7957fe
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/stdlib.pxi
@@ -0,0 +1,175 @@
+# 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_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
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/system.pxd b/venv/lib/python3.11/site-packages/uvloop/includes/system.pxd
new file mode 100644
index 0000000..367fedd
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/system.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/includes/uv.pxd b/venv/lib/python3.11/site-packages/uvloop/includes/uv.pxd
new file mode 100644
index 0000000..8765130
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/includes/uv.pxd
@@ -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
+ cdef int SO_REUSEPORT
+ 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
+
+ cpdef 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)
+ int 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_file 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()
diff --git a/venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so b/venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so
new file mode 100755
index 0000000..58ae5dc
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/loop.cpython-311-x86_64-linux-gnu.so
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/uvloop/loop.pxd b/venv/lib/python3.11/site-packages/uvloop/loop.pxd
new file mode 100644
index 0000000..5613473
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/loop.pxd
@@ -0,0 +1,229 @@
+# 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
+
+ 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"
diff --git a/venv/lib/python3.11/site-packages/uvloop/loop.pyi b/venv/lib/python3.11/site-packages/uvloop/loop.pyi
new file mode 100644
index 0000000..9c8c462
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/loop.pyi
@@ -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: ...
diff --git a/venv/lib/python3.11/site-packages/uvloop/loop.pyx b/venv/lib/python3.11/site-packages/uvloop/loop.pyx
new file mode 100644
index 0000000..334d8d5
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/loop.pyx
@@ -0,0 +1,3403 @@
+# cython: language_level=3, embedsignature=True
+
+import asyncio
+cimport cython
+
+from .includes.debug cimport UVLOOP_DEBUG
+from .includes cimport uv
+from .includes cimport system
+from .includes.python cimport (
+ PY_VERSION_HEX,
+ PyMem_RawMalloc, PyMem_RawFree,
+ PyMem_RawCalloc, PyMem_RawRealloc,
+ PyUnicode_EncodeFSDefault,
+ PyErr_SetInterrupt,
+ _Py_RestoreSignals,
+ Context_CopyCurrent,
+ Context_Enter,
+ Context_Exit,
+ PyMemoryView_FromMemory, PyBUF_WRITE,
+ PyMemoryView_FromObject, PyMemoryView_Check,
+ PyOS_AfterFork_Parent, PyOS_AfterFork_Child,
+ PyOS_BeforeFork,
+ PyUnicode_FromString
+)
+from .includes.flowcontrol cimport add_flowcontrol_defaults
+
+from libc.stdint cimport uint64_t
+from libc.string cimport memset, strerror, memcpy
+from libc cimport errno
+
+from cpython cimport PyObject
+from cpython cimport PyErr_CheckSignals, PyErr_Occurred
+from cpython cimport PyThread_get_thread_ident
+from cpython cimport Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF
+from cpython cimport (
+ PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE,
+ Py_buffer, PyBytes_AsString, PyBytes_CheckExact,
+ PyBytes_AsStringAndSize,
+ Py_SIZE, PyBytes_AS_STRING, PyBUF_WRITABLE
+)
+from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer
+
+from . import _noop
+
+
+include "includes/consts.pxi"
+include "includes/stdlib.pxi"
+
+include "errors.pyx"
+
+cdef:
+ int PY39 = PY_VERSION_HEX >= 0x03090000
+ int PY311 = PY_VERSION_HEX >= 0x030b0000
+ uint64_t MAX_SLEEP = 3600 * 24 * 365 * 100
+
+
+cdef _is_sock_stream(sock_type):
+ if SOCK_NONBLOCK == -1:
+ return sock_type == uv.SOCK_STREAM
+ else:
+ # Linux's socket.type is a bitmask that can include extra info
+ # about socket (like SOCK_NONBLOCK bit), therefore we can't do simple
+ # `sock_type == socket.SOCK_STREAM`, see
+ # https://github.com/torvalds/linux/blob/v4.13/include/linux/net.h#L77
+ # for more details.
+ return (sock_type & 0xF) == uv.SOCK_STREAM
+
+
+cdef _is_sock_dgram(sock_type):
+ if SOCK_NONBLOCK == -1:
+ return sock_type == uv.SOCK_DGRAM
+ else:
+ # Read the comment in `_is_sock_stream`.
+ return (sock_type & 0xF) == uv.SOCK_DGRAM
+
+
+cdef isfuture(obj):
+ if aio_isfuture is None:
+ return isinstance(obj, aio_Future)
+ else:
+ return aio_isfuture(obj)
+
+
+cdef inline socket_inc_io_ref(sock):
+ if isinstance(sock, socket_socket):
+ sock._io_refs += 1
+
+
+cdef inline socket_dec_io_ref(sock):
+ if isinstance(sock, socket_socket):
+ sock._decref_socketios()
+
+
+cdef inline run_in_context(context, method):
+ # This method is internally used to workaround a reference issue that in
+ # certain circumstances, inlined context.run() will not hold a reference to
+ # the given method instance, which - if deallocated - will cause segfault.
+ # See also: edgedb/edgedb#2222
+ Py_INCREF(method)
+ try:
+ return context.run(method)
+ finally:
+ Py_DECREF(method)
+
+
+cdef inline run_in_context1(context, method, arg):
+ Py_INCREF(method)
+ try:
+ return context.run(method, arg)
+ finally:
+ Py_DECREF(method)
+
+
+cdef inline run_in_context2(context, method, arg1, arg2):
+ Py_INCREF(method)
+ try:
+ return context.run(method, arg1, arg2)
+ finally:
+ Py_DECREF(method)
+
+
+# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s
+# *reuse_address* parameter
+_unset = object()
+
+
+@cython.no_gc_clear
+cdef class Loop:
+ def __cinit__(self):
+ cdef int err
+
+ # Install PyMem* memory allocators if they aren't installed yet.
+ __install_pymem()
+
+ # Install pthread_atfork handlers
+ __install_atfork()
+
+ self.uvloop = <uv.uv_loop_t*>PyMem_RawMalloc(sizeof(uv.uv_loop_t))
+ if self.uvloop is NULL:
+ raise MemoryError()
+
+ self.slow_callback_duration = 0.1
+
+ self._closed = 0
+ self._debug = 0
+ self._thread_id = 0
+ self._running = 0
+ self._stopping = 0
+
+ self._transports = weakref_WeakValueDictionary()
+ self._processes = set()
+
+ # Used to keep a reference (and hence keep the fileobj alive)
+ # for as long as its registered by add_reader or add_writer.
+ # This is how the selector module and hence asyncio behaves.
+ self._fd_to_reader_fileobj = {}
+ self._fd_to_writer_fileobj = {}
+
+ self._timers = set()
+ self._polls = {}
+
+ self._recv_buffer_in_use = 0
+
+ err = uv.uv_loop_init(self.uvloop)
+ if err < 0:
+ raise convert_error(err)
+ self.uvloop.data = <void*> self
+
+ self._init_debug_fields()
+
+ self.active_process_handler = None
+
+ self._last_error = None
+
+ self._task_factory = None
+ self._exception_handler = None
+ self._default_executor = None
+
+ self._queued_streams = set()
+ self._executing_streams = set()
+ self._ready = col_deque()
+ self._ready_len = 0
+
+ self.handler_async = UVAsync.new(
+ self, <method_t>self._on_wake, self)
+
+ self.handler_idle = UVIdle.new(
+ self,
+ new_MethodHandle(
+ self, "loop._on_idle", <method_t>self._on_idle, None, self))
+
+ # Needed to call `UVStream._exec_write` for writes scheduled
+ # during `Protocol.data_received`.
+ self.handler_check__exec_writes = UVCheck.new(
+ self,
+ new_MethodHandle(
+ self, "loop._exec_queued_writes",
+ <method_t>self._exec_queued_writes, None, self))
+
+ self._signals = set()
+ self._ssock = self._csock = None
+ self._signal_handlers = {}
+ self._listening_signals = False
+ self._old_signal_wakeup_id = -1
+
+ self._coroutine_debug_set = False
+
+ # A weak set of all asynchronous generators that are
+ # being iterated by the loop.
+ self._asyncgens = weakref_WeakSet()
+
+ # Set to True when `loop.shutdown_asyncgens` is called.
+ self._asyncgens_shutdown_called = False
+ # Set to True when `loop.shutdown_default_executor` is called.
+ self._executor_shutdown_called = False
+
+ self._servers = set()
+
+ cdef inline _is_main_thread(self):
+ cdef uint64_t main_thread_id = system.MAIN_THREAD_ID
+ if system.MAIN_THREAD_ID_SET == 0:
+ main_thread_id = <uint64_t>threading_main_thread().ident
+ system.setMainThreadID(main_thread_id)
+ return main_thread_id == PyThread_get_thread_ident()
+
+ def __init__(self):
+ self.set_debug(
+ sys_dev_mode or (not sys_ignore_environment
+ and bool(os_environ.get('PYTHONASYNCIODEBUG'))))
+
+ def __dealloc__(self):
+ if self._running == 1:
+ raise RuntimeError('deallocating a running event loop!')
+ if self._closed == 0:
+ aio_logger.error("deallocating an open event loop")
+ return
+ PyMem_RawFree(self.uvloop)
+ self.uvloop = NULL
+
+ cdef _init_debug_fields(self):
+ self._debug_cc = bool(UVLOOP_DEBUG)
+
+ if UVLOOP_DEBUG:
+ self._debug_handles_current = col_Counter()
+ self._debug_handles_closed = col_Counter()
+ self._debug_handles_total = col_Counter()
+ else:
+ self._debug_handles_current = None
+ self._debug_handles_closed = None
+ self._debug_handles_total = None
+
+ self._debug_uv_handles_total = 0
+ self._debug_uv_handles_freed = 0
+
+ self._debug_stream_read_cb_total = 0
+ self._debug_stream_read_eof_total = 0
+ self._debug_stream_read_errors_total = 0
+ self._debug_stream_read_cb_errors_total = 0
+ self._debug_stream_read_eof_cb_errors_total = 0
+
+ self._debug_stream_shutdown_errors_total = 0
+ self._debug_stream_listen_errors_total = 0
+
+ self._debug_stream_write_tries = 0
+ self._debug_stream_write_errors_total = 0
+ self._debug_stream_write_ctx_total = 0
+ self._debug_stream_write_ctx_cnt = 0
+ self._debug_stream_write_cb_errors_total = 0
+
+ self._debug_cb_handles_total = 0
+ self._debug_cb_handles_count = 0
+
+ self._debug_cb_timer_handles_total = 0
+ self._debug_cb_timer_handles_count = 0
+
+ self._poll_read_events_total = 0
+ self._poll_read_cb_errors_total = 0
+ self._poll_write_events_total = 0
+ self._poll_write_cb_errors_total = 0
+
+ self._sock_try_write_total = 0
+
+ self._debug_exception_handler_cnt = 0
+
+ cdef _setup_or_resume_signals(self):
+ if not self._is_main_thread():
+ return
+
+ if self._listening_signals:
+ raise RuntimeError('signals handling has been already setup')
+
+ if self._ssock is not None:
+ raise RuntimeError('self-pipe exists before loop run')
+
+ # Create a self-pipe and call set_signal_wakeup_fd() with one
+ # of its ends. This is needed so that libuv knows that it needs
+ # to wakeup on ^C (no matter if the SIGINT handler is still the
+ # standard Python's one or or user set their own.)
+
+ self._ssock, self._csock = socket_socketpair()
+ try:
+ self._ssock.setblocking(False)
+ self._csock.setblocking(False)
+
+ fileno = self._csock.fileno()
+
+ self._old_signal_wakeup_id = _set_signal_wakeup_fd(fileno)
+ except Exception:
+ # Out of all statements in the try block, only the
+ # "_set_signal_wakeup_fd()" call can fail, but it shouldn't,
+ # as we ensure that the current thread is the main thread.
+ # Still, if something goes horribly wrong we want to clean up
+ # the socket pair.
+ self._ssock.close()
+ self._csock.close()
+ self._ssock = None
+ self._csock = None
+ raise
+
+ self._add_reader(
+ self._ssock,
+ new_MethodHandle(
+ self,
+ "Loop._read_from_self",
+ <method_t>self._read_from_self,
+ None,
+ self))
+
+ self._listening_signals = True
+
+ cdef _pause_signals(self):
+ if not self._is_main_thread():
+ if self._listening_signals:
+ raise RuntimeError(
+ 'cannot pause signals handling; no longer running in '
+ 'the main thread')
+ else:
+ return
+
+ if not self._listening_signals:
+ raise RuntimeError('signals handling has not been setup')
+
+ self._listening_signals = False
+
+ _set_signal_wakeup_fd(self._old_signal_wakeup_id)
+
+ self._remove_reader(self._ssock)
+ self._ssock.close()
+ self._csock.close()
+ self._ssock = None
+ self._csock = None
+
+ cdef _shutdown_signals(self):
+ if not self._is_main_thread():
+ if self._signal_handlers:
+ aio_logger.warning(
+ 'cannot cleanup signal handlers: closing the event loop '
+ 'in a non-main OS thread')
+ return
+
+ if self._listening_signals:
+ raise RuntimeError(
+ 'cannot shutdown signals handling as it has not been paused')
+
+ if self._ssock:
+ raise RuntimeError(
+ 'self-pipe was not cleaned up after loop was run')
+
+ for sig in list(self._signal_handlers):
+ self.remove_signal_handler(sig)
+
+ def __sighandler(self, signum, frame):
+ self._signals.add(signum)
+
+ cdef inline _ceval_process_signals(self):
+ # Invoke CPython eval loop to let process signals.
+ PyErr_CheckSignals()
+ # Calling a pure-Python function will invoke
+ # _PyEval_EvalFrameDefault which will process
+ # pending signal callbacks.
+ _noop.noop() # Might raise ^C
+
+ cdef _read_from_self(self):
+ cdef bytes sigdata
+ sigdata = b''
+ while True:
+ try:
+ data = self._ssock.recv(65536)
+ if not data:
+ break
+ sigdata += data
+ except InterruptedError:
+ continue
+ except BlockingIOError:
+ break
+ if sigdata:
+ self._invoke_signals(sigdata)
+
+ cdef _invoke_signals(self, bytes data):
+ cdef set sigs
+
+ self._ceval_process_signals()
+
+ sigs = self._signals.copy()
+ self._signals.clear()
+ for signum in data:
+ if not signum:
+ # ignore null bytes written by set_wakeup_fd()
+ continue
+ sigs.discard(signum)
+ self._handle_signal(signum)
+
+ for signum in sigs:
+ # Since not all signals are registered by add_signal_handler()
+ # (for instance, we use the default SIGINT handler) not all
+ # signals will trigger loop.__sighandler() callback. Therefore
+ # we combine two datasources: one is self-pipe, one is data
+ # from __sighandler; this ensures that signals shouldn't be
+ # lost even if set_wakeup_fd() couldn't write to the self-pipe.
+ self._handle_signal(signum)
+
+ cdef _handle_signal(self, sig):
+ cdef Handle handle
+
+ try:
+ handle = <Handle>(self._signal_handlers[sig])
+ except KeyError:
+ handle = None
+
+ if handle is None:
+ self._ceval_process_signals()
+ return
+
+ if handle._cancelled:
+ self.remove_signal_handler(sig) # Remove it properly.
+ else:
+ self._append_ready_handle(handle)
+ self.handler_async.send()
+
+ cdef _on_wake(self):
+ if ((self._ready_len > 0 or self._stopping) and
+ not self.handler_idle.running):
+ self.handler_idle.start()
+
+ cdef _on_idle(self):
+ cdef:
+ int i, ntodo
+ object popleft = self._ready.popleft
+ Handle handler
+
+ ntodo = len(self._ready)
+ if self._debug:
+ for i from 0 <= i < ntodo:
+ handler = <Handle> popleft()
+ if handler._cancelled == 0:
+ try:
+ started = time_monotonic()
+ handler._run()
+ except BaseException as ex:
+ self._stop(ex)
+ return
+ else:
+ delta = time_monotonic() - started
+ if delta > self.slow_callback_duration:
+ aio_logger.warning(
+ 'Executing %s took %.3f seconds',
+ handler._format_handle(), delta)
+
+ else:
+ for i from 0 <= i < ntodo:
+ handler = <Handle> popleft()
+ if handler._cancelled == 0:
+ try:
+ handler._run()
+ except BaseException as ex:
+ self._stop(ex)
+ return
+
+ if len(self._queued_streams):
+ self._exec_queued_writes()
+
+ self._ready_len = len(self._ready)
+ if self._ready_len == 0 and self.handler_idle.running:
+ self.handler_idle.stop()
+
+ if self._stopping:
+ uv.uv_stop(self.uvloop) # void
+
+ cdef _stop(self, exc):
+ if exc is not None:
+ self._last_error = exc
+ if self._stopping == 1:
+ return
+ self._stopping = 1
+ if not self.handler_idle.running:
+ self.handler_idle.start()
+
+ cdef __run(self, uv.uv_run_mode mode):
+ # Although every UVHandle holds a reference to the loop,
+ # we want to do everything to ensure that the loop will
+ # never deallocate during the run -- so we do some
+ # manual refs management.
+ Py_INCREF(self)
+ with nogil:
+ err = uv.uv_run(self.uvloop, mode)
+ Py_DECREF(self)
+
+ if err < 0:
+ raise convert_error(err)
+
+ cdef _run(self, uv.uv_run_mode mode):
+ cdef int err
+
+ if self._closed == 1:
+ raise RuntimeError('unable to start the loop; it was closed')
+
+ if self._running == 1:
+ raise RuntimeError('this event loop is already running.')
+
+ if (aio_get_running_loop is not None and
+ aio_get_running_loop() is not None):
+ raise RuntimeError(
+ 'Cannot run the event loop while another loop is running')
+
+ # reset _last_error
+ self._last_error = None
+
+ self._thread_id = PyThread_get_thread_ident()
+ self._running = 1
+
+ self.handler_check__exec_writes.start()
+ self.handler_idle.start()
+
+ self._setup_or_resume_signals()
+
+ if aio_set_running_loop is not None:
+ aio_set_running_loop(self)
+ try:
+ self.__run(mode)
+ finally:
+ if aio_set_running_loop is not None:
+ aio_set_running_loop(None)
+
+ self.handler_check__exec_writes.stop()
+ self.handler_idle.stop()
+
+ self._pause_signals()
+
+ self._thread_id = 0
+ self._running = 0
+ self._stopping = 0
+
+ if self._last_error is not None:
+ # The loop was stopped with an error with 'loop._stop(error)' call
+ raise self._last_error
+
+ cdef _close(self):
+ cdef int err
+
+ if self._running == 1:
+ raise RuntimeError("Cannot close a running event loop")
+
+ if self._closed == 1:
+ return
+
+ self._closed = 1
+
+ for cb_handle in self._ready:
+ cb_handle.cancel()
+ self._ready.clear()
+ self._ready_len = 0
+
+ if self._polls:
+ for poll_handle in self._polls.values():
+ (<UVHandle>poll_handle)._close()
+
+ self._polls.clear()
+
+ if self._timers:
+ for timer_cbhandle in tuple(self._timers):
+ timer_cbhandle.cancel()
+
+ # Close all remaining handles
+ self.handler_async._close()
+ self.handler_idle._close()
+ self.handler_check__exec_writes._close()
+ __close_all_handles(self)
+ self._shutdown_signals()
+ # During this run there should be no open handles,
+ # so it should finish right away
+ self.__run(uv.UV_RUN_DEFAULT)
+
+ if self._fd_to_writer_fileobj:
+ for fileobj in self._fd_to_writer_fileobj.values():
+ socket_dec_io_ref(fileobj)
+ self._fd_to_writer_fileobj.clear()
+
+ if self._fd_to_reader_fileobj:
+ for fileobj in self._fd_to_reader_fileobj.values():
+ socket_dec_io_ref(fileobj)
+ self._fd_to_reader_fileobj.clear()
+
+ if self._timers:
+ raise RuntimeError(
+ f"new timers were queued during loop closing: {self._timers}")
+
+ if self._polls:
+ raise RuntimeError(
+ f"new poll handles were queued during loop closing: "
+ f"{self._polls}")
+
+ if self._ready:
+ raise RuntimeError(
+ f"new callbacks were queued during loop closing: "
+ f"{self._ready}")
+
+ err = uv.uv_loop_close(self.uvloop)
+ if err < 0:
+ raise convert_error(err)
+
+ self.handler_async = None
+ self.handler_idle = None
+ self.handler_check__exec_writes = None
+
+ self._executor_shutdown_called = True
+ executor = self._default_executor
+ if executor is not None:
+ self._default_executor = None
+ executor.shutdown(wait=False)
+
+ cdef uint64_t _time(self):
+ # asyncio doesn't have a time cache, neither should uvloop.
+ uv.uv_update_time(self.uvloop) # void
+ return uv.uv_now(self.uvloop)
+
+ cdef inline _queue_write(self, UVStream stream):
+ self._queued_streams.add(stream)
+ if not self.handler_check__exec_writes.running:
+ self.handler_check__exec_writes.start()
+
+ cdef _exec_queued_writes(self):
+ if len(self._queued_streams) == 0:
+ if self.handler_check__exec_writes.running:
+ self.handler_check__exec_writes.stop()
+ return
+
+ cdef:
+ UVStream stream
+
+ streams = self._queued_streams
+ self._queued_streams = self._executing_streams
+ self._executing_streams = streams
+ try:
+ for pystream in streams:
+ stream = <UVStream>pystream
+ stream._exec_write()
+ finally:
+ streams.clear()
+
+ if self.handler_check__exec_writes.running:
+ if len(self._queued_streams) == 0:
+ self.handler_check__exec_writes.stop()
+
+ cdef inline _call_soon(self, object callback, object args, object context):
+ cdef Handle handle
+ handle = new_Handle(self, callback, args, context)
+ self._call_soon_handle(handle)
+ return handle
+
+ cdef inline _append_ready_handle(self, Handle handle):
+ self._check_closed()
+ self._ready.append(handle)
+ self._ready_len += 1
+
+ cdef inline _call_soon_handle(self, Handle handle):
+ self._append_ready_handle(handle)
+ if not self.handler_idle.running:
+ self.handler_idle.start()
+
+ cdef _call_later(self, uint64_t delay, object callback, object args,
+ object context):
+ return TimerHandle(self, callback, args, delay, context)
+
+ cdef void _handle_exception(self, object ex):
+ if isinstance(ex, Exception):
+ self.call_exception_handler({'exception': ex})
+ else:
+ # BaseException
+ self._last_error = ex
+ # Exit ASAP
+ self._stop(None)
+
+ cdef inline _check_signal(self, sig):
+ if not isinstance(sig, int):
+ raise TypeError('sig must be an int, not {!r}'.format(sig))
+
+ if not (1 <= sig < signal_NSIG):
+ raise ValueError(
+ 'sig {} out of range(1, {})'.format(sig, signal_NSIG))
+
+ cdef inline _check_closed(self):
+ if self._closed == 1:
+ raise RuntimeError('Event loop is closed')
+
+ cdef inline _check_thread(self):
+ if self._thread_id == 0:
+ return
+
+ cdef uint64_t thread_id
+ thread_id = <uint64_t>PyThread_get_thread_ident()
+
+ if thread_id != self._thread_id:
+ raise RuntimeError(
+ "Non-thread-safe operation invoked on an event loop other "
+ "than the current one")
+
+ cdef inline _new_future(self):
+ return aio_Future(loop=self)
+
+ cdef _track_transport(self, UVBaseTransport transport):
+ self._transports[transport._fileno()] = transport
+
+ cdef _track_process(self, UVProcess proc):
+ self._processes.add(proc)
+
+ cdef _untrack_process(self, UVProcess proc):
+ self._processes.discard(proc)
+
+ cdef _fileobj_to_fd(self, fileobj):
+ """Return a file descriptor from a file object.
+
+ Parameters:
+ fileobj -- file object or file descriptor
+
+ Returns:
+ corresponding file descriptor
+
+ Raises:
+ ValueError if the object is invalid
+ """
+ # Copy of the `selectors._fileobj_to_fd()` function.
+ if isinstance(fileobj, int):
+ fd = fileobj
+ else:
+ try:
+ fd = int(fileobj.fileno())
+ except (AttributeError, TypeError, ValueError):
+ raise ValueError("Invalid file object: "
+ "{!r}".format(fileobj)) from None
+ if fd < 0:
+ raise ValueError("Invalid file descriptor: {}".format(fd))
+ return fd
+
+ cdef _ensure_fd_no_transport(self, fd):
+ cdef UVBaseTransport tr
+ try:
+ tr = <UVBaseTransport>(self._transports[fd])
+ except KeyError:
+ pass
+ else:
+ if tr._is_alive():
+ raise RuntimeError(
+ 'File descriptor {!r} is used by transport {!r}'.format(
+ fd, tr))
+
+ cdef _add_reader(self, fileobj, Handle handle):
+ cdef:
+ UVPoll poll
+
+ self._check_closed()
+ fd = self._fileobj_to_fd(fileobj)
+ self._ensure_fd_no_transport(fd)
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ poll = UVPoll.new(self, fd)
+ self._polls[fd] = poll
+
+ poll.start_reading(handle)
+
+ old_fileobj = self._fd_to_reader_fileobj.pop(fd, None)
+ if old_fileobj is not None:
+ socket_dec_io_ref(old_fileobj)
+
+ self._fd_to_reader_fileobj[fd] = fileobj
+ socket_inc_io_ref(fileobj)
+
+ cdef _remove_reader(self, fileobj):
+ cdef:
+ UVPoll poll
+
+ fd = self._fileobj_to_fd(fileobj)
+ self._ensure_fd_no_transport(fd)
+
+ mapped_fileobj = self._fd_to_reader_fileobj.pop(fd, None)
+ if mapped_fileobj is not None:
+ socket_dec_io_ref(mapped_fileobj)
+
+ if self._closed == 1:
+ return False
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ return False
+
+ result = poll.stop_reading()
+ if not poll.is_active():
+ del self._polls[fd]
+ poll._close()
+
+ return result
+
+ cdef _has_reader(self, fileobj):
+ cdef:
+ UVPoll poll
+
+ self._check_closed()
+ fd = self._fileobj_to_fd(fileobj)
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ return False
+
+ return poll.is_reading()
+
+ cdef _add_writer(self, fileobj, Handle handle):
+ cdef:
+ UVPoll poll
+
+ self._check_closed()
+ fd = self._fileobj_to_fd(fileobj)
+ self._ensure_fd_no_transport(fd)
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ poll = UVPoll.new(self, fd)
+ self._polls[fd] = poll
+
+ poll.start_writing(handle)
+
+ old_fileobj = self._fd_to_writer_fileobj.pop(fd, None)
+ if old_fileobj is not None:
+ socket_dec_io_ref(old_fileobj)
+
+ self._fd_to_writer_fileobj[fd] = fileobj
+ socket_inc_io_ref(fileobj)
+
+ cdef _remove_writer(self, fileobj):
+ cdef:
+ UVPoll poll
+
+ fd = self._fileobj_to_fd(fileobj)
+ self._ensure_fd_no_transport(fd)
+
+ mapped_fileobj = self._fd_to_writer_fileobj.pop(fd, None)
+ if mapped_fileobj is not None:
+ socket_dec_io_ref(mapped_fileobj)
+
+ if self._closed == 1:
+ return False
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ return False
+
+ result = poll.stop_writing()
+ if not poll.is_active():
+ del self._polls[fd]
+ poll._close()
+
+ return result
+
+ cdef _has_writer(self, fileobj):
+ cdef:
+ UVPoll poll
+
+ self._check_closed()
+ fd = self._fileobj_to_fd(fileobj)
+
+ try:
+ poll = <UVPoll>(self._polls[fd])
+ except KeyError:
+ return False
+
+ return poll.is_writing()
+
+ cdef _getaddrinfo(self, object host, object port,
+ int family, int type,
+ int proto, int flags,
+ int unpack):
+
+ if isinstance(port, str):
+ port = port.encode()
+ elif isinstance(port, int):
+ port = str(port).encode()
+ if port is not None and not isinstance(port, bytes):
+ raise TypeError('port must be a str, bytes or int')
+
+ if isinstance(host, str):
+ host = host.encode('idna')
+ if host is not None:
+ if not isinstance(host, bytes):
+ raise TypeError('host must be a str or bytes')
+
+ fut = self._new_future()
+
+ def callback(result):
+ if AddrInfo.isinstance(result):
+ try:
+ if unpack == 0:
+ data = result
+ else:
+ data = (<AddrInfo>result).unpack()
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as ex:
+ if not fut.cancelled():
+ fut.set_exception(ex)
+ else:
+ if not fut.cancelled():
+ fut.set_result(data)
+ else:
+ if not fut.cancelled():
+ fut.set_exception(result)
+
+ AddrInfoRequest(self, host, port, family, type, proto, flags, callback)
+ return fut
+
+ cdef _getnameinfo(self, system.sockaddr *addr, int flags):
+ cdef NameInfoRequest nr
+ fut = self._new_future()
+
+ def callback(result):
+ if isinstance(result, tuple):
+ fut.set_result(result)
+ else:
+ fut.set_exception(result)
+
+ nr = NameInfoRequest(self, callback)
+ nr.query(addr, flags)
+ return fut
+
+ cdef _sock_recv(self, fut, sock, n):
+ if UVLOOP_DEBUG:
+ if fut.cancelled():
+ # Shouldn't happen with _SyncSocketReaderFuture.
+ raise RuntimeError(
+ f'_sock_recv is called on a cancelled Future')
+
+ if not self._has_reader(sock):
+ raise RuntimeError(
+ f'socket {sock!r} does not have a reader '
+ f'in the _sock_recv callback')
+
+ try:
+ data = sock.recv(n)
+ except (BlockingIOError, InterruptedError):
+ # No need to re-add the reader, let's just wait until
+ # the poll handler calls this callback again.
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ fut.set_exception(exc)
+ self._remove_reader(sock)
+ else:
+ fut.set_result(data)
+ self._remove_reader(sock)
+
+ cdef _sock_recv_into(self, fut, sock, buf):
+ if UVLOOP_DEBUG:
+ if fut.cancelled():
+ # Shouldn't happen with _SyncSocketReaderFuture.
+ raise RuntimeError(
+ f'_sock_recv_into is called on a cancelled Future')
+
+ if not self._has_reader(sock):
+ raise RuntimeError(
+ f'socket {sock!r} does not have a reader '
+ f'in the _sock_recv_into callback')
+
+ try:
+ data = sock.recv_into(buf)
+ except (BlockingIOError, InterruptedError):
+ # No need to re-add the reader, let's just wait until
+ # the poll handler calls this callback again.
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ fut.set_exception(exc)
+ self._remove_reader(sock)
+ else:
+ fut.set_result(data)
+ self._remove_reader(sock)
+
+ cdef _sock_sendall(self, fut, sock, data):
+ cdef:
+ Handle handle
+ int n
+
+ if UVLOOP_DEBUG:
+ if fut.cancelled():
+ # Shouldn't happen with _SyncSocketWriterFuture.
+ raise RuntimeError(
+ f'_sock_sendall is called on a cancelled Future')
+
+ if not self._has_writer(sock):
+ raise RuntimeError(
+ f'socket {sock!r} does not have a writer '
+ f'in the _sock_sendall callback')
+
+ try:
+ n = sock.send(data)
+ except (BlockingIOError, InterruptedError):
+ # Try next time.
+ return
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ fut.set_exception(exc)
+ self._remove_writer(sock)
+ return
+
+ self._remove_writer(sock)
+
+ if n == len(data):
+ fut.set_result(None)
+ else:
+ if n:
+ if not isinstance(data, memoryview):
+ data = memoryview(data)
+ data = data[n:]
+
+ handle = new_MethodHandle3(
+ self,
+ "Loop._sock_sendall",
+ <method3_t>self._sock_sendall,
+ None,
+ self,
+ fut, sock, data)
+
+ self._add_writer(sock, handle)
+
+ cdef _sock_accept(self, fut, sock):
+ try:
+ conn, address = sock.accept()
+ conn.setblocking(False)
+ except (BlockingIOError, InterruptedError):
+ # There is an active reader for _sock_accept, so
+ # do nothing, it will be called again.
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ fut.set_exception(exc)
+ self._remove_reader(sock)
+ else:
+ fut.set_result((conn, address))
+ self._remove_reader(sock)
+
+ cdef _sock_connect(self, sock, address):
+ cdef:
+ Handle handle
+
+ try:
+ sock.connect(address)
+ except (BlockingIOError, InterruptedError):
+ pass
+ else:
+ return
+
+ fut = _SyncSocketWriterFuture(sock, self)
+ handle = new_MethodHandle3(
+ self,
+ "Loop._sock_connect",
+ <method3_t>self._sock_connect_cb,
+ None,
+ self,
+ fut, sock, address)
+
+ self._add_writer(sock, handle)
+ return fut
+
+ cdef _sock_connect_cb(self, fut, sock, address):
+ if UVLOOP_DEBUG:
+ if fut.cancelled():
+ # Shouldn't happen with _SyncSocketWriterFuture.
+ raise RuntimeError(
+ f'_sock_connect_cb is called on a cancelled Future')
+
+ if not self._has_writer(sock):
+ raise RuntimeError(
+ f'socket {sock!r} does not have a writer '
+ f'in the _sock_connect_cb callback')
+
+ try:
+ err = sock.getsockopt(uv.SOL_SOCKET, uv.SO_ERROR)
+ if err != 0:
+ # Jump to any except clause below.
+ raise OSError(err, 'Connect call failed %s' % (address,))
+ except (BlockingIOError, InterruptedError):
+ # socket is still registered, the callback will be retried later
+ pass
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ fut.set_exception(exc)
+ self._remove_writer(sock)
+ else:
+ fut.set_result(None)
+ self._remove_writer(sock)
+
+ cdef _sock_set_reuseport(self, int fd):
+ cdef:
+ int err
+ int reuseport_flag = 1
+
+ err = system.setsockopt(
+ fd,
+ uv.SOL_SOCKET,
+ SO_REUSEPORT,
+ <char*>&reuseport_flag,
+ sizeof(reuseport_flag))
+
+ if err < 0:
+ raise convert_error(-errno.errno)
+
+ cdef _set_coroutine_debug(self, bint enabled):
+ enabled = bool(enabled)
+ if self._coroutine_debug_set == enabled:
+ return
+
+ if enabled:
+ self._coroutine_origin_tracking_saved_depth = (
+ sys.get_coroutine_origin_tracking_depth())
+ sys.set_coroutine_origin_tracking_depth(
+ DEBUG_STACK_DEPTH)
+ else:
+ sys.set_coroutine_origin_tracking_depth(
+ self._coroutine_origin_tracking_saved_depth)
+
+ self._coroutine_debug_set = enabled
+
+ def _get_backend_id(self):
+ """This method is used by uvloop tests and is not part of the API."""
+ return uv.uv_backend_fd(self.uvloop)
+
+ cdef _print_debug_info(self):
+ cdef:
+ int err
+ uv.uv_rusage_t rusage
+
+ err = uv.uv_getrusage(&rusage)
+ if err < 0:
+ raise convert_error(err)
+
+ # OS
+
+ print('---- Process info: -----')
+ print('Process memory: {}'.format(rusage.ru_maxrss))
+ print('Number of signals: {}'.format(rusage.ru_nsignals))
+ print('')
+
+ # Loop
+
+ print('--- Loop debug info: ---')
+ print('Loop time: {}'.format(self.time()))
+ print('Errors logged: {}'.format(
+ self._debug_exception_handler_cnt))
+ print()
+ print('Callback handles: {: <8} | {}'.format(
+ self._debug_cb_handles_count,
+ self._debug_cb_handles_total))
+ print('Timer handles: {: <8} | {}'.format(
+ self._debug_cb_timer_handles_count,
+ self._debug_cb_timer_handles_total))
+ print()
+
+ print(' alive | closed |')
+ print('UVHandles python | libuv | total')
+ print(' objs | handles |')
+ print('-------------------------------+---------+---------')
+ for name in sorted(self._debug_handles_total):
+ print(' {: <18} {: >7} | {: >7} | {: >7}'.format(
+ name,
+ self._debug_handles_current[name],
+ self._debug_handles_closed[name],
+ self._debug_handles_total[name]))
+ print()
+
+ print('uv_handle_t (current: {}; freed: {}; total: {})'.format(
+ self._debug_uv_handles_total - self._debug_uv_handles_freed,
+ self._debug_uv_handles_freed,
+ self._debug_uv_handles_total))
+ print()
+
+ print('--- Streams debug info: ---')
+ print('Write errors: {}'.format(
+ self._debug_stream_write_errors_total))
+ print('Write without poll: {}'.format(
+ self._debug_stream_write_tries))
+ print('Write contexts: {: <8} | {}'.format(
+ self._debug_stream_write_ctx_cnt,
+ self._debug_stream_write_ctx_total))
+ print('Write failed callbacks: {}'.format(
+ self._debug_stream_write_cb_errors_total))
+ print()
+ print('Read errors: {}'.format(
+ self._debug_stream_read_errors_total))
+ print('Read callbacks: {}'.format(
+ self._debug_stream_read_cb_total))
+ print('Read failed callbacks: {}'.format(
+ self._debug_stream_read_cb_errors_total))
+ print('Read EOFs: {}'.format(
+ self._debug_stream_read_eof_total))
+ print('Read EOF failed callbacks: {}'.format(
+ self._debug_stream_read_eof_cb_errors_total))
+ print()
+ print('Listen errors: {}'.format(
+ self._debug_stream_listen_errors_total))
+ print('Shutdown errors {}'.format(
+ self._debug_stream_shutdown_errors_total))
+ print()
+
+ print('--- Polls debug info: ---')
+ print('Read events: {}'.format(
+ self._poll_read_events_total))
+ print('Read callbacks failed: {}'.format(
+ self._poll_read_cb_errors_total))
+ print('Write events: {}'.format(
+ self._poll_write_events_total))
+ print('Write callbacks failed: {}'.format(
+ self._poll_write_cb_errors_total))
+ print()
+
+ print('--- Sock ops successful on 1st try: ---')
+ print('Socket try-writes: {}'.format(
+ self._sock_try_write_total))
+
+ print(flush=True)
+
+ property print_debug_info:
+ def __get__(self):
+ if UVLOOP_DEBUG:
+ return lambda: self._print_debug_info()
+ else:
+ raise AttributeError('print_debug_info')
+
+ # Public API
+
+ def __repr__(self):
+ return '<{}.{} running={} closed={} debug={}>'.format(
+ self.__class__.__module__,
+ self.__class__.__name__,
+ self.is_running(),
+ self.is_closed(),
+ self.get_debug()
+ )
+
+ def call_soon(self, callback, *args, context=None):
+ """Arrange for a callback to be called as soon as possible.
+
+ This operates as a FIFO queue: callbacks are called in the
+ order in which they are registered. Each callback will be
+ called exactly once.
+
+ Any positional arguments after the callback will be passed to
+ the callback when it is called.
+ """
+ if self._debug == 1:
+ self._check_thread()
+ if args:
+ return self._call_soon(callback, args, context)
+ else:
+ return self._call_soon(callback, None, context)
+
+ def call_soon_threadsafe(self, callback, *args, context=None):
+ """Like call_soon(), but thread-safe."""
+ if not args:
+ args = None
+ cdef Handle handle = new_Handle(self, callback, args, context)
+ self._append_ready_handle(handle) # deque append is atomic
+ # libuv async handler is thread-safe while the idle handler is not -
+ # we only set the async handler here, which will start the idle handler
+ # in _on_wake() from the loop and eventually call the callback.
+ self.handler_async.send()
+ return handle
+
+ def call_later(self, delay, callback, *args, context=None):
+ """Arrange for a callback to be called at a given time.
+
+ Return a Handle: an opaque object with a cancel() method that
+ can be used to cancel the call.
+
+ The delay can be an int or float, expressed in seconds. It is
+ always relative to the current time.
+
+ Each callback will be called exactly once. If two callbacks
+ are scheduled for exactly the same time, it undefined which
+ will be called first.
+
+ Any positional arguments after the callback will be passed to
+ the callback when it is called.
+ """
+ cdef uint64_t when
+
+ self._check_closed()
+ if self._debug == 1:
+ self._check_thread()
+
+ if delay < 0:
+ delay = 0
+ elif delay == py_inf or delay > MAX_SLEEP:
+ # ~100 years sounds like a good approximation of
+ # infinity for a Python application.
+ delay = MAX_SLEEP
+
+ when = <uint64_t>round(delay * 1000)
+ if not args:
+ args = None
+ if when == 0:
+ return self._call_soon(callback, args, context)
+ else:
+ return self._call_later(when, callback, args, context)
+
+ def call_at(self, when, callback, *args, context=None):
+ """Like call_later(), but uses an absolute time.
+
+ Absolute time corresponds to the event loop's time() method.
+ """
+ return self.call_later(
+ when - self.time(), callback, *args, context=context)
+
+ def time(self):
+ """Return the time according to the event loop's clock.
+
+ This is a float expressed in seconds since an epoch, but the
+ epoch, precision, accuracy and drift are unspecified and may
+ differ per event loop.
+ """
+ return self._time() / 1000
+
+ def stop(self):
+ """Stop running the event loop.
+
+ Every callback already scheduled will still run. This simply informs
+ run_forever to stop looping after a complete iteration.
+ """
+ self._call_soon_handle(
+ new_MethodHandle1(
+ self,
+ "Loop._stop",
+ <method1_t>self._stop,
+ None,
+ self,
+ None))
+
+ def run_forever(self):
+ """Run the event loop until stop() is called."""
+ self._check_closed()
+ mode = uv.UV_RUN_DEFAULT
+ if self._stopping:
+ # loop.stop() was called right before loop.run_forever().
+ # This is how asyncio loop behaves.
+ mode = uv.UV_RUN_NOWAIT
+ self._set_coroutine_debug(self._debug)
+ old_agen_hooks = sys.get_asyncgen_hooks()
+ sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook,
+ finalizer=self._asyncgen_finalizer_hook)
+ try:
+ self._run(mode)
+ finally:
+ self._set_coroutine_debug(False)
+ sys.set_asyncgen_hooks(*old_agen_hooks)
+
+ def close(self):
+ """Close the event loop.
+
+ The event loop must not be running.
+
+ This is idempotent and irreversible.
+
+ No other methods should be called after this one.
+ """
+ self._close()
+
+ def get_debug(self):
+ return bool(self._debug)
+
+ def set_debug(self, enabled):
+ self._debug = bool(enabled)
+ if self.is_running():
+ self.call_soon_threadsafe(
+ self._set_coroutine_debug, self, self._debug)
+
+ def is_running(self):
+ """Return whether the event loop is currently running."""
+ return bool(self._running)
+
+ def is_closed(self):
+ """Returns True if the event loop was closed."""
+ return bool(self._closed)
+
+ def create_future(self):
+ """Create a Future object attached to the loop."""
+ return self._new_future()
+
+ def create_task(self, coro, *, name=None, context=None):
+ """Schedule a coroutine object.
+
+ Return a task object.
+
+ If name is not None, task.set_name(name) will be called if the task
+ object has the set_name attribute, true for default Task in CPython.
+
+ An optional keyword-only context argument allows specifying a custom
+ contextvars.Context for the coro to run in. The current context copy is
+ created when no context is provided.
+ """
+ self._check_closed()
+ if PY311:
+ if self._task_factory is None:
+ task = aio_Task(coro, loop=self, context=context)
+ else:
+ task = self._task_factory(self, coro, context=context)
+ else:
+ if context is None:
+ if self._task_factory is None:
+ task = aio_Task(coro, loop=self)
+ else:
+ task = self._task_factory(self, coro)
+ else:
+ if self._task_factory is None:
+ task = context.run(aio_Task, coro, self)
+ else:
+ task = context.run(self._task_factory, self, coro)
+
+ # copied from asyncio.tasks._set_task_name (bpo-34270)
+ if name is not None:
+ try:
+ set_name = task.set_name
+ except AttributeError:
+ pass
+ else:
+ set_name(name)
+
+ return task
+
+ def set_task_factory(self, factory):
+ """Set a task factory that will be used by loop.create_task().
+
+ If factory is None the default task factory will be set.
+
+ If factory is a callable, it should have a signature matching
+ '(loop, coro)', where 'loop' will be a reference to the active
+ event loop, 'coro' will be a coroutine object. The callable
+ must return a Future.
+ """
+ if factory is not None and not callable(factory):
+ raise TypeError('task factory must be a callable or None')
+ self._task_factory = factory
+
+ def get_task_factory(self):
+ """Return a task factory, or None if the default one is in use."""
+ return self._task_factory
+
+ def run_until_complete(self, future):
+ """Run until the Future is done.
+
+ If the argument is a coroutine, it is wrapped in a Task.
+
+ WARNING: It would be disastrous to call run_until_complete()
+ with the same coroutine twice -- it would wrap it in two
+ different Tasks and that can't be good.
+
+ Return the Future's result, or raise its exception.
+ """
+ self._check_closed()
+
+ new_task = not isfuture(future)
+ future = aio_ensure_future(future, loop=self)
+ if new_task:
+ # An exception is raised if the future didn't complete, so there
+ # is no need to log the "destroy pending task" message
+ future._log_destroy_pending = False
+
+ def done_cb(fut):
+ if not fut.cancelled():
+ exc = fut.exception()
+ if isinstance(exc, (SystemExit, KeyboardInterrupt)):
+ # Issue #336: run_forever() already finished,
+ # no need to stop it.
+ return
+ self.stop()
+
+ future.add_done_callback(done_cb)
+ try:
+ self.run_forever()
+ except BaseException:
+ if new_task and future.done() and not future.cancelled():
+ # The coroutine raised a BaseException. Consume the exception
+ # to not log a warning, the caller doesn't have access to the
+ # local task.
+ future.exception()
+ raise
+ finally:
+ future.remove_done_callback(done_cb)
+ if not future.done():
+ raise RuntimeError('Event loop stopped before Future completed.')
+
+ return future.result()
+
+ @cython.iterable_coroutine
+ async def getaddrinfo(self, object host, object port, *,
+ int family=0, int type=0, int proto=0, int flags=0):
+
+ addr = __static_getaddrinfo_pyaddr(host, port, family,
+ type, proto, flags)
+ if addr is not None:
+ return [addr]
+
+ return await self._getaddrinfo(
+ host, port, family, type, proto, flags, 1)
+
+ @cython.iterable_coroutine
+ async def getnameinfo(self, sockaddr, int flags=0):
+ cdef:
+ AddrInfo ai_cnt
+ system.addrinfo *ai
+ system.sockaddr_in6 *sin6
+
+ if not isinstance(sockaddr, tuple):
+ raise TypeError('getnameinfo() argument 1 must be a tuple')
+
+ sl = len(sockaddr)
+
+ if sl < 2 or sl > 4:
+ raise ValueError('sockaddr must be a tuple of 2, 3 or 4 values')
+
+ if sl > 2:
+ flowinfo = sockaddr[2]
+ if flowinfo < 0 or flowinfo > 0xfffff:
+ raise OverflowError(
+ 'getnameinfo(): flowinfo must be 0-1048575.')
+ else:
+ flowinfo = 0
+
+ if sl > 3:
+ scope_id = sockaddr[3]
+ if scope_id < 0 or scope_id > 2 ** 32:
+ raise OverflowError(
+ 'getsockaddrarg: scope_id must be unsigned 32 bit integer')
+ else:
+ scope_id = 0
+
+ ai_cnt = await self._getaddrinfo(
+ sockaddr[0], sockaddr[1],
+ uv.AF_UNSPEC, # family
+ uv.SOCK_DGRAM, # type
+ 0, # proto
+ uv.AI_NUMERICHOST, # flags
+ 0) # unpack
+
+ ai = ai_cnt.data
+
+ if ai.ai_next:
+ raise OSError("sockaddr resolved to multiple addresses")
+
+ if ai.ai_family == uv.AF_INET:
+ if sl > 2:
+ raise OSError("IPv4 sockaddr must be 2 tuple")
+ elif ai.ai_family == uv.AF_INET6:
+ # Modify some fields in `ai`
+ sin6 = <system.sockaddr_in6*> ai.ai_addr
+ sin6.sin6_flowinfo = system.htonl(flowinfo)
+ sin6.sin6_scope_id = scope_id
+
+ return await self._getnameinfo(ai.ai_addr, flags)
+
+ @cython.iterable_coroutine
+ async def start_tls(self, transport, protocol, sslcontext, *,
+ server_side=False,
+ server_hostname=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None):
+ """Upgrade transport to TLS.
+
+ Return a new transport that *protocol* should start using
+ immediately.
+ """
+ if not isinstance(sslcontext, ssl_SSLContext):
+ raise TypeError(
+ f'sslcontext is expected to be an instance of ssl.SSLContext, '
+ f'got {sslcontext!r}')
+
+ if isinstance(transport, (TCPTransport, UnixTransport)):
+ context = (<UVStream>transport).context
+ elif isinstance(transport, _SSLProtocolTransport):
+ context = (<_SSLProtocolTransport>transport).context
+ else:
+ raise TypeError(
+ f'transport {transport!r} is not supported by start_tls()')
+
+ waiter = self._new_future()
+ ssl_protocol = SSLProtocol(
+ self, protocol, sslcontext, waiter,
+ server_side, server_hostname,
+ ssl_handshake_timeout=ssl_handshake_timeout,
+ ssl_shutdown_timeout=ssl_shutdown_timeout,
+ call_connection_made=False)
+
+ # Pause early so that "ssl_protocol.data_received()" doesn't
+ # have a chance to get called before "ssl_protocol.connection_made()".
+ transport.pause_reading()
+
+ transport.set_protocol(ssl_protocol)
+ conmade_cb = self.call_soon(ssl_protocol.connection_made, transport,
+ context=context)
+ # transport.resume_reading() will use the right context
+ # (transport.context) to call e.g. data_received()
+ resume_cb = self.call_soon(transport.resume_reading)
+ app_transport = ssl_protocol._get_app_transport(context)
+
+ try:
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ app_transport.close()
+ conmade_cb.cancel()
+ resume_cb.cancel()
+ raise
+
+ return app_transport
+
+ @cython.iterable_coroutine
+ async def create_server(self, protocol_factory, host=None, port=None,
+ *,
+ int family=uv.AF_UNSPEC,
+ int flags=uv.AI_PASSIVE,
+ sock=None,
+ backlog=100,
+ ssl=None,
+ reuse_address=None,
+ reuse_port=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None,
+ start_serving=True):
+ """A coroutine which creates a TCP server bound to host and port.
+
+ The return value is a Server object which can be used to stop
+ the service.
+
+ If host is an empty string or None all interfaces are assumed
+ and a list of multiple sockets will be returned (most likely
+ one for IPv4 and another one for IPv6). The host parameter can also be
+ a sequence (e.g. list) of hosts to bind to.
+
+ family can be set to either AF_INET or AF_INET6 to force the
+ socket to use IPv4 or IPv6. If not set it will be determined
+ from host (defaults to AF_UNSPEC).
+
+ flags is a bitmask for getaddrinfo().
+
+ sock can optionally be specified in order to use a preexisting
+ socket object.
+
+ backlog is the maximum number of queued connections passed to
+ listen() (defaults to 100).
+
+ ssl can be set to an SSLContext to enable SSL over the
+ accepted connections.
+
+ reuse_address tells the kernel to reuse a local socket in
+ TIME_WAIT state, without waiting for its natural timeout to
+ expire. If not specified will automatically be set to True on
+ UNIX.
+
+ reuse_port tells the kernel to allow this endpoint to be bound to
+ the same port as other existing endpoints are bound to, so long as
+ they all set this flag when being created. This option is not
+ supported on Windows.
+
+ ssl_handshake_timeout is the time in seconds that an SSL server
+ will wait for completion of the SSL handshake before aborting the
+ connection. Default is 60s.
+
+ ssl_shutdown_timeout is the time in seconds that an SSL server
+ will wait for completion of the SSL shutdown before aborting the
+ connection. Default is 30s.
+ """
+ cdef:
+ TCPServer tcp
+ system.addrinfo *addrinfo
+ Server server
+
+ if sock is not None and sock.family == uv.AF_UNIX:
+ if host is not None or port is not None:
+ raise ValueError(
+ 'host/port and sock can not be specified at the same time')
+ return await self.create_unix_server(
+ protocol_factory, sock=sock, backlog=backlog, ssl=ssl,
+ start_serving=start_serving)
+
+ server = Server(self)
+
+ if ssl is not None:
+ if not isinstance(ssl, ssl_SSLContext):
+ raise TypeError('ssl argument must be an SSLContext or None')
+ 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')
+
+ if host is not None or port is not None:
+ if sock is not None:
+ raise ValueError(
+ 'host/port and sock can not be specified at the same time')
+
+ if reuse_address is None:
+ reuse_address = os_name == 'posix' and sys_platform != 'cygwin'
+ reuse_port = bool(reuse_port)
+ if reuse_port and not has_SO_REUSEPORT:
+ raise ValueError(
+ 'reuse_port not supported by socket module')
+
+ if host == '':
+ hosts = [None]
+ elif (isinstance(host, str) or not isinstance(host, col_Iterable)):
+ hosts = [host]
+ else:
+ hosts = host
+
+ fs = [self._getaddrinfo(host, port, family,
+ uv.SOCK_STREAM, 0, flags,
+ 0) for host in hosts]
+
+ infos = await aio_gather(*fs)
+
+ completed = False
+ sock = None
+ try:
+ for info in infos:
+ addrinfo = (<AddrInfo>info).data
+ while addrinfo != NULL:
+ if addrinfo.ai_family == uv.AF_UNSPEC:
+ raise RuntimeError('AF_UNSPEC in DNS results')
+
+ try:
+ sock = socket_socket(addrinfo.ai_family,
+ addrinfo.ai_socktype,
+ addrinfo.ai_protocol)
+ except socket_error:
+ # Assume it's a bad family/type/protocol
+ # combination.
+ if self._debug:
+ aio_logger.warning(
+ 'create_server() failed to create '
+ 'socket.socket(%r, %r, %r)',
+ addrinfo.ai_family,
+ addrinfo.ai_socktype,
+ addrinfo.ai_protocol, exc_info=True)
+ addrinfo = addrinfo.ai_next
+ continue
+
+ if reuse_address:
+ sock.setsockopt(uv.SOL_SOCKET, uv.SO_REUSEADDR, 1)
+ if reuse_port:
+ sock.setsockopt(uv.SOL_SOCKET, uv.SO_REUSEPORT, 1)
+ # Disable IPv4/IPv6 dual stack support (enabled by
+ # default on Linux) which makes a single socket
+ # listen on both address families.
+ if (addrinfo.ai_family == uv.AF_INET6 and
+ has_IPV6_V6ONLY):
+ sock.setsockopt(uv.IPPROTO_IPV6, IPV6_V6ONLY, 1)
+
+ pyaddr = __convert_sockaddr_to_pyaddr(addrinfo.ai_addr)
+ try:
+ sock.bind(pyaddr)
+ except OSError as err:
+ raise OSError(
+ err.errno, 'error while attempting '
+ 'to bind on address %r: %s'
+ % (pyaddr, err.strerror.lower())) from None
+
+ tcp = TCPServer.new(self, protocol_factory, server,
+ uv.AF_UNSPEC, backlog,
+ ssl, ssl_handshake_timeout,
+ ssl_shutdown_timeout)
+
+ try:
+ tcp._open(sock.fileno())
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ tcp._close()
+ raise
+
+ server._add_server(tcp)
+ sock.detach()
+ sock = None
+
+ addrinfo = addrinfo.ai_next
+
+ completed = True
+ finally:
+ if not completed:
+ if sock is not None:
+ sock.close()
+ server.close()
+ else:
+ if sock is None:
+ raise ValueError('Neither host/port nor sock were specified')
+ if not _is_sock_stream(sock.type):
+ raise ValueError(
+ 'A Stream Socket was expected, got {!r}'.format(sock))
+
+ # libuv will set the socket to non-blocking mode, but
+ # we want Python socket object to notice that.
+ sock.setblocking(False)
+
+ tcp = TCPServer.new(self, protocol_factory, server,
+ uv.AF_UNSPEC, backlog,
+ ssl, ssl_handshake_timeout,
+ ssl_shutdown_timeout)
+
+ try:
+ tcp._open(sock.fileno())
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ tcp._close()
+ raise
+
+ tcp._attach_fileobj(sock)
+ server._add_server(tcp)
+
+ if start_serving:
+ server._start_serving()
+
+ server._ref()
+ return server
+
+ @cython.iterable_coroutine
+ async def create_connection(self, protocol_factory, host=None, port=None,
+ *,
+ ssl=None,
+ family=0, proto=0, flags=0, sock=None,
+ local_addr=None, server_hostname=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None):
+ """Connect to a TCP server.
+
+ Create a streaming transport connection to a given Internet host and
+ port: socket family AF_INET or socket.AF_INET6 depending on host (or
+ family if specified), socket type SOCK_STREAM. protocol_factory must be
+ a callable returning a protocol instance.
+
+ This method is a coroutine which will try to establish the connection
+ in the background. When successful, the coroutine returns a
+ (transport, protocol) pair.
+ """
+ cdef:
+ AddrInfo ai_local = None
+ AddrInfo ai_remote
+ TCPTransport tr
+
+ system.addrinfo *rai = NULL
+ system.addrinfo *lai = NULL
+
+ system.addrinfo *rai_iter = NULL
+ system.addrinfo *lai_iter = NULL
+
+ system.addrinfo rai_static
+ system.sockaddr_storage rai_addr_static
+ system.addrinfo lai_static
+ system.sockaddr_storage lai_addr_static
+
+ object app_protocol
+ object app_transport
+ object protocol
+ object ssl_waiter
+
+ if sock is not None and sock.family == uv.AF_UNIX:
+ if host is not None or port is not None:
+ raise ValueError(
+ 'host/port and sock can not be specified at the same time')
+ return await self.create_unix_connection(
+ protocol_factory, None,
+ sock=sock, ssl=ssl, server_hostname=server_hostname)
+
+ app_protocol = protocol = protocol_factory()
+ ssl_waiter = None
+ context = Context_CopyCurrent()
+ if ssl:
+ if server_hostname is None:
+ if not host:
+ raise ValueError('You must set server_hostname '
+ 'when using ssl without a host')
+ server_hostname = host
+
+ ssl_waiter = self._new_future()
+ sslcontext = None if isinstance(ssl, bool) else ssl
+ protocol = SSLProtocol(
+ self, app_protocol, sslcontext, ssl_waiter,
+ False, server_hostname,
+ ssl_handshake_timeout=ssl_handshake_timeout,
+ ssl_shutdown_timeout=ssl_shutdown_timeout)
+ else:
+ if server_hostname is not None:
+ raise ValueError('server_hostname is only meaningful with ssl')
+ 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')
+
+ if host is not None or port is not None:
+ if sock is not None:
+ raise ValueError(
+ 'host/port and sock can not be specified at the same time')
+
+ fs = []
+ f1 = f2 = None
+
+ addr = __static_getaddrinfo(
+ host, port, family, uv.SOCK_STREAM,
+ proto, <system.sockaddr*>&rai_addr_static)
+
+ if addr is None:
+ f1 = self._getaddrinfo(
+ host, port, family,
+ uv.SOCK_STREAM, proto, flags,
+ 0) # 0 == don't unpack
+
+ fs.append(f1)
+ else:
+ rai_static.ai_addr = <system.sockaddr*>&rai_addr_static
+ rai_static.ai_next = NULL
+ rai = &rai_static
+
+ if local_addr is not None:
+ if not isinstance(local_addr, (tuple, list)) or \
+ len(local_addr) != 2:
+ raise ValueError(
+ 'local_addr must be a tuple of host and port')
+
+ addr = __static_getaddrinfo(
+ local_addr[0], local_addr[1],
+ family, uv.SOCK_STREAM,
+ proto, <system.sockaddr*>&lai_addr_static)
+ if addr is None:
+ f2 = self._getaddrinfo(
+ local_addr[0], local_addr[1], family,
+ uv.SOCK_STREAM, proto, flags,
+ 0) # 0 == don't unpack
+
+ fs.append(f2)
+ else:
+ lai_static.ai_addr = <system.sockaddr*>&lai_addr_static
+ lai_static.ai_next = NULL
+ lai = &lai_static
+
+ if len(fs):
+ await aio_wait(fs)
+
+ if rai is NULL:
+ ai_remote = f1.result()
+ if ai_remote.data is NULL:
+ raise OSError('getaddrinfo() returned empty list')
+ rai = ai_remote.data
+
+ if lai is NULL and f2 is not None:
+ ai_local = f2.result()
+ if ai_local.data is NULL:
+ raise OSError(
+ 'getaddrinfo() returned empty list for local_addr')
+ lai = ai_local.data
+
+ exceptions = []
+ rai_iter = rai
+ while rai_iter is not NULL:
+ tr = None
+ try:
+ waiter = self._new_future()
+ tr = TCPTransport.new(self, protocol, None, waiter,
+ context)
+
+ if lai is not NULL:
+ lai_iter = lai
+ while lai_iter is not NULL:
+ try:
+ tr.bind(lai_iter.ai_addr)
+ break
+ except OSError as exc:
+ exceptions.append(exc)
+ lai_iter = lai_iter.ai_next
+ else:
+ tr._close()
+ tr = None
+
+ rai_iter = rai_iter.ai_next
+ continue
+
+ tr.connect(rai_iter.ai_addr)
+ await waiter
+
+ except OSError as exc:
+ if tr is not None:
+ tr._close()
+ tr = None
+ exceptions.append(exc)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ if tr is not None:
+ tr._close()
+ tr = None
+ raise
+ else:
+ break
+
+ rai_iter = rai_iter.ai_next
+
+ else:
+ # If they all have the same str(), raise one.
+ model = str(exceptions[0])
+ if all(str(exc) == model for exc in exceptions):
+ raise exceptions[0]
+ # Raise a combined exception so the user can see all
+ # the various error messages.
+ raise OSError('Multiple exceptions: {}'.format(
+ ', '.join(str(exc) for exc in exceptions)))
+ else:
+ if sock is None:
+ raise ValueError(
+ 'host and port was not specified and no sock specified')
+ if not _is_sock_stream(sock.type):
+ raise ValueError(
+ 'A Stream Socket was expected, got {!r}'.format(sock))
+
+ # libuv will set the socket to non-blocking mode, but
+ # we want Python socket object to notice that.
+ sock.setblocking(False)
+
+ waiter = self._new_future()
+ tr = TCPTransport.new(self, protocol, None, waiter, context)
+ try:
+ # libuv will make socket non-blocking
+ tr._open(sock.fileno())
+ tr._init_protocol()
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ # It's OK to call `_close()` here, as opposed to
+ # `_force_close()` or `close()` as we want to terminate the
+ # transport immediately. The `waiter` can only be waken
+ # up in `Transport._call_connection_made()`, and calling
+ # `_close()` before it is fine.
+ tr._close()
+ raise
+
+ tr._attach_fileobj(sock)
+
+ if ssl:
+ app_transport = protocol._get_app_transport(context)
+ try:
+ await ssl_waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ app_transport.close()
+ raise
+ return app_transport, app_protocol
+ else:
+ return tr, protocol
+
+ @cython.iterable_coroutine
+ async def create_unix_server(self, protocol_factory, path=None,
+ *, backlog=100, sock=None, ssl=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None,
+ start_serving=True):
+ """A coroutine which creates a UNIX Domain Socket server.
+
+ The return value is a Server object, which can be used to stop
+ the service.
+
+ path is a str, representing a file systsem path to bind the
+ server socket to.
+
+ sock can optionally be specified in order to use a preexisting
+ socket object.
+
+ backlog is the maximum number of queued connections passed to
+ listen() (defaults to 100).
+
+ ssl can be set to an SSLContext to enable SSL over the
+ accepted connections.
+
+ ssl_handshake_timeout is the time in seconds that an SSL server
+ will wait for completion of the SSL handshake before aborting the
+ connection. Default is 60s.
+
+ ssl_shutdown_timeout is the time in seconds that an SSL server
+ will wait for completion of the SSL shutdown before aborting the
+ connection. Default is 30s.
+ """
+ cdef:
+ UnixServer pipe
+ Server server = Server(self)
+
+ if ssl is not None:
+ if not isinstance(ssl, ssl_SSLContext):
+ raise TypeError('ssl argument must be an SSLContext or None')
+ 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')
+
+ if path is not None:
+ if sock is not None:
+ raise ValueError(
+ 'path and sock can not be specified at the same time')
+ orig_path = path
+
+ path = os_fspath(path)
+
+ if isinstance(path, str):
+ path = PyUnicode_EncodeFSDefault(path)
+
+ # Check for abstract socket.
+ if path[0] != 0:
+ try:
+ if stat_S_ISSOCK(os_stat(path).st_mode):
+ os_remove(path)
+ except FileNotFoundError:
+ pass
+ except OSError as err:
+ # Directory may have permissions only to create socket.
+ aio_logger.error(
+ 'Unable to check or remove stale UNIX socket %r: %r',
+ orig_path, err)
+
+ # We use Python sockets to create a UNIX server socket because
+ # when UNIX sockets are created by libuv, libuv removes the path
+ # they were bound to. This is different from asyncio, which
+ # doesn't cleanup the socket path.
+ sock = socket_socket(uv.AF_UNIX)
+
+ try:
+ sock.bind(path)
+ except OSError as exc:
+ sock.close()
+ if exc.errno == errno.EADDRINUSE:
+ # Let's improve the error message by adding
+ # with what exact address it occurs.
+ msg = 'Address {!r} is already in use'.format(orig_path)
+ raise OSError(errno.EADDRINUSE, msg) from None
+ else:
+ raise
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ sock.close()
+ raise
+
+ else:
+ if sock is None:
+ raise ValueError(
+ 'path was not specified, and no sock specified')
+
+ if sock.family != uv.AF_UNIX or not _is_sock_stream(sock.type):
+ raise ValueError(
+ 'A UNIX Domain Stream Socket was expected, got {!r}'
+ .format(sock))
+
+ # libuv will set the socket to non-blocking mode, but
+ # we want Python socket object to notice that.
+ sock.setblocking(False)
+
+ pipe = UnixServer.new(
+ self, protocol_factory, server, backlog,
+ ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
+
+ try:
+ pipe._open(sock.fileno())
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ pipe._close()
+ sock.close()
+ raise
+
+ pipe._attach_fileobj(sock)
+ server._add_server(pipe)
+
+ if start_serving:
+ server._start_serving()
+
+ return server
+
+ @cython.iterable_coroutine
+ async def create_unix_connection(self, protocol_factory, path=None, *,
+ ssl=None, sock=None,
+ server_hostname=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None):
+
+ cdef:
+ UnixTransport tr
+ object app_protocol
+ object app_transport
+ object protocol
+ object ssl_waiter
+
+ app_protocol = protocol = protocol_factory()
+ ssl_waiter = None
+ context = Context_CopyCurrent()
+ if ssl:
+ if server_hostname is None:
+ raise ValueError('You must set server_hostname '
+ 'when using ssl without a host')
+
+ ssl_waiter = self._new_future()
+ sslcontext = None if isinstance(ssl, bool) else ssl
+ protocol = SSLProtocol(
+ self, app_protocol, sslcontext, ssl_waiter,
+ False, server_hostname,
+ ssl_handshake_timeout=ssl_handshake_timeout,
+ ssl_shutdown_timeout=ssl_shutdown_timeout)
+ else:
+ if server_hostname is not None:
+ raise ValueError('server_hostname is only meaningful with ssl')
+ 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')
+
+ if path is not None:
+ if sock is not None:
+ raise ValueError(
+ 'path and sock can not be specified at the same time')
+
+ path = os_fspath(path)
+
+ if isinstance(path, str):
+ path = PyUnicode_EncodeFSDefault(path)
+
+ waiter = self._new_future()
+ tr = UnixTransport.new(self, protocol, None, waiter, context)
+ tr.connect(path)
+ try:
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ tr._close()
+ raise
+
+ else:
+ if sock is None:
+ raise ValueError('no path and sock were specified')
+
+ if sock.family != uv.AF_UNIX or not _is_sock_stream(sock.type):
+ raise ValueError(
+ 'A UNIX Domain Stream Socket was expected, got {!r}'
+ .format(sock))
+
+ # libuv will set the socket to non-blocking mode, but
+ # we want Python socket object to notice that.
+ sock.setblocking(False)
+
+ waiter = self._new_future()
+ tr = UnixTransport.new(self, protocol, None, waiter, context)
+ try:
+ tr._open(sock.fileno())
+ tr._init_protocol()
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ tr._close()
+ raise
+
+ tr._attach_fileobj(sock)
+
+ if ssl:
+ app_transport = protocol._get_app_transport(Context_CopyCurrent())
+ try:
+ await ssl_waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ app_transport.close()
+ raise
+ return app_transport, app_protocol
+ else:
+ return tr, protocol
+
+ def default_exception_handler(self, context):
+ """Default exception handler.
+
+ This is called when an exception occurs and no exception
+ handler is set, and can be called by a custom exception
+ handler that wants to defer to the default behavior.
+
+ The context parameter has the same meaning as in
+ `call_exception_handler()`.
+ """
+ message = context.get('message')
+ if not message:
+ message = 'Unhandled exception in event loop'
+
+ exception = context.get('exception')
+ if exception is not None:
+ exc_info = (type(exception), exception, exception.__traceback__)
+ else:
+ exc_info = False
+
+ log_lines = [message]
+ for key in sorted(context):
+ if key in {'message', 'exception'}:
+ continue
+ value = context[key]
+ if key == 'source_traceback':
+ tb = ''.join(tb_format_list(value))
+ value = 'Object created at (most recent call last):\n'
+ value += tb.rstrip()
+ else:
+ try:
+ value = repr(value)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as ex:
+ value = ('Exception in __repr__ {!r}; '
+ 'value type: {!r}'.format(ex, type(value)))
+ log_lines.append('{}: {}'.format(key, value))
+
+ aio_logger.error('\n'.join(log_lines), exc_info=exc_info)
+
+ def get_exception_handler(self):
+ """Return an exception handler, or None if the default one is in use.
+ """
+ return self._exception_handler
+
+ def set_exception_handler(self, handler):
+ """Set handler as the new event loop exception handler.
+
+ If handler is None, the default exception handler will
+ be set.
+
+ If handler is a callable object, it should have a
+ signature matching '(loop, context)', where 'loop'
+ will be a reference to the active event loop, 'context'
+ will be a dict object (see `call_exception_handler()`
+ documentation for details about context).
+ """
+ if handler is not None and not callable(handler):
+ raise TypeError('A callable object or None is expected, '
+ 'got {!r}'.format(handler))
+ self._exception_handler = handler
+
+ def call_exception_handler(self, context):
+ """Call the current event loop's exception handler.
+
+ The context argument is a dict containing the following keys:
+
+ - 'message': Error message;
+ - 'exception' (optional): Exception object;
+ - 'future' (optional): Future instance;
+ - 'handle' (optional): Handle instance;
+ - 'protocol' (optional): Protocol instance;
+ - 'transport' (optional): Transport instance;
+ - 'socket' (optional): Socket instance.
+
+ New keys maybe introduced in the future.
+
+ Note: do not overload this method in an event loop subclass.
+ For custom exception handling, use the
+ `set_exception_handler()` method.
+ """
+ if UVLOOP_DEBUG:
+ self._debug_exception_handler_cnt += 1
+
+ if self._exception_handler is None:
+ try:
+ self.default_exception_handler(context)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ # Second protection layer for unexpected errors
+ # in the default implementation, as well as for subclassed
+ # event loops with overloaded "default_exception_handler".
+ aio_logger.error('Exception in default exception handler',
+ exc_info=True)
+ else:
+ try:
+ self._exception_handler(self, context)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as exc:
+ # Exception in the user set custom exception handler.
+ try:
+ # Let's try default handler.
+ self.default_exception_handler({
+ 'message': 'Unhandled error in exception handler',
+ 'exception': exc,
+ 'context': context,
+ })
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ # Guard 'default_exception_handler' in case it is
+ # overloaded.
+ aio_logger.error('Exception in default exception handler '
+ 'while handling an unexpected error '
+ 'in custom exception handler',
+ exc_info=True)
+
+ def add_reader(self, fileobj, callback, *args):
+ """Add a reader callback."""
+ if len(args) == 0:
+ args = None
+ self._add_reader(fileobj, new_Handle(self, callback, args, None))
+
+ def remove_reader(self, fileobj):
+ """Remove a reader callback."""
+ self._remove_reader(fileobj)
+
+ def add_writer(self, fileobj, callback, *args):
+ """Add a writer callback.."""
+ if len(args) == 0:
+ args = None
+ self._add_writer(fileobj, new_Handle(self, callback, args, None))
+
+ def remove_writer(self, fileobj):
+ """Remove a writer callback."""
+ self._remove_writer(fileobj)
+
+ @cython.iterable_coroutine
+ async def sock_recv(self, sock, n):
+ """Receive data from the socket.
+
+ The return value is a bytes object representing the data received.
+ The maximum amount of data to be received at once is specified by
+ nbytes.
+
+ This method is a coroutine.
+ """
+ cdef:
+ Handle handle
+
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+ fut = _SyncSocketReaderFuture(sock, self)
+ handle = new_MethodHandle3(
+ self,
+ "Loop._sock_recv",
+ <method3_t>self._sock_recv,
+ None,
+ self,
+ fut, sock, n)
+
+ self._add_reader(sock, handle)
+ return await fut
+
+ @cython.iterable_coroutine
+ async def sock_recv_into(self, sock, buf):
+ """Receive data from the socket.
+
+ The received data is written into *buf* (a writable buffer).
+ The return value is the number of bytes written.
+
+ This method is a coroutine.
+ """
+ cdef:
+ Handle handle
+
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+ fut = _SyncSocketReaderFuture(sock, self)
+ handle = new_MethodHandle3(
+ self,
+ "Loop._sock_recv_into",
+ <method3_t>self._sock_recv_into,
+ None,
+ self,
+ fut, sock, buf)
+
+ self._add_reader(sock, handle)
+ return await fut
+
+ @cython.iterable_coroutine
+ async def sock_sendall(self, sock, data):
+ """Send data to the socket.
+
+ The socket must be connected to a remote socket. This method continues
+ to send data from data until either all data has been sent or an
+ error occurs. None is returned on success. On error, an exception is
+ raised, and there is no way to determine how much data, if any, was
+ successfully processed by the receiving end of the connection.
+
+ This method is a coroutine.
+ """
+ cdef:
+ Handle handle
+ ssize_t n
+
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+ if not data:
+ return
+
+ socket_inc_io_ref(sock)
+ try:
+ try:
+ n = sock.send(data)
+ except (BlockingIOError, InterruptedError):
+ pass
+ else:
+ if UVLOOP_DEBUG:
+ # This can be a partial success, i.e. only part
+ # of the data was sent
+ self._sock_try_write_total += 1
+
+ if n == len(data):
+ return
+ if not isinstance(data, memoryview):
+ data = memoryview(data)
+ data = data[n:]
+
+ fut = _SyncSocketWriterFuture(sock, self)
+ handle = new_MethodHandle3(
+ self,
+ "Loop._sock_sendall",
+ <method3_t>self._sock_sendall,
+ None,
+ self,
+ fut, sock, data)
+
+ self._add_writer(sock, handle)
+ return await fut
+ finally:
+ socket_dec_io_ref(sock)
+
+ @cython.iterable_coroutine
+ async def sock_accept(self, sock):
+ """Accept a connection.
+
+ The socket must be bound to an address and listening for connections.
+ The return value is a pair (conn, address) where conn is a new socket
+ object usable to send and receive data on the connection, and address
+ is the address bound to the socket on the other end of the connection.
+
+ This method is a coroutine.
+ """
+ cdef:
+ Handle handle
+
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+ fut = _SyncSocketReaderFuture(sock, self)
+ handle = new_MethodHandle2(
+ self,
+ "Loop._sock_accept",
+ <method2_t>self._sock_accept,
+ None,
+ self,
+ fut, sock)
+
+ self._add_reader(sock, handle)
+ return await fut
+
+ @cython.iterable_coroutine
+ async def sock_connect(self, sock, address):
+ """Connect to a remote socket at address.
+
+ This method is a coroutine.
+ """
+ if self._debug and sock.gettimeout() != 0:
+ raise ValueError("the socket must be non-blocking")
+
+ socket_inc_io_ref(sock)
+ try:
+ if sock.family == uv.AF_UNIX:
+ fut = self._sock_connect(sock, address)
+ else:
+ addrs = await self.getaddrinfo(
+ *address[:2], family=sock.family)
+
+ _, _, _, _, address = addrs[0]
+ fut = self._sock_connect(sock, address)
+ if fut is not None:
+ await fut
+ finally:
+ socket_dec_io_ref(sock)
+
+ @cython.iterable_coroutine
+ async def sock_recvfrom(self, sock, bufsize):
+ raise NotImplementedError
+
+ @cython.iterable_coroutine
+ async def sock_recvfrom_into(self, sock, buf, nbytes=0):
+ raise NotImplementedError
+
+ @cython.iterable_coroutine
+ async def sock_sendto(self, sock, data, address):
+ raise NotImplementedError
+
+ @cython.iterable_coroutine
+ async def connect_accepted_socket(self, protocol_factory, sock, *,
+ ssl=None,
+ ssl_handshake_timeout=None,
+ ssl_shutdown_timeout=None):
+ """Handle an accepted connection.
+
+ This is used by servers that accept connections outside of
+ asyncio but that use asyncio to handle connections.
+
+ This method is a coroutine. When completed, the coroutine
+ returns a (transport, protocol) pair.
+ """
+
+ cdef:
+ UVStream transport = None
+
+ if ssl is not None:
+ if not isinstance(ssl, ssl_SSLContext):
+ raise TypeError('ssl argument must be an SSLContext or None')
+ 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')
+
+ if not _is_sock_stream(sock.type):
+ raise ValueError(
+ 'A Stream Socket was expected, got {!r}'.format(sock))
+
+ app_protocol = protocol_factory()
+ waiter = self._new_future()
+ transport_waiter = None
+ context = Context_CopyCurrent()
+
+ if ssl is None:
+ protocol = app_protocol
+ transport_waiter = waiter
+ else:
+ protocol = SSLProtocol(
+ self, app_protocol, ssl, waiter,
+ server_side=True,
+ server_hostname=None,
+ ssl_handshake_timeout=ssl_handshake_timeout,
+ ssl_shutdown_timeout=ssl_shutdown_timeout)
+ transport_waiter = None
+
+ if sock.family == uv.AF_UNIX:
+ transport = <UVStream>UnixTransport.new(
+ self, protocol, None, transport_waiter, context)
+ elif sock.family in (uv.AF_INET, uv.AF_INET6):
+ transport = <UVStream>TCPTransport.new(
+ self, protocol, None, transport_waiter, context)
+
+ if transport is None:
+ raise ValueError(
+ 'invalid socket family, expected AF_UNIX, AF_INET or AF_INET6')
+
+ transport._open(sock.fileno())
+ transport._init_protocol()
+ transport._attach_fileobj(sock)
+
+ if ssl:
+ app_transport = protocol._get_app_transport(context)
+ try:
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ app_transport.close()
+ raise
+ return app_transport, protocol
+ else:
+ try:
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ transport._close()
+ raise
+ return transport, protocol
+
+ def run_in_executor(self, executor, func, *args):
+ if aio_iscoroutine(func) or aio_iscoroutinefunction(func):
+ raise TypeError("coroutines cannot be used with run_in_executor()")
+
+ self._check_closed()
+
+ if executor is None:
+ executor = self._default_executor
+ # Only check when the default executor is being used
+ self._check_default_executor()
+ if executor is None:
+ executor = cc_ThreadPoolExecutor()
+ self._default_executor = executor
+
+ return aio_wrap_future(executor.submit(func, *args), loop=self)
+
+ def set_default_executor(self, executor):
+ self._default_executor = executor
+
+ @cython.iterable_coroutine
+ async def __subprocess_run(self, protocol_factory, args,
+ stdin=subprocess_PIPE,
+ stdout=subprocess_PIPE,
+ stderr=subprocess_PIPE,
+ universal_newlines=False,
+ shell=True,
+ bufsize=0,
+ preexec_fn=None,
+ close_fds=None,
+ cwd=None,
+ env=None,
+ startupinfo=None,
+ creationflags=0,
+ restore_signals=True,
+ start_new_session=False,
+ executable=None,
+ pass_fds=(),
+ # For tests only! Do not use in your code. Ever.
+ __uvloop_sleep_after_fork=False):
+
+ # TODO: Implement close_fds (might not be very important in
+ # Python 3.5, since all FDs aren't inheritable by default.)
+
+ cdef:
+ int debug_flags = 0
+
+ if universal_newlines:
+ raise ValueError("universal_newlines must be False")
+ if bufsize != 0:
+ raise ValueError("bufsize must be 0")
+ if startupinfo is not None:
+ raise ValueError('startupinfo is not supported')
+ if creationflags != 0:
+ raise ValueError('creationflags is not supported')
+
+ if executable is not None:
+ args[0] = executable
+
+ if __uvloop_sleep_after_fork:
+ debug_flags |= __PROCESS_DEBUG_SLEEP_AFTER_FORK
+
+ waiter = self._new_future()
+ protocol = protocol_factory()
+ proc = UVProcessTransport.new(self, protocol,
+ args, env, cwd, start_new_session,
+ stdin, stdout, stderr, pass_fds,
+ waiter,
+ debug_flags,
+ preexec_fn,
+ restore_signals)
+
+ try:
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ proc.close()
+ raise
+
+ return proc, protocol
+
+ @cython.iterable_coroutine
+ async def subprocess_shell(self, protocol_factory, cmd, *,
+ shell=True,
+ **kwargs):
+
+ if not shell:
+ raise ValueError("shell must be True")
+
+ args = [cmd]
+ if shell:
+ args = [b'/bin/sh', b'-c'] + args
+
+ return await self.__subprocess_run(protocol_factory, args, shell=True,
+ **kwargs)
+
+ @cython.iterable_coroutine
+ async def subprocess_exec(self, protocol_factory, program, *args,
+ shell=False, **kwargs):
+
+ if shell:
+ raise ValueError("shell must be False")
+
+ args = list((program,) + args)
+
+ return await self.__subprocess_run(protocol_factory, args, shell=False,
+ **kwargs)
+
+ @cython.iterable_coroutine
+ async def connect_read_pipe(self, proto_factory, pipe):
+ """Register read pipe in event loop. Set the pipe to non-blocking mode.
+
+ protocol_factory should instantiate object with Protocol interface.
+ pipe is a file-like object.
+ Return pair (transport, protocol), where transport supports the
+ ReadTransport interface."""
+ cdef:
+ ReadUnixTransport transp
+
+ waiter = self._new_future()
+ proto = proto_factory()
+ transp = ReadUnixTransport.new(self, proto, None, waiter)
+ transp._add_extra_info('pipe', pipe)
+ try:
+ transp._open(pipe.fileno())
+ transp._init_protocol()
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ transp._close()
+ raise
+ transp._attach_fileobj(pipe)
+ return transp, proto
+
+ @cython.iterable_coroutine
+ async def connect_write_pipe(self, proto_factory, pipe):
+ """Register write pipe in event loop.
+
+ protocol_factory should instantiate object with BaseProtocol interface.
+ Pipe is file-like object already switched to nonblocking.
+ Return pair (transport, protocol), where transport support
+ WriteTransport interface."""
+ cdef:
+ WriteUnixTransport transp
+
+ waiter = self._new_future()
+ proto = proto_factory()
+ transp = WriteUnixTransport.new(self, proto, None, waiter)
+ transp._add_extra_info('pipe', pipe)
+ try:
+ transp._open(pipe.fileno())
+ transp._init_protocol()
+ await waiter
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException:
+ transp._close()
+ raise
+ transp._attach_fileobj(pipe)
+ return transp, proto
+
+ def add_signal_handler(self, sig, callback, *args):
+ """Add a handler for a signal. UNIX only.
+
+ Raise ValueError if the signal number is invalid or uncatchable.
+ Raise RuntimeError if there is a problem setting up the handler.
+ """
+ cdef:
+ Handle h
+
+ if not self._is_main_thread():
+ raise ValueError(
+ 'add_signal_handler() can only be called from '
+ 'the main thread')
+
+ if (aio_iscoroutine(callback)
+ or aio_iscoroutinefunction(callback)):
+ raise TypeError(
+ "coroutines cannot be used with add_signal_handler()")
+
+ if sig == uv.SIGCHLD:
+ if (hasattr(callback, '__self__') and
+ isinstance(callback.__self__, aio_AbstractChildWatcher)):
+
+ warnings_warn(
+ "!!! asyncio is trying to install its ChildWatcher for "
+ "SIGCHLD signal !!!\n\nThis is probably because a uvloop "
+ "instance is used with asyncio.set_event_loop(). "
+ "The correct way to use uvloop is to install its policy: "
+ "`asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())`"
+ "\n\n", RuntimeWarning, source=self)
+
+ # TODO: ideally we should always raise an error here,
+ # but that would be a backwards incompatible change,
+ # because we recommended using "asyncio.set_event_loop()"
+ # in our README. Need to start a deprecation period
+ # at some point to turn this warning into an error.
+ return
+
+ raise RuntimeError(
+ 'cannot add a signal handler for SIGCHLD: it is used '
+ 'by the event loop to track subprocesses')
+
+ self._check_signal(sig)
+ self._check_closed()
+
+ h = new_Handle(self, callback, args or None, None)
+ self._signal_handlers[sig] = h
+
+ try:
+ # Register a dummy signal handler to ask Python to write the signal
+ # number in the wakeup file descriptor.
+ signal_signal(sig, self.__sighandler)
+
+ # Set SA_RESTART to limit EINTR occurrences.
+ signal_siginterrupt(sig, False)
+ except OSError as exc:
+ del self._signal_handlers[sig]
+ if not self._signal_handlers:
+ try:
+ signal_set_wakeup_fd(-1)
+ except (ValueError, OSError) as nexc:
+ aio_logger.info('set_wakeup_fd(-1) failed: %s', nexc)
+
+ if exc.errno == errno_EINVAL:
+ raise RuntimeError('sig {} cannot be caught'.format(sig))
+ else:
+ raise
+
+ def remove_signal_handler(self, sig):
+ """Remove a handler for a signal. UNIX only.
+
+ Return True if a signal handler was removed, False if not.
+ """
+
+ if not self._is_main_thread():
+ raise ValueError(
+ 'remove_signal_handler() can only be called from '
+ 'the main thread')
+
+ self._check_signal(sig)
+
+ if not self._listening_signals:
+ return False
+
+ try:
+ del self._signal_handlers[sig]
+ except KeyError:
+ return False
+
+ if sig == uv.SIGINT:
+ handler = signal_default_int_handler
+ else:
+ handler = signal_SIG_DFL
+
+ try:
+ signal_signal(sig, handler)
+ except OSError as exc:
+ if exc.errno == errno_EINVAL:
+ raise RuntimeError('sig {} cannot be caught'.format(sig))
+ else:
+ raise
+
+ return True
+
+ @cython.iterable_coroutine
+ async def create_datagram_endpoint(self, protocol_factory,
+ local_addr=None, remote_addr=None, *,
+ family=0, proto=0, flags=0,
+ reuse_address=_unset, reuse_port=None,
+ allow_broadcast=None, sock=None):
+ """A coroutine which creates a datagram endpoint.
+
+ This method will try to establish the endpoint in the background.
+ When successful, the coroutine returns a (transport, protocol) pair.
+
+ protocol_factory must be a callable returning a protocol instance.
+
+ socket family AF_INET or socket.AF_INET6 depending on host (or
+ family if specified), socket type SOCK_DGRAM.
+
+ reuse_port tells the kernel to allow this endpoint to be bound to
+ the same port as other existing endpoints are bound to, so long as
+ they all set this flag when being created. This option is not
+ supported on Windows and some UNIX's. If the
+ :py:data:`~socket.SO_REUSEPORT` constant is not defined then this
+ capability is unsupported.
+
+ allow_broadcast tells the kernel to allow this endpoint to send
+ messages to the broadcast address.
+
+ sock can optionally be specified in order to use a preexisting
+ socket object.
+ """
+ cdef:
+ UDPTransport udp = None
+ system.addrinfo * lai
+ system.addrinfo * rai
+
+ if sock is not None:
+ if not _is_sock_dgram(sock.type):
+ raise ValueError(
+ 'A UDP Socket was expected, got {!r}'.format(sock))
+ if (local_addr or remote_addr or
+ family or proto or flags or
+ reuse_port or allow_broadcast):
+ # show the problematic kwargs in exception msg
+ opts = dict(local_addr=local_addr, remote_addr=remote_addr,
+ family=family, proto=proto, flags=flags,
+ reuse_address=reuse_address, reuse_port=reuse_port,
+ allow_broadcast=allow_broadcast)
+ problems = ', '.join(
+ '{}={}'.format(k, v) for k, v in opts.items() if v)
+ raise ValueError(
+ 'socket modifier keyword arguments can not be used '
+ 'when sock is specified. ({})'.format(problems))
+ sock.setblocking(False)
+ udp = UDPTransport.__new__(UDPTransport)
+ udp._init(self, uv.AF_UNSPEC)
+ udp.open(sock.family, sock.fileno())
+ udp._attach_fileobj(sock)
+ else:
+ if reuse_address is not _unset:
+ if reuse_address:
+ raise ValueError("Passing `reuse_address=True` is no "
+ "longer supported, as the usage of "
+ "SO_REUSEPORT in UDP poses a significant "
+ "security concern.")
+ else:
+ warnings_warn("The *reuse_address* parameter has been "
+ "deprecated as of 0.15.", DeprecationWarning,
+ stacklevel=2)
+ reuse_port = bool(reuse_port)
+ if reuse_port and not has_SO_REUSEPORT:
+ raise ValueError(
+ 'reuse_port not supported by socket module')
+
+ lads = None
+ if local_addr is not None:
+ if (not isinstance(local_addr, (tuple, list)) or
+ len(local_addr) != 2):
+ raise TypeError(
+ 'local_addr must be a tuple of (host, port)')
+ lads = await self._getaddrinfo(
+ local_addr[0], local_addr[1],
+ family, uv.SOCK_DGRAM, proto, flags,
+ 0)
+
+ rads = None
+ if remote_addr is not None:
+ if (not isinstance(remote_addr, (tuple, list)) or
+ len(remote_addr) != 2):
+ raise TypeError(
+ 'remote_addr must be a tuple of (host, port)')
+ rads = await self._getaddrinfo(
+ remote_addr[0], remote_addr[1],
+ family, uv.SOCK_DGRAM, proto, flags,
+ 0)
+
+ excs = []
+ if lads is None:
+ if rads is not None:
+ udp = UDPTransport.__new__(UDPTransport)
+ rai = (<AddrInfo>rads).data
+ udp._init(self, rai.ai_family)
+ udp._connect(rai.ai_addr, rai.ai_addrlen)
+ udp._set_address(rai)
+ else:
+ if family not in (uv.AF_INET, uv.AF_INET6):
+ raise ValueError('unexpected address family')
+ udp = UDPTransport.__new__(UDPTransport)
+ udp._init(self, family)
+
+ if reuse_port:
+ self._sock_set_reuseport(udp._fileno())
+
+ else:
+ lai = (<AddrInfo>lads).data
+ while lai is not NULL:
+ try:
+ udp = UDPTransport.__new__(UDPTransport)
+ udp._init(self, lai.ai_family)
+ if reuse_port:
+ self._sock_set_reuseport(udp._fileno())
+ udp._bind(lai.ai_addr)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except BaseException as ex:
+ lai = lai.ai_next
+ excs.append(ex)
+ continue
+ else:
+ break
+ else:
+ ctx = None
+ if len(excs):
+ ctx = excs[0]
+ raise OSError('could not bind to local_addr {}'.format(
+ local_addr)) from ctx
+
+ if rads is not None:
+ rai = (<AddrInfo>rads).data
+ while rai is not NULL:
+ if rai.ai_family != lai.ai_family:
+ rai = rai.ai_next
+ continue
+ if rai.ai_protocol != lai.ai_protocol:
+ rai = rai.ai_next
+ continue
+ udp._connect(rai.ai_addr, rai.ai_addrlen)
+ udp._set_address(rai)
+ break
+ else:
+ raise OSError(
+ 'could not bind to remote_addr {}'.format(
+ remote_addr))
+
+ if allow_broadcast:
+ udp._set_broadcast(1)
+
+ protocol = protocol_factory()
+ waiter = self._new_future()
+ assert udp is not None
+ udp._set_protocol(protocol)
+ udp._set_waiter(waiter)
+ udp._init_protocol()
+
+ await waiter
+ return udp, protocol
+
+ def _monitor_fs(self, path: str, callback) -> asyncio.Handle:
+ cdef:
+ UVFSEvent fs_handle
+ char* c_str_path
+
+ self._check_closed()
+ fs_handle = UVFSEvent.new(self, callback, None)
+ p_bytes = path.encode('UTF-8')
+ c_str_path = p_bytes
+ flags = 0
+ fs_handle.start(c_str_path, flags)
+ return fs_handle
+
+ def _check_default_executor(self):
+ if self._executor_shutdown_called:
+ raise RuntimeError('Executor shutdown has been called')
+
+ def _asyncgen_finalizer_hook(self, agen):
+ self._asyncgens.discard(agen)
+ if not self.is_closed():
+ self.call_soon_threadsafe(self.create_task, agen.aclose())
+
+ def _asyncgen_firstiter_hook(self, agen):
+ if self._asyncgens_shutdown_called:
+ warnings_warn(
+ "asynchronous generator {!r} was scheduled after "
+ "loop.shutdown_asyncgens() call".format(agen),
+ ResourceWarning, source=self)
+
+ self._asyncgens.add(agen)
+
+ @cython.iterable_coroutine
+ async def shutdown_asyncgens(self):
+ """Shutdown all active asynchronous generators."""
+ self._asyncgens_shutdown_called = True
+
+ if not len(self._asyncgens):
+ return
+
+ closing_agens = list(self._asyncgens)
+ self._asyncgens.clear()
+
+ shutdown_coro = aio_gather(
+ *[ag.aclose() for ag in closing_agens],
+ return_exceptions=True)
+
+ results = await shutdown_coro
+ for result, agen in zip(results, closing_agens):
+ if isinstance(result, Exception):
+ self.call_exception_handler({
+ 'message': 'an error occurred during closing of '
+ 'asynchronous generator {!r}'.format(agen),
+ 'exception': result,
+ 'asyncgen': agen
+ })
+
+ @cython.iterable_coroutine
+ async def shutdown_default_executor(self, timeout=None):
+ """Schedule the shutdown of the default executor.
+
+ The timeout parameter specifies the amount of time the executor will
+ be given to finish joining. The default value is None, which means
+ that the executor will be given an unlimited amount of time.
+ """
+ self._executor_shutdown_called = True
+ if self._default_executor is None:
+ return
+ future = self.create_future()
+ thread = threading_Thread(target=self._do_shutdown, args=(future,))
+ thread.start()
+ try:
+ await future
+ finally:
+ thread.join(timeout)
+
+ if thread.is_alive():
+ warnings_warn(
+ "The executor did not finishing joining "
+ f"its threads within {timeout} seconds.",
+ RuntimeWarning,
+ stacklevel=2
+ )
+ self._default_executor.shutdown(wait=False)
+
+ def _do_shutdown(self, future):
+ try:
+ self._default_executor.shutdown(wait=True)
+ self.call_soon_threadsafe(future.set_result, None)
+ except Exception as ex:
+ self.call_soon_threadsafe(future.set_exception, ex)
+
+
+# Expose pointer for integration with other C-extensions
+def libuv_get_loop_t_ptr(loop):
+ return PyCapsule_New(<void *>(<Loop>loop).uvloop, NULL, NULL)
+
+
+def libuv_get_version():
+ return uv.uv_version()
+
+
+def _testhelper_unwrap_capsuled_pointer(obj):
+ return <uint64_t>PyCapsule_GetPointer(obj, NULL)
+
+
+cdef void __loop_alloc_buffer(
+ uv.uv_handle_t* uvhandle,
+ size_t suggested_size,
+ uv.uv_buf_t* buf
+) noexcept with gil:
+ cdef:
+ Loop loop = (<UVHandle>uvhandle.data)._loop
+
+ if loop._recv_buffer_in_use == 1:
+ buf.len = 0
+ exc = RuntimeError('concurrent allocations')
+ loop._handle_exception(exc)
+ return
+
+ loop._recv_buffer_in_use = 1
+ buf.base = loop._recv_buffer
+ buf.len = sizeof(loop._recv_buffer)
+
+
+cdef inline void __loop_free_buffer(Loop loop):
+ loop._recv_buffer_in_use = 0
+
+
+class _SyncSocketReaderFuture(aio_Future):
+
+ def __init__(self, sock, loop):
+ aio_Future.__init__(self, loop=loop)
+ self.__sock = sock
+ self.__loop = loop
+
+ def __remove_reader(self):
+ if self.__sock is not None and self.__sock.fileno() != -1:
+ self.__loop.remove_reader(self.__sock)
+ self.__sock = None
+
+ if PY39:
+ def cancel(self, msg=None):
+ self.__remove_reader()
+ aio_Future.cancel(self, msg=msg)
+
+ else:
+ def cancel(self):
+ self.__remove_reader()
+ aio_Future.cancel(self)
+
+
+class _SyncSocketWriterFuture(aio_Future):
+
+ def __init__(self, sock, loop):
+ aio_Future.__init__(self, loop=loop)
+ self.__sock = sock
+ self.__loop = loop
+
+ def __remove_writer(self):
+ if self.__sock is not None and self.__sock.fileno() != -1:
+ self.__loop.remove_writer(self.__sock)
+ self.__sock = None
+
+ if PY39:
+ def cancel(self, msg=None):
+ self.__remove_writer()
+ aio_Future.cancel(self, msg=msg)
+
+ else:
+ def cancel(self):
+ self.__remove_writer()
+ aio_Future.cancel(self)
+
+
+include "cbhandles.pyx"
+include "pseudosock.pyx"
+include "lru.pyx"
+
+include "handles/handle.pyx"
+include "handles/async_.pyx"
+include "handles/idle.pyx"
+include "handles/check.pyx"
+include "handles/timer.pyx"
+include "handles/poll.pyx"
+include "handles/basetransport.pyx"
+include "handles/stream.pyx"
+include "handles/streamserver.pyx"
+include "handles/tcp.pyx"
+include "handles/pipe.pyx"
+include "handles/process.pyx"
+include "handles/fsevent.pyx"
+
+include "request.pyx"
+include "dns.pyx"
+include "sslproto.pyx"
+
+include "handles/udp.pyx"
+
+include "server.pyx"
+
+
+# Used in UVProcess
+cdef vint __atfork_installed = 0
+cdef vint __forking = 0
+cdef Loop __forking_loop = None
+
+
+cdef void __get_fork_handler() noexcept nogil:
+ with gil:
+ if (__forking and __forking_loop is not None and
+ __forking_loop.active_process_handler is not None):
+ __forking_loop.active_process_handler._after_fork()
+
+cdef __install_atfork():
+ global __atfork_installed
+
+ if __atfork_installed:
+ return
+ __atfork_installed = 1
+
+ cdef int err
+
+ err = system.pthread_atfork(NULL, NULL, &system.handleAtFork)
+ if err:
+ __atfork_installed = 0
+ raise convert_error(-err)
+
+
+# Install PyMem* memory allocators
+cdef vint __mem_installed = 0
+cdef __install_pymem():
+ global __mem_installed
+ if __mem_installed:
+ return
+ __mem_installed = 1
+
+ cdef int err
+ err = uv.uv_replace_allocator(<uv.uv_malloc_func>PyMem_RawMalloc,
+ <uv.uv_realloc_func>PyMem_RawRealloc,
+ <uv.uv_calloc_func>PyMem_RawCalloc,
+ <uv.uv_free_func>PyMem_RawFree)
+ if err < 0:
+ __mem_installed = 0
+ raise convert_error(err)
+
+
+cdef _set_signal_wakeup_fd(fd):
+ if fd >= 0:
+ return signal_set_wakeup_fd(fd, warn_on_full_buffer=False)
+ else:
+ return signal_set_wakeup_fd(fd)
+
+
+# Helpers for tests
+
+@cython.iterable_coroutine
+async def _test_coroutine_1():
+ return 42
diff --git a/venv/lib/python3.11/site-packages/uvloop/lru.pyx b/venv/lib/python3.11/site-packages/uvloop/lru.pyx
new file mode 100644
index 0000000..cc7ea1d
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/lru.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/pseudosock.pyx b/venv/lib/python3.11/site-packages/uvloop/pseudosock.pyx
new file mode 100644
index 0000000..10a1ad6
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/pseudosock.pyx
@@ -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')
diff --git a/venv/lib/python3.11/site-packages/uvloop/py.typed b/venv/lib/python3.11/site-packages/uvloop/py.typed
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/py.typed
diff --git a/venv/lib/python3.11/site-packages/uvloop/request.pxd b/venv/lib/python3.11/site-packages/uvloop/request.pxd
new file mode 100644
index 0000000..bafa51d
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/request.pxd
@@ -0,0 +1,8 @@
+cdef class UVRequest:
+ cdef:
+ uv.uv_req_t *request
+ bint done
+ Loop loop
+
+ cdef on_done(self)
+ cdef cancel(self)
diff --git a/venv/lib/python3.11/site-packages/uvloop/request.pyx b/venv/lib/python3.11/site-packages/uvloop/request.pyx
new file mode 100644
index 0000000..f15103a
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/request.pyx
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/server.pxd b/venv/lib/python3.11/site-packages/uvloop/server.pxd
new file mode 100644
index 0000000..ef10f81
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/server.pxd
@@ -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)
diff --git a/venv/lib/python3.11/site-packages/uvloop/server.pyx b/venv/lib/python3.11/site-packages/uvloop/server.pyx
new file mode 100644
index 0000000..845bcfd
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/server.pyx
@@ -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
diff --git a/venv/lib/python3.11/site-packages/uvloop/sslproto.pxd b/venv/lib/python3.11/site-packages/uvloop/sslproto.pxd
new file mode 100644
index 0000000..3da10f0
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/sslproto.pxd
@@ -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=*)
diff --git a/venv/lib/python3.11/site-packages/uvloop/sslproto.pyx b/venv/lib/python3.11/site-packages/uvloop/sslproto.pyx
new file mode 100644
index 0000000..42bb764
--- /dev/null
+++ b/venv/lib/python3.11/site-packages/uvloop/sslproto.pyx
@@ -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,
+ })