tigrcorn-transports 0.3.16.dev5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tigrcorn_transports/__init__.py +1 -0
- tigrcorn_transports/base.py +9 -0
- tigrcorn_transports/inproc/__init__.py +3 -0
- tigrcorn_transports/inproc/channel.py +19 -0
- tigrcorn_transports/listeners/__init__.py +4 -0
- tigrcorn_transports/listeners/base.py +14 -0
- tigrcorn_transports/listeners/inproc.py +24 -0
- tigrcorn_transports/listeners/pipe.py +72 -0
- tigrcorn_transports/listeners/registry.py +15 -0
- tigrcorn_transports/listeners/tcp.py +90 -0
- tigrcorn_transports/listeners/udp.py +82 -0
- tigrcorn_transports/listeners/unix.py +69 -0
- tigrcorn_transports/pipe/__init__.py +3 -0
- tigrcorn_transports/pipe/connection.py +19 -0
- tigrcorn_transports/py.typed +1 -0
- tigrcorn_transports/quic/__init__.py +108 -0
- tigrcorn_transports/quic/connection.py +2178 -0
- tigrcorn_transports/quic/crypto.py +508 -0
- tigrcorn_transports/quic/datagrams.py +72 -0
- tigrcorn_transports/quic/flow.py +168 -0
- tigrcorn_transports/quic/handshake.py +21 -0
- tigrcorn_transports/quic/packets.py +398 -0
- tigrcorn_transports/quic/recovery.py +435 -0
- tigrcorn_transports/quic/scheduler.py +70 -0
- tigrcorn_transports/quic/streams.py +964 -0
- tigrcorn_transports/quic/tls_adapter.py +59 -0
- tigrcorn_transports/registry.py +10 -0
- tigrcorn_transports/tcp/__init__.py +1 -0
- tigrcorn_transports/tcp/accept.py +7 -0
- tigrcorn_transports/tcp/connection.py +14 -0
- tigrcorn_transports/tcp/reader.py +59 -0
- tigrcorn_transports/tcp/socketopts.py +13 -0
- tigrcorn_transports/tcp/tls.py +5 -0
- tigrcorn_transports/tcp/writer.py +8 -0
- tigrcorn_transports/udp/__init__.py +3 -0
- tigrcorn_transports/udp/endpoint.py +16 -0
- tigrcorn_transports/udp/packet.py +14 -0
- tigrcorn_transports/udp/socketopts.py +10 -0
- tigrcorn_transports/unix/__init__.py +1 -0
- tigrcorn_transports/unix/connection.py +10 -0
- tigrcorn_transports-0.3.16.dev5.dist-info/METADATA +236 -0
- tigrcorn_transports-0.3.16.dev5.dist-info/RECORD +45 -0
- tigrcorn_transports-0.3.16.dev5.dist-info/WHEEL +5 -0
- tigrcorn_transports-0.3.16.dev5.dist-info/licenses/LICENSE +163 -0
- tigrcorn_transports-0.3.16.dev5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Transport implementations."""
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class InProcChannel:
|
|
9
|
+
capacity: int = 0
|
|
10
|
+
_queue: asyncio.Queue[bytes] = field(init=False)
|
|
11
|
+
|
|
12
|
+
def __post_init__(self) -> None:
|
|
13
|
+
self._queue = asyncio.Queue(maxsize=self.capacity)
|
|
14
|
+
|
|
15
|
+
async def send(self, payload: bytes) -> None:
|
|
16
|
+
await self._queue.put(payload)
|
|
17
|
+
|
|
18
|
+
async def recv(self) -> bytes:
|
|
19
|
+
return await self._queue.get()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseListener(ABC):
|
|
8
|
+
@abstractmethod
|
|
9
|
+
async def start(self, client_connected_cb: Callable[..., Awaitable[None]]) -> None:
|
|
10
|
+
raise NotImplementedError
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
async def close(self) -> None:
|
|
14
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
5
|
+
|
|
6
|
+
from .base import BaseListener
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class InProcListener(BaseListener):
|
|
10
|
+
def __init__(self) -> None:
|
|
11
|
+
self._callback: Callable[..., Awaitable[None]] | None = None
|
|
12
|
+
|
|
13
|
+
async def start(self, client_connected_cb: Callable[..., Awaitable[None]]) -> None:
|
|
14
|
+
self._callback = client_connected_cb
|
|
15
|
+
|
|
16
|
+
async def dispatch(self, *args) -> None:
|
|
17
|
+
if self._callback is None:
|
|
18
|
+
raise RuntimeError('in-process listener has not been started')
|
|
19
|
+
result = self._callback(*args)
|
|
20
|
+
if inspect.isawaitable(result):
|
|
21
|
+
await result
|
|
22
|
+
|
|
23
|
+
async def close(self) -> None:
|
|
24
|
+
self._callback = None
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import inspect
|
|
5
|
+
import os
|
|
6
|
+
import stat
|
|
7
|
+
from collections.abc import Awaitable, Callable
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from tigrcorn_core.errors import ServerError
|
|
11
|
+
from tigrcorn_transports.pipe.connection import PipeConnection
|
|
12
|
+
|
|
13
|
+
from .base import BaseListener
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PipeListener(BaseListener):
|
|
17
|
+
def __init__(self, path: str) -> None:
|
|
18
|
+
self.path = path
|
|
19
|
+
self._callback: Callable[..., Awaitable[None] | None] | None = None
|
|
20
|
+
self._reader_fd: int | None = None
|
|
21
|
+
self._writer_fd: int | None = None
|
|
22
|
+
self._connection: PipeConnection | None = None
|
|
23
|
+
self._loop: asyncio.AbstractEventLoop | None = None
|
|
24
|
+
self._tasks: set[asyncio.Task[None]] = set()
|
|
25
|
+
|
|
26
|
+
async def start(self, client_connected_cb):
|
|
27
|
+
if not hasattr(os, 'mkfifo'):
|
|
28
|
+
raise ServerError('named pipes are not available on this platform')
|
|
29
|
+
self._callback = client_connected_cb
|
|
30
|
+
self._loop = asyncio.get_running_loop()
|
|
31
|
+
path = Path(self.path)
|
|
32
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
if path.exists():
|
|
34
|
+
mode = path.stat().st_mode
|
|
35
|
+
if not stat.S_ISFIFO(mode):
|
|
36
|
+
raise ServerError(f'{self.path!r} exists and is not a FIFO')
|
|
37
|
+
else:
|
|
38
|
+
os.mkfifo(path)
|
|
39
|
+
self._reader_fd = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
|
|
40
|
+
self._writer_fd = os.open(path, os.O_WRONLY | os.O_NONBLOCK)
|
|
41
|
+
self._connection = PipeConnection(path=self.path, read_fd=self._reader_fd, write_fd=self._writer_fd)
|
|
42
|
+
self._loop.add_reader(self._reader_fd, self._on_readable)
|
|
43
|
+
|
|
44
|
+
def _on_readable(self) -> None:
|
|
45
|
+
if self._reader_fd is None or self._callback is None or self._connection is None:
|
|
46
|
+
return
|
|
47
|
+
try:
|
|
48
|
+
data = os.read(self._reader_fd, 65536)
|
|
49
|
+
except BlockingIOError:
|
|
50
|
+
return
|
|
51
|
+
if not data:
|
|
52
|
+
return
|
|
53
|
+
result = self._callback(self._connection, data)
|
|
54
|
+
if inspect.isawaitable(result):
|
|
55
|
+
task = asyncio.create_task(result)
|
|
56
|
+
self._tasks.add(task)
|
|
57
|
+
task.add_done_callback(self._tasks.discard)
|
|
58
|
+
|
|
59
|
+
async def close(self) -> None:
|
|
60
|
+
if self._loop is not None and self._reader_fd is not None:
|
|
61
|
+
self._loop.remove_reader(self._reader_fd)
|
|
62
|
+
for task in list(self._tasks):
|
|
63
|
+
task.cancel()
|
|
64
|
+
for fd in (self._reader_fd, self._writer_fd):
|
|
65
|
+
if fd is not None:
|
|
66
|
+
try:
|
|
67
|
+
os.close(fd)
|
|
68
|
+
except OSError:
|
|
69
|
+
pass
|
|
70
|
+
self._reader_fd = None
|
|
71
|
+
self._writer_fd = None
|
|
72
|
+
self._connection = None
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from tigrcorn_transports.listeners.inproc import InProcListener
|
|
4
|
+
from tigrcorn_transports.listeners.pipe import PipeListener
|
|
5
|
+
from tigrcorn_transports.listeners.tcp import TCPListener
|
|
6
|
+
from tigrcorn_transports.listeners.udp import UDPListener
|
|
7
|
+
from tigrcorn_transports.listeners.unix import UnixListener
|
|
8
|
+
|
|
9
|
+
LISTENER_TYPES = {
|
|
10
|
+
"tcp": TCPListener,
|
|
11
|
+
"udp": UDPListener,
|
|
12
|
+
"unix": UnixListener,
|
|
13
|
+
"pipe": PipeListener,
|
|
14
|
+
"inproc": InProcListener,
|
|
15
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import socket
|
|
5
|
+
from collections.abc import Awaitable, Callable
|
|
6
|
+
from contextlib import suppress
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from tigrcorn_security.tls import wrap_server_tls_connection
|
|
10
|
+
from tigrcorn_transports.tcp.socketopts import configure_socket
|
|
11
|
+
|
|
12
|
+
from .base import BaseListener
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TCPListener(BaseListener):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
host: str,
|
|
19
|
+
port: int,
|
|
20
|
+
backlog: int = 2048,
|
|
21
|
+
ssl: Any = None,
|
|
22
|
+
*,
|
|
23
|
+
reuse_port: bool = False,
|
|
24
|
+
reuse_address: bool = True,
|
|
25
|
+
nodelay: bool = True,
|
|
26
|
+
fd: int | None = None,
|
|
27
|
+
sock: socket.socket | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.host = host
|
|
30
|
+
self.port = port
|
|
31
|
+
self.backlog = backlog
|
|
32
|
+
self.ssl = ssl
|
|
33
|
+
self.reuse_port = reuse_port
|
|
34
|
+
self.reuse_address = reuse_address
|
|
35
|
+
self.nodelay = nodelay
|
|
36
|
+
self.fd = fd
|
|
37
|
+
self.sock = sock
|
|
38
|
+
self.server: asyncio.AbstractServer | None = None
|
|
39
|
+
|
|
40
|
+
def _get_socket(self) -> socket.socket | None:
|
|
41
|
+
if self.sock is not None:
|
|
42
|
+
return self.sock
|
|
43
|
+
if self.fd is None:
|
|
44
|
+
return None
|
|
45
|
+
sock = socket.socket(fileno=self.fd)
|
|
46
|
+
sock.setblocking(False)
|
|
47
|
+
configure_socket(sock, nodelay=self.nodelay)
|
|
48
|
+
self.sock = sock
|
|
49
|
+
return sock
|
|
50
|
+
|
|
51
|
+
async def start(self, client_connected_cb: Callable[..., Awaitable[None]]) -> None:
|
|
52
|
+
ssl_param = None
|
|
53
|
+
if self.ssl is None:
|
|
54
|
+
callback = client_connected_cb
|
|
55
|
+
elif hasattr(self.ssl, 'certificate_pem') and hasattr(self.ssl, 'private_key_pem'):
|
|
56
|
+
async def callback(raw_reader: asyncio.StreamReader, raw_writer: asyncio.StreamWriter) -> None:
|
|
57
|
+
try:
|
|
58
|
+
connection = await wrap_server_tls_connection(raw_reader, raw_writer, self.ssl)
|
|
59
|
+
except Exception:
|
|
60
|
+
raw_writer.close()
|
|
61
|
+
with suppress(Exception):
|
|
62
|
+
await raw_writer.wait_closed()
|
|
63
|
+
return
|
|
64
|
+
await client_connected_cb(connection, connection)
|
|
65
|
+
else:
|
|
66
|
+
callback = client_connected_cb
|
|
67
|
+
ssl_param = self.ssl
|
|
68
|
+
|
|
69
|
+
existing_sock = self._get_socket()
|
|
70
|
+
if existing_sock is not None:
|
|
71
|
+
self.server = await asyncio.start_server(callback, sock=existing_sock, ssl=ssl_param, backlog=self.backlog)
|
|
72
|
+
else:
|
|
73
|
+
self.server = await asyncio.start_server(
|
|
74
|
+
callback,
|
|
75
|
+
host=self.host,
|
|
76
|
+
port=self.port,
|
|
77
|
+
backlog=self.backlog,
|
|
78
|
+
ssl=ssl_param,
|
|
79
|
+
reuse_port=self.reuse_port,
|
|
80
|
+
reuse_address=self.reuse_address,
|
|
81
|
+
)
|
|
82
|
+
sockets = self.server.sockets or []
|
|
83
|
+
for sock in sockets:
|
|
84
|
+
configure_socket(sock, nodelay=self.nodelay)
|
|
85
|
+
|
|
86
|
+
async def close(self) -> None:
|
|
87
|
+
if self.server is not None:
|
|
88
|
+
self.server.close()
|
|
89
|
+
await self.server.wait_closed()
|
|
90
|
+
self.server = None
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import inspect
|
|
5
|
+
import socket
|
|
6
|
+
from collections.abc import Awaitable, Callable
|
|
7
|
+
|
|
8
|
+
from tigrcorn_transports.udp.endpoint import UDPEndpoint
|
|
9
|
+
from tigrcorn_transports.udp.packet import UDPPacket
|
|
10
|
+
from tigrcorn_transports.udp.socketopts import configure_udp_socket
|
|
11
|
+
|
|
12
|
+
from .base import BaseListener
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _UDPProtocol(asyncio.DatagramProtocol):
|
|
16
|
+
def __init__(self, callback: Callable[..., Awaitable[None] | None]) -> None:
|
|
17
|
+
self.callback = callback
|
|
18
|
+
self.transport: asyncio.DatagramTransport | None = None
|
|
19
|
+
self.endpoint: UDPEndpoint | None = None
|
|
20
|
+
self.tasks: set[asyncio.Task[None]] = set()
|
|
21
|
+
|
|
22
|
+
def connection_made(self, transport: asyncio.BaseTransport) -> None:
|
|
23
|
+
self.transport = transport # runtime transport provided by asyncio
|
|
24
|
+
sockname = transport.get_extra_info('sockname')
|
|
25
|
+
sock = transport.get_extra_info('socket')
|
|
26
|
+
if sock is not None:
|
|
27
|
+
configure_udp_socket(sock)
|
|
28
|
+
self.endpoint = UDPEndpoint(transport=transport, local_addr=sockname)
|
|
29
|
+
|
|
30
|
+
def datagram_received(self, data: bytes, addr) -> None: # type: ignore[override]
|
|
31
|
+
if self.endpoint is None:
|
|
32
|
+
return
|
|
33
|
+
packet = UDPPacket(data=data, addr=addr)
|
|
34
|
+
result = self.callback(packet, self.endpoint)
|
|
35
|
+
if inspect.isawaitable(result):
|
|
36
|
+
task = asyncio.create_task(result)
|
|
37
|
+
self.tasks.add(task)
|
|
38
|
+
task.add_done_callback(self.tasks.discard)
|
|
39
|
+
|
|
40
|
+
def connection_lost(self, exc: Exception | None) -> None:
|
|
41
|
+
for task in list(self.tasks):
|
|
42
|
+
task.cancel()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UDPListener(BaseListener):
|
|
46
|
+
def __init__(self, host: str, port: int, *, reuse_port: bool = False, fd: int | None = None, sock: socket.socket | None = None) -> None:
|
|
47
|
+
self.host = host
|
|
48
|
+
self.port = port
|
|
49
|
+
self.reuse_port = reuse_port
|
|
50
|
+
self.fd = fd
|
|
51
|
+
self.sock = sock
|
|
52
|
+
self.transport: asyncio.DatagramTransport | None = None
|
|
53
|
+
self.protocol: _UDPProtocol | None = None
|
|
54
|
+
|
|
55
|
+
def _get_socket(self) -> socket.socket | None:
|
|
56
|
+
if self.sock is not None:
|
|
57
|
+
return self.sock
|
|
58
|
+
if self.fd is None:
|
|
59
|
+
return None
|
|
60
|
+
sock = socket.socket(fileno=self.fd)
|
|
61
|
+
sock.setblocking(False)
|
|
62
|
+
configure_udp_socket(sock)
|
|
63
|
+
self.sock = sock
|
|
64
|
+
return sock
|
|
65
|
+
|
|
66
|
+
async def start(self, client_connected_cb):
|
|
67
|
+
loop = asyncio.get_running_loop()
|
|
68
|
+
existing_sock = self._get_socket()
|
|
69
|
+
transport, protocol = await loop.create_datagram_endpoint(
|
|
70
|
+
lambda: _UDPProtocol(client_connected_cb),
|
|
71
|
+
local_addr=None if existing_sock is not None else (self.host, self.port),
|
|
72
|
+
reuse_port=self.reuse_port if existing_sock is None else None,
|
|
73
|
+
sock=existing_sock,
|
|
74
|
+
)
|
|
75
|
+
self.transport = transport
|
|
76
|
+
self.protocol = protocol
|
|
77
|
+
|
|
78
|
+
async def close(self) -> None:
|
|
79
|
+
if self.transport is not None:
|
|
80
|
+
self.transport.close()
|
|
81
|
+
self.transport = None
|
|
82
|
+
self.protocol = None
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import socket
|
|
5
|
+
from collections.abc import Awaitable, Callable
|
|
6
|
+
from contextlib import suppress
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from tigrcorn_security.tls import wrap_server_tls_connection
|
|
11
|
+
from tigrcorn_core.utils.net import ensure_parent_dir
|
|
12
|
+
|
|
13
|
+
from .base import BaseListener
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class UnixListener(BaseListener):
|
|
17
|
+
def __init__(self, path: str, backlog: int = 2048, ssl: Any = None, *, fd: int | None = None, sock: socket.socket | None = None) -> None:
|
|
18
|
+
self.path = path
|
|
19
|
+
self.backlog = backlog
|
|
20
|
+
self.ssl = ssl
|
|
21
|
+
self.fd = fd
|
|
22
|
+
self.sock = sock
|
|
23
|
+
self.server: asyncio.AbstractServer | None = None
|
|
24
|
+
|
|
25
|
+
def _get_socket(self) -> socket.socket | None:
|
|
26
|
+
if self.sock is not None:
|
|
27
|
+
return self.sock
|
|
28
|
+
if self.fd is None:
|
|
29
|
+
return None
|
|
30
|
+
sock = socket.socket(fileno=self.fd)
|
|
31
|
+
sock.setblocking(False)
|
|
32
|
+
self.sock = sock
|
|
33
|
+
return sock
|
|
34
|
+
|
|
35
|
+
async def start(self, client_connected_cb: Callable[..., Awaitable[None]]) -> None:
|
|
36
|
+
path = Path(self.path) if self.path else None
|
|
37
|
+
existing_sock = self._get_socket()
|
|
38
|
+
if existing_sock is None and path is not None:
|
|
39
|
+
ensure_parent_dir(str(path))
|
|
40
|
+
if path.exists():
|
|
41
|
+
path.unlink()
|
|
42
|
+
|
|
43
|
+
ssl_param = None
|
|
44
|
+
if self.ssl is None:
|
|
45
|
+
callback = client_connected_cb
|
|
46
|
+
elif hasattr(self.ssl, 'certificate_pem') and hasattr(self.ssl, 'private_key_pem'):
|
|
47
|
+
async def callback(raw_reader: asyncio.StreamReader, raw_writer: asyncio.StreamWriter) -> None:
|
|
48
|
+
try:
|
|
49
|
+
connection = await wrap_server_tls_connection(raw_reader, raw_writer, self.ssl)
|
|
50
|
+
except Exception:
|
|
51
|
+
raw_writer.close()
|
|
52
|
+
with suppress(Exception):
|
|
53
|
+
await raw_writer.wait_closed()
|
|
54
|
+
return
|
|
55
|
+
await client_connected_cb(connection, connection)
|
|
56
|
+
else:
|
|
57
|
+
callback = client_connected_cb
|
|
58
|
+
ssl_param = self.ssl
|
|
59
|
+
|
|
60
|
+
if existing_sock is not None:
|
|
61
|
+
self.server = await asyncio.start_unix_server(callback, sock=existing_sock, ssl=ssl_param, backlog=self.backlog)
|
|
62
|
+
else:
|
|
63
|
+
self.server = await asyncio.start_unix_server(callback, path=self.path, backlog=self.backlog, ssl=ssl_param)
|
|
64
|
+
|
|
65
|
+
async def close(self) -> None:
|
|
66
|
+
if self.server is not None:
|
|
67
|
+
self.server.close()
|
|
68
|
+
await self.server.wait_closed()
|
|
69
|
+
self.server = None
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class PipeConnection:
|
|
9
|
+
path: str
|
|
10
|
+
read_fd: int
|
|
11
|
+
write_fd: int | None = None
|
|
12
|
+
|
|
13
|
+
def read(self, n: int = 65536) -> bytes:
|
|
14
|
+
return os.read(self.read_fd, n)
|
|
15
|
+
|
|
16
|
+
def write(self, data: bytes) -> int:
|
|
17
|
+
if self.write_fd is None:
|
|
18
|
+
raise OSError('pipe is not writable')
|
|
19
|
+
return os.write(self.write_fd, data)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from .crypto import (
|
|
2
|
+
QUIC_V1_INITIAL_SALT,
|
|
3
|
+
QuicPacketProtectionKeys,
|
|
4
|
+
aes_gcm_decrypt,
|
|
5
|
+
aes_gcm_encrypt,
|
|
6
|
+
apply_header_protection,
|
|
7
|
+
derive_initial_packet_protection_keys,
|
|
8
|
+
derive_initial_secret,
|
|
9
|
+
derive_quic_packet_protection_keys,
|
|
10
|
+
derive_secret,
|
|
11
|
+
generate_connection_id,
|
|
12
|
+
hkdf_expand_label,
|
|
13
|
+
hkdf_extract,
|
|
14
|
+
make_integrity_tag,
|
|
15
|
+
packet_nonce,
|
|
16
|
+
protect_payload,
|
|
17
|
+
remove_header_protection,
|
|
18
|
+
unprotect_payload,
|
|
19
|
+
unprotect_quic_packet,
|
|
20
|
+
protect_quic_packet,
|
|
21
|
+
)
|
|
22
|
+
from .datagrams import QuicDatagram, QuicHeader, QuicPacketType, decode_datagram, encode_datagram
|
|
23
|
+
from .packets import (
|
|
24
|
+
QuicLongHeaderPacket,
|
|
25
|
+
QuicLongHeaderType,
|
|
26
|
+
QuicRetryPacket,
|
|
27
|
+
QuicShortHeaderPacket,
|
|
28
|
+
QuicStatelessResetPacket,
|
|
29
|
+
QuicVersionNegotiationPacket,
|
|
30
|
+
decode_packet,
|
|
31
|
+
decode_long_header_packet,
|
|
32
|
+
decode_short_header_packet,
|
|
33
|
+
parse_stateless_reset,
|
|
34
|
+
)
|
|
35
|
+
from .streams import QuicStreamFrame, QuicAckFrame, QuicConnectionCloseFrame, QuicMaxDataFrame, QuicMaxStreamDataFrame
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
'QuicConnection',
|
|
39
|
+
'QuicEvent',
|
|
40
|
+
'QuicDatagram',
|
|
41
|
+
'QuicHeader',
|
|
42
|
+
'QuicPacketType',
|
|
43
|
+
'QuicStreamFrame',
|
|
44
|
+
'QuicAckFrame',
|
|
45
|
+
'QuicConnectionCloseFrame',
|
|
46
|
+
'QuicMaxDataFrame',
|
|
47
|
+
'QuicMaxStreamDataFrame',
|
|
48
|
+
'decode_datagram',
|
|
49
|
+
'encode_datagram',
|
|
50
|
+
'QuicLongHeaderPacket',
|
|
51
|
+
'QuicLongHeaderType',
|
|
52
|
+
'QuicRetryPacket',
|
|
53
|
+
'QuicShortHeaderPacket',
|
|
54
|
+
'QuicStatelessResetPacket',
|
|
55
|
+
'QuicVersionNegotiationPacket',
|
|
56
|
+
'decode_packet',
|
|
57
|
+
'decode_long_header_packet',
|
|
58
|
+
'decode_short_header_packet',
|
|
59
|
+
'parse_stateless_reset',
|
|
60
|
+
'QUIC_V1_INITIAL_SALT',
|
|
61
|
+
'QuicPacketProtectionKeys',
|
|
62
|
+
'aes_gcm_encrypt',
|
|
63
|
+
'aes_gcm_decrypt',
|
|
64
|
+
'apply_header_protection',
|
|
65
|
+
'remove_header_protection',
|
|
66
|
+
'protect_quic_packet',
|
|
67
|
+
'unprotect_quic_packet',
|
|
68
|
+
'derive_initial_secret',
|
|
69
|
+
'derive_initial_packet_protection_keys',
|
|
70
|
+
'derive_quic_packet_protection_keys',
|
|
71
|
+
'hkdf_extract',
|
|
72
|
+
'hkdf_expand_label',
|
|
73
|
+
'packet_nonce',
|
|
74
|
+
'derive_secret',
|
|
75
|
+
'generate_connection_id',
|
|
76
|
+
'make_integrity_tag',
|
|
77
|
+
'protect_payload',
|
|
78
|
+
'unprotect_payload',
|
|
79
|
+
'QuicTlsHandshakeDriver',
|
|
80
|
+
'TransportParameters',
|
|
81
|
+
'generate_self_signed_certificate',
|
|
82
|
+
'QuicLossRecovery',
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def __getattr__(name: str):
|
|
87
|
+
if name in {"QuicConnection", "QuicEvent"}:
|
|
88
|
+
from .connection import QuicConnection, QuicEvent
|
|
89
|
+
|
|
90
|
+
mapping = {
|
|
91
|
+
"QuicConnection": QuicConnection,
|
|
92
|
+
"QuicEvent": QuicEvent,
|
|
93
|
+
}
|
|
94
|
+
return mapping[name]
|
|
95
|
+
if name in {"QuicTlsHandshakeDriver", "TransportParameters", "generate_self_signed_certificate"}:
|
|
96
|
+
from .handshake import QuicTlsHandshakeDriver, TransportParameters, generate_self_signed_certificate
|
|
97
|
+
|
|
98
|
+
mapping = {
|
|
99
|
+
"QuicTlsHandshakeDriver": QuicTlsHandshakeDriver,
|
|
100
|
+
"TransportParameters": TransportParameters,
|
|
101
|
+
"generate_self_signed_certificate": generate_self_signed_certificate,
|
|
102
|
+
}
|
|
103
|
+
return mapping[name]
|
|
104
|
+
if name == "QuicLossRecovery":
|
|
105
|
+
from .recovery import QuicLossRecovery
|
|
106
|
+
|
|
107
|
+
return QuicLossRecovery
|
|
108
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|