Skip to main content

High-performance QUIC/HTTP3 library — picoquic-backed, qh3-compatible asyncio API

Project description

aiopquic - Async QUIC + WebTransport (picoquic)

aiopquic is a Python/Cython binding to picoquic, providing high-performance QUIC transport and WebTransport for asyncio applications.

Overview

aiopquic exposes picoquic's QUIC implementation through a lock-free SPSC ring buffer architecture that bridges the picoquic network thread with Python's asyncio event loop. It provides an asyncio QUIC/HTTP3 transport API in the spirit of aioquic (and its fork qh3) — similar shapes for QuicConfiguration, QuicConnection, connect() / serve(), and event types — plus a native WebTransport client/server layered on picoquic's H3 + h3zero. Note: not a drop-in replacement — semantics differ around backpressure (send_stream_data raises BufferError on full per-stream ring) and flow-control sizing.

Architecture

  • SPSC Ring Buffers -- Lock-free single producer/single consumer rings for zero-copy event passing between threads. RX uses per-event malloc with ownership transfer at pop (1-copy delivery to Python via StreamChunk).
  • Cross-platform wake fd -- Linux eventfd for efficient asyncio add_reader() notification; pipe() self-pipe fallback on macOS / BSD.
  • Dedicated Network Thread -- picoquic runs in its own thread via picoquic_start_network_thread().
  • Cython Bridge -- Thin Cython layer over C callbacks, minimal overhead.
  • WebTransport -- asyncio.webtransport.WebTransportSession (client + server) over picoquic's picowt_* API and h3zero.

Features

  • QUIC client and server support (qh3-compatible asyncio API: connect(), serve(), QuicConnectionProtocol)
  • Stream data send/receive with FIN signaling, stream reset, stop_sending
  • Datagram support
  • WebTransport client + server (serve_webtransport, WebTransportSession)
  • Connection migration / 0-RTT (inherited from picoquic)
  • Connection management (create, close, idle timeout, application close codes)
  • Per-cnx multiplexing on the server side via QuicEngine
  • Native picoquic_ct / picohttp_ct subprocess smoke (catches upstream regressions on every submodule bump)

Test Results

Tests pass on Linux and macOS (excluding the network-dependent interop suite):

Suite Tests Coverage
test_spsc_ring per-event malloc ring lifecycle
test_buffer Cython Buffer (qh3-compatible)
test_transport Transport lifecycle, wake fd, wake-up, connection management
test_loopback 17 tests — handshake, streams, FIN, reset, datagrams, ALPN mismatch, idle timeout, app-close codes, stop_sending, many-streams stress, TX-ring overflow
test_asyncio qh3-compat client/server stream and datagram exchange
test_baton_pattern Pure-QUIC baton-style stream multiplexing (UNI ↔ BIDI)
test_native_picoquic picoquic_ct / picohttp_ct subprocess driver
test_interop Real public endpoints (network required, opt-in)
tests/bench/ 17 microbenches: ring push/pop, single-shot/sustained/parallel/bidirectional throughput, datagrams, RTT latency, handshake rate (opt-in via pytest tests/bench)

Installation

Requires Python 3.14+ and a C build toolchain. picoquic + picotls are built from source as git submodules.

git clone https://github.com/gmarzot/aiopquic.git
cd aiopquic
git submodule update --init --recursive
./bootstrap_python.sh
source .venv/bin/activate
./build_picoquic.sh        # builds picotls, picoquic, native test drivers
pip install -e '.[dev]'

On macOS, set OPENSSL_ROOT_DIR if Homebrew OpenSSL is not auto-detected (the build script tries openssl@3 then openssl@1.1).

Usage

Low-level Transport API

from aiopquic._binding._transport import TransportContext

server = TransportContext()
server.start(port=4433, cert_file="cert.pem", key_file="key.pem",
             alpn="moq-00", is_client=False)

client = TransportContext()
client.start(port=0, alpn="moq-00", is_client=True)
client.create_client_connection("127.0.0.1", 4433,
                                 sni="localhost", alpn="moq-00")

qh3-compatible asyncio API

from aiopquic.asyncio.client import connect
from aiopquic.quic.configuration import QuicConfiguration

configuration = QuicConfiguration(
    alpn_protocols=["h3"],
    is_client=True,
)

async with connect("quic.nginx.org", 443,
                   configuration=configuration) as protocol:
    quic = protocol._quic
    stream_id = quic.get_next_available_stream_id()
    quic.send_stream_data(stream_id, b"GET / HTTP/1.0\r\n\r\n", end_stream=True)
    protocol.transmit()

WebTransport

from aiopquic.asyncio.webtransport import (
    serve_webtransport, WebTransportSession,
)
# See src/aiopquic/asyncio/webtransport.py and tests/ for full examples.

Development

pip install -e '.[dev]'
python -m pytest tests/ -v -m "not interop and not native"

# Microbenches (opt-in)
python -m pytest tests/bench

Known Limitations

  • Python 3.14+ required -- relax planned (test on 3.12/3.13).
  • Free-threaded Python (3.14t) not yet supported -- the TX-ring producer side, TransportContext lifecycle, and the WebTransport engine state currently rely on the GIL for serialization. FT support deferred until a per-context locking audit lands.
  • STOP_SENDING error codes surface as 0 today: picoquic's public stream-error getter only returns the RESET_STREAM code. STOP_SENDING's code lives in stream->remote_stop_error in picoquic_internal.h (no public getter). A small helper that pulls the field is straightforward future work — see TODO in src/aiopquic/_binding/c/callback.h.
  • Source build only -- requires building picoquic + picotls from submodules; binary wheel distribution planned.

TODO

  • Windows support (eventfd alternative — IOCP / WSAEventSelect on the wake-fd path)
  • Free-threaded Python (3.14t) support after producer-side locking audit
  • STOP_SENDING error-code surfacing helper (read remote_stop_error from picoquic_internal.h)
  • Relax Python version requirement (test on 3.12/3.13)
  • Per-stream wrapper cleanup on RESET/FIN before connection close (currently bounded leak per cnx)

Resources


A Marz Research project.

License

MIT License -- see LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aiopquic-0.2.0.tar.gz (399.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

aiopquic-0.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.9 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

aiopquic-0.2.0-cp314-cp314-macosx_14_0_arm64.whl (3.6 MB view details)

Uploaded CPython 3.14macOS 14.0+ ARM64

aiopquic-0.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.9 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

aiopquic-0.2.0-cp313-cp313-macosx_14_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.13macOS 14.0+ ARM64

aiopquic-0.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.9 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

aiopquic-0.2.0-cp312-cp312-macosx_14_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.12macOS 14.0+ ARM64

File details

Details for the file aiopquic-0.2.0.tar.gz.

File metadata

  • Download URL: aiopquic-0.2.0.tar.gz
  • Upload date:
  • Size: 399.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for aiopquic-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7afa63ce3b85fe34b355e003602381739cc48ff41c1d4e7de79e30a779b08533
MD5 04b9f41501c8e76ad53c1c1e96d92b38
BLAKE2b-256 82ce3c5d9d3b3a58862d394f745bdf9ccb1e315812b6d944501e5f8bcbeae46b

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2dfdb6b36df71f20b3f3928bd0dbaaf5100316d19c5d81a2a0c4e11bebf9ffb2
MD5 39030e2bad48a329def00162f6e1c2fe
BLAKE2b-256 bbaf1e9f2a7625b4cf6b0d735c18eb5cf5f3a81e590b005236be7760158b2ee0

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp314-cp314-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp314-cp314-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 11bc699521e7852aabc919d1ab7cbaf94ebec9a3b5f8aa478e95bcfd6c9c525b
MD5 42ca6fd480f42af80148176739410434
BLAKE2b-256 878ded80233d42283c83c678d336fc3bab4202e70c8941e957b2186a3b166d45

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 fb2b064d0d7f9c8b116d582762c775a875d070c456c83662a395f541a2ffb793
MD5 9d6bb0bcee1d439d8177a88586e71c11
BLAKE2b-256 446768a6ae86af8e609d241f1cbf5c18191fd36358410bb1a5e69e089c12467b

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp313-cp313-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp313-cp313-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 6500a0715c9fe008e6ab941c7cb8fc26139fd5209ddb25970d4f2bee68a7d7a8
MD5 5ed5c0faa91157b4f439445b6322afc2
BLAKE2b-256 e2df3186e38f0751a9f11530c48400b8f7be34e72bbf5c5a8721403b2e497ed6

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 3e2f9f33e7bd6d80836244225c93a95f06d78359d8647b4047f9fbae3b5c93e8
MD5 818f1a0c252db78ab0560fbf2b03e76f
BLAKE2b-256 228e4095fec219caf5908d44d4eddabd5feb3ca7b54a788e4633f6da451e6e20

See more details on using hashes here.

File details

Details for the file aiopquic-0.2.0-cp312-cp312-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for aiopquic-0.2.0-cp312-cp312-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 9577c3da7caa2a739d7492e4cb3dfc9b34d073c71817c001d7755feff245a539
MD5 d86075cb8290ebbd54d7d3efb3dbb7a7
BLAKE2b-256 1b5ee8c9d87f311faded61c562adb2eed48be5f6ea3959a57773852fdf0a966a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page