A pure-Swift implementation of the QUIC transport protocol, built on SwiftNIO.
Status: early development. The public API is not yet stable and there is no tagged release. See
docs/PLAN.mdfor the roadmap and issue #1 for live per-task status.
A QUIC endpoint, client and server, over SwiftNIO’s UDP datagram channels.
| Spec | Title | Implemented |
|---|---|---|
| RFC 8999 | Version-Independent Properties of QUIC | Header invariants, connection IDs, version negotiation |
| RFC 9000 | QUIC: A UDP-Based Multiplexed and Secure Transport | Connections, streams, flow control, address validation, connection migration (§ 9) including server preferred_address, and the § 20 error codes |
| RFC 9001 | Using TLS to Secure QUIC | The TLS 1.3 handshake, packet and header protection, 0-RTT resumption, key update |
| RFC 9002 | QUIC Loss Detection and Congestion Control | RTT estimation, packet- and time-threshold loss detection, PTO, NewReno, ECN response, pacing |
| RFC 9221 | An Unreliable Datagram Extension to QUIC | DATAGRAM frames, with send backpressure and a bounded receive backlog |
| RFC 9368 | Compatible Version Negotiation for QUIC | A version-1 first flight upgraded to version 2 inside one handshake |
| RFC 9369 | QUIC Version 2 | Version 2, preferred by default |
| RFC 8899 | Packetization Layer Path MTU Discovery | DPLPMTUD, which RFC 9000 § 14.3 binds into QUIC to grow datagrams past the 1200-byte floor |
draft-ietf-quic-qlog-main-schema-13 |
qlog: Structured Logging for Network Protocols | Event logs written to QLOGDIR, carrying the QUIC event set that draft-ietf-quic-qlog-quic-events-13 defines. Still an Internet-Draft, so the code pins the draft version it cites |
docs/specs/TRACEABILITY.md maps each normative
section to its implementation and tests.
Beyond the specs:
- Swift 6 language mode with strict concurrency, and an
async/awaitpublic API. Streams are bespoke async send, receive, and bidirectional types with inbound backpressure wired to flow control. - Sans-I/O core. The state machines take bytes and events in and give bytes
and events out. The
ChannelHandlers are a thin shell, so protocol logic stays deterministically testable. - Cross-platform, everywhere SwiftNIO runs. Dependencies are SwiftNIO, a fork of swift-nio-ssl, swift-crypto, swift-collections, and swift-log.
- Linux datapath offloads: batched reads (
recvmmsg), GRO receive, GSO send, ECN marking, and tunable socket buffers. - Tested against the RFCs and other implementations. Roughly 1,100 deterministic unit and integration tests, in-process lossy-link simulators with seeded packet fates, and interop CI against quic-go and ngtcp2 through the QUIC Interop Runner.
QUIC transport only. HTTP/3 and QPACK will live in a separate swift-nio-http3
package that depends on this one.
The roadmap tracker (issue #1) carries per-task status. The larger open items:
- Abuse hardening is a set of point defenses, not full coverage of
RFC 9000 § 21. The § 21.5.6, § 21.6, and § 21.9 defenses are in place;
the rest is tracked per section in
TRACEABILITY.md. - Retry tokens and stateless-reset tokens use per-process keys. They do not survive a restart and cannot span a cluster, because neither is derived from a configurable server secret (RFC 9000 § 8.1, § 10.3) (#127).
- The interop
rebind-portandrebind-addrcases fail on more than one pairing, so peer migration after a NAT rebind (RFC 9000 § 9.3) does not yet pass against every implementation (#364). - The public API has had no review pass. It carries no DocC yet, and whether
to offer a
Channel-conforming surface alongside the async types is still an open design question (#337). - A server scales to one socket per address. Single-socket dual-stack
listening (#201) and
SO_REUSEPORTsharding across event loops (#211) are both pending. - Two interop cases are not enabled yet:
chacha20, which needs the TLS 1.3 cipher pinned (#175), andconnectionmigration, which waits on quic-interop-runner#500 (#274).
QUIC drives the TLS 1.3 handshake directly rather than running it over records.
swift-nio-quic uses a fork of swift-nio-ssl at
alta/swift-nio-ssl that exposes
BoringSSL’s QUIC-TLS interface, and swift-crypto for packet protection. See
AGENTS.md and docs/ARCHITECTURE.md for
details.
swift build
swift testSome tests cost about a minute each and hold several event loop threads and a
multi-megabyte transfer, so they are excluded from the default run. Set
QUIC_RUN_SLOW_TESTS to a truthy value (1, true, yes, y, or on) to
include them:
QUIC_RUN_SLOW_TESTS=1 swift testThis follows SWIFTNIO_RUN_SLOW_TESTS in apple/swift-nio. It currently gates
the real-socket NAT rebind cases in RebindLoopbackTests, which drive the
rebind-port and rebind-addr interop scenarios through a loopback relay.
One cheap case from that suite runs by default.
The in-process simulator has its own large-seed sweeps behind
QUIC_SIMULATOR_SWEEP, which predates this convention.
The fork is expected to be checked out as a sibling directory at
../swift-nio-ssl. To build against your local checkout instead of the pinned
remote commit:
swift package edit swift-nio-ssl --path ../swift-nio-ssl
# … hack on both repos …
swift package unedit swift-nio-sslApache License 2.0. See LICENSE.txt and NOTICE.txt.