Part XIII — Modern Transports

§ 14. QUIC Deep Dive

QUIC's wire image, TLS 1.3 handshake, independent streams, loss recovery, migration, HTTP/3, and the trade-offs behind 0-RTT.

1. § 14.1 — Why QUIC Replaces TCP + TLS

TCP gives the application one reliable ordered byte stream. HTTP/2 can multiplex logical streams inside that byte stream, but the TCP receiver still cannot deliver bytes after a missing segment. QUIC moves reliability above UDP, so each stream has its own ordering and loss only blocks the affected stream.

QUIC also folds the TLS 1.3 handshake into transport setup. A fresh connection can send application data after one round trip, while a resumed connection can send replay-sensitive early data immediately with 0-RTT. UDP encapsulation also gives QUIC room to evolve when middleboxes ossify TCP options.

Minimal C Demo — HOL Blocking

HOL Blocking: TCP vs QUIC — C Demo
stdin (optional)

2. § 14.2 — QUIC Wire Image

QUIC has two visible packet families. Long headers carry versioned handshake packets such as Initial, Handshake, 0-RTT, and Retry. Short headers carry protected 1-RTT application data after the handshake. Payloads are AEAD encrypted, and packet numbers are header-protected so passive observers see only a narrow, intentional wire image.

A packet carries frames rather than a single fixed payload type. The important frame families are STREAM for application bytes, ACK for received packet ranges,CRYPTO for TLS handshake bytes, flow-control credit frames, migration frames, and close frames.

3. § 14.3 — Streams and Flow Control

Stream IDs encode both ownership and direction in the low two bits: client bidirectional streams are 0, 4, 8; server bidirectional streams are 1, 5, 9; client unidirectional streams are 2, 6, 10; server unidirectional streams are 3, 7, 11. Each stream carries offsets, so retransmitted data can be placed back into the stream even though it appears in a new packet number.

Flow control exists at two levels. MAX_STREAM_DATA limits a single stream, while MAX_DATA limits total connection bytes. A paused or reset stream does not consume ordering progress from unrelated streams.

Minimal C Demo — Two-Level Flow Control

QUIC Stream Flow Control — C Demo
stdin (optional)

4. § 14.4 — TLS 1.3 Integration and 0-RTT

QUIC uses TLS 1.3 exclusively, but TLS records are not sent on the wire. Handshake messages are carried in CRYPTO frames, and QUIC packet protection applies at Initial, Handshake, and 1-RTT key phases. Initial keys are derived from the destination connection ID, so they protect against accidental corruption but are not secret.

0-RTT uses a resumption PSK from a prior connection. The latency win is real, but early data is replayable and not forward-secret in the same way as final 1-RTT data. Servers should restrict 0-RTT to idempotent requests and use anti-replay tokens or caches.

Minimal C Demo — 0-RTT Replay Trade-Off

0-RTT vs 1-RTT — C Demo
stdin (optional)

5. § 14.5 — Connection Migration

TCP identifies a connection by its 4-tuple. QUIC identifies the connection by connection IDs chosen by the peers, so a NAT rebinding or WiFi-to-cellular move can keep the transport state alive. The new path must still be validated with PATH_CHALLENGE and PATH_RESPONSE before the server fully trusts it.

Minimal C Demo — Migration vs Reconnect

QUIC Connection Migration — C Demo
stdin (optional)

6. § 14.6 — Loss Recovery and Congestion Control

QUIC packet numbers are monotonic and never reused. When a packet is lost, the sender retransmits its frames in a new packet with a new packet number. This removes TCP's retransmission ambiguity and lets ACK ranges act like a mandatory SACK mechanism. RFC 9002 declares loss by either a packet threshold of three higher acknowledged packets or a time threshold based on recent RTT.

Congestion control is still connection-level and usually uses familiar algorithms such as CUBIC, NewReno, or BBR. QUIC can also validate ECN because ACK frames report received ECT0, ECT1, and CE counters.

Minimal C Demo — Packet Threshold Loss

QUIC Loss Detection — C Demo
stdin (optional)

7. § 14.7 — HTTP/3 over QUIC

HTTP/3 maps each request and response to a bidirectional QUIC stream. QPACK replaces HPACK and separates header-table synchronization onto encoder and decoder streams, avoiding a single TCP-style compression dependency from stalling all requests.

Servers advertise HTTP/3 with Alt-Svc: h3=":443". Clients can coalesce origins onto one QUIC connection when the certificate and authority checks allow it.

8. § 14.8 — Implementations and Operational Notes

Production implementations include Cloudflare quiche, ngtcp2, Microsoft MsQuic, quic-go, LiteSpeed lsquic, Chromium QUIC, and nginx's native HTTP/3 support. At high throughput, Linux UDP GSO/GRO and pacing support matter because QUIC lives above UDP rather than inside the kernel TCP stack.

  • Debug wire behavior with qlog/qvis, packet captures, and browser net logs.
  • Remember that QUIC removes inter-stream HOL, not HOL within a single stream.
  • Keep 0-RTT handlers idempotent, authenticated, and replay-aware.
  • Migration depends on stable CIDs plus path validation, not on ignoring the 4-tuple.

Interview Prep

  • What exactly blocks in HTTP/2 over TCP when one TCP segment is lost?
  • Why are QUIC packet numbers never reused, even for retransmitted data?
  • What can safely be sent in 0-RTT, and what should never be sent there?
  • How does PATH_CHALLENGE defend connection migration from spoofed addresses?
  • Why did QPACK replace HPACK for HTTP/3?