diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/uvloop')
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.pycBinary files differ new file mode 100644 index 0000000..ebc913e --- /dev/null +++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc 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.pycBinary files differ new file mode 100644 index 0000000..155eaae --- /dev/null +++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc 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.pycBinary files differ new file mode 100644 index 0000000..ca115de --- /dev/null +++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc 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.pycBinary files differ new file mode 100644 index 0000000..e31e416 --- /dev/null +++ b/venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc 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.pycBinary files differ new file mode 100644 index 0000000..a4464aa --- /dev/null +++ b/venv/lib/python3.11/site-packages/uvloop/includes/__pycache__/__init__.cpython-311.pyc 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.soBinary files differ 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 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, +            }) | 
