QUIC library with NAT traversal
Project description
QUIC Portal (experimental)
⚠️ Warning: This library is experimental and not intended for production use.
High-performance QUIC communication library with automatic NAT traversal within Modal applications.
Current features
- Automatic NAT traversal: Built-in STUN discovery and UDP hole punching, using Modal Dict for rendezvous.
- High-performance QUIC: Rust-based implementation for maximum throughput and minimal latency
- Simple synchronous API: Easy-to-use Portal class with static methods for server/client creation. WebSocket-style messaging.
Upcoming roadmap
- TODO: Improved NAT traversal: Handle more complex client-side NATs using port scanning + birthday technique. Currently only supports clients behind "easy" NATs.
- TODO: Shared server certificates: Use a modal.Dict to share server/client certificates, to mutually validate identity.
- TODO: Tunable QUIC settings: Expose currently hardcoded bandwidth optimization as a parameter in Python class.
Installation
# Install from PyPi (only certain wheels built)
pip install quic-portal
# Install from source (requires Rust toolchain)
git clone <repository>
cd quic-portal
pip install .
Quick Start
Usage with Modal
import modal
from quic_portal import Portal
app = modal.App("my-quic-app")
@app.function()
def server_function(coord_dict: modal.Dict):
# Create server with automatic NAT traversal
portal = Portal.create_server(dict=coord_dict, local_port=5555)
# Receive and echo messages
while True:
data = portal.recv(timeout_ms=10000)
if data:
message = data.decode("utf-8")
print(f"Received: {message}")
portal.send(f"Echo: {message}".encode("utf-8"))
@app.function()
def client_function(coord_dict: modal.Dict):
# Create client with automatic NAT traversal
portal = Portal.create_client(dict=coord_dict, local_port=5556)
# Send messages
portal.send(b"Hello, QUIC!")
response = portal.recv(timeout_ms=5000)
if response:
print(f"Got response: {response.decode('utf-8')}")
@app.local_entrypoint()
def main(local: bool = False):
# Create coordination dict
with modal.Dict.ephemeral() as coord_dict:
# Start server
server_task = server_function.spawn(coord_dict)
# Run client
if local:
# Run test between local environment and remote container.
client_function.local(coord_dict)
else:
# Run test between two containers.
client_function.remote(coord_dict)
server_task.cancel()
Manual NAT Traversal
For advanced use cases where you handle NAT traversal yourself, or the server has a public IP:
from quic_portal import Portal
# After NAT hole punching is complete...
# Server side
server = Portal()
server.listen(5555)
# Client side
client = Portal()
client.connect("server_ip", 5555, 5556)
# WebSocket-style messaging
client.send(b"Hello!")
response = server.recv(timeout_ms=1000)
API Reference
Portal Class
Static Methods
Portal.create_server(dict, local_port=5555, stun_server=("stun.ekiga.net", 3478), punch_timeout=15)
Create a server portal with automatic NAT traversal. Synchronous operation.
Parameters:
dict(modal.Dict or dict): Modal Dict or regular dict for peer coordinationlocal_port(int): Local port for QUIC server (default: 5555)stun_server(tuple): STUN server for NAT discovery (default: ("stun.ekiga.net", 3478))punch_timeout(int): Timeout in seconds for NAT punching (default: 15)
Returns: Connected Portal instance ready for communication
Portal.create_client(dict, local_port=5556, stun_server=("stun.ekiga.net", 3478), punch_timeout=15)
Create a client portal with automatic NAT traversal. Synchronous operation.
Parameters:
dict(modal.Dict or dict): Modal Dict or regular dict for peer coordination (must be same as server)local_port(int): Local port for QUIC client (default: 5556)stun_server(tuple): STUN server for NAT discovery (default: ("stun.ekiga.net", 3478))punch_timeout(int): Timeout in seconds for NAT punching (default: 15)
Returns: Connected Portal instance ready for communication
Instance Methods
send(data: Union[bytes, str]) -> None
Send data over QUIC connection (WebSocket-style). Synchronous operation.
recv(timeout_ms: Optional[int] = None) -> Optional[bytes]
Receive data from QUIC connection. Blocks until message arrives or timeout. Synchronous operation.
Parameters:
timeout_ms(int, optional): Timeout in milliseconds (None for blocking)
Returns: Received data as bytes, or None if timeout
connect(server_ip: str, server_port: int, local_port: int) -> None
Connect to a QUIC server (for manual NAT traversal). Synchronous operation.
Parameters:
server_ip(str): Server IP addressserver_port(int): Server portlocal_port(int): Local port to bind to
listen(local_port: int) -> None
Start QUIC server and wait for connection (for manual NAT traversal). Synchronous operation.
Parameters:
local_port(int): Local port to bind to
is_connected() -> bool
Check if connected to peer.
close() -> None
Close the connection and clean up resources.
Examples
See the examples/ directory for complete working examples:
modal_simple.py- Basic server/client communicationmodal_benchmark.py- Performance benchmarking
Requirements
- Python 3.8+
- Modal (for automatic NAT traversal)
- Rust toolchain (for building from source)
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quic_portal-0.1.2.tar.gz.
File metadata
- Download URL: quic_portal-0.1.2.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.8.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e66968d7844b2eefae6433223ccec6bfbd64df28359cb80e967056f40df0537f
|
|
| MD5 |
8dd76a8c282e7edd18f758c803252cc5
|
|
| BLAKE2b-256 |
f7b0883c99337ce745324579d64cdbb0896791dd705e469870e5669555f86a6b
|
File details
Details for the file quic_portal-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: quic_portal-0.1.2-cp38-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.8+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.7.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8d379f08ca524ad6216bd5a5273d46080ee47566699f0e9575e77c6da3e3dbd
|
|
| MD5 |
59dfefb802991e38a73fb51dfa8bd71a
|
|
| BLAKE2b-256 |
c85f397ac550a5fef962be58e57d7832b4b60be5c6893e299cf83dce862efdc0
|
File details
Details for the file quic_portal-0.1.2-cp38-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: quic_portal-0.1.2-cp38-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.2 MB
- Tags: CPython 3.8+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.8.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa2b6409c96d783d39760850bd621240e9da48690e5d909e59e3a642da1724ec
|
|
| MD5 |
73eb1389f7a221f63543288f4fc956ee
|
|
| BLAKE2b-256 |
a08f108ab4a9ed9912aea12b3ce30ce2f695fc41792025993735503e72d5ad01
|