Module Map

View Source

Where the code lives and what to read first. The source is 68 modules and about 47,000 lines, and roughly a quarter of it is one module, so reading in file order does not work. Read this when you are new to the tree, or when you know what you want to change but not where it lives. docs/DESIGN.md covers how the protocol works; this page covers where it is.

Read these seven first

In this order, they give you the whole path of a connection without opening the big module:

  1. src/quic.erl (976 lines) is the public API and the owner-message protocol. Its module header lists every message an owner receives.
  2. src/quic_listener.erl (1,411) accepts connections. Its header is the clearest writing in the tree on connection ownership and the handover race.
  3. src/quic_packet.erl (405) and src/quic_frame.erl (443) are the wire format, with the header diagrams in the packet module.
  4. src/quic_varint.erl (112) is the encoding everything else is built from.
  5. src/quic_crypto.erl (671) is the key schedule, and src/quic_aead.erl packet protection.
  6. src/quic_cc.erl (401) is the congestion control behaviour, with quic_loss and quic_ack beside it.
  7. src/quic_connection.erl (12,691) is the state machine everything above meets in. Read it by section banner, not top to bottom.

Layers

LayerModules
Public APIquic, quic_listener
Connectionquic_connection, quic_connection_state.hrl, quic_cid (both connection ID pools and the two active_connection_id_limits), quic_pqueue (the send queue's urgency buckets, RFC 9218), quic_reassembly (out-of-order buffers), quic_interval (disjoint interval lists, used for reclaimed stream ids)
Protocolquic_packet, quic_frame, quic_varint
Cryptoquic_crypto, quic_tls, quic_tls_negotiation (cipher, ALPN and group choices), quic_keys, quic_aead, quic_aead_ctx, quic_hkdf, quic_crypto_nif, quic_cert, quic_keylog
Recoveryquic_cc with quic_cc_newreno, quic_cc_cubic, quic_cc_bbr; quic_loss (per-packet-number-space sent packets and loss state, with the probe backoff and bytes in flight connection-wide), quic_rtt (the path's RTT estimate, which every space shares), quic_ack (the connection's ACK range and frame path, plus an #ack_state{} accumulator only tests drive)
Transport servicesquic_socket, quic_pmtu, quic_lb, quic_happy, quic_ticket, quic_token_cache, quic_address_token, quic_qlog
Supervisionquic_app, quic_sup, quic_server_sup, quic_server_registry, quic_conn_sup, quic_happy_sup, quic_listener_sup, quic_listener_sup_sup, quic_listener_manager
HTTP/3src/h3/: quic_h3, quic_h3_connection, quic_h3_frame, quic_h3_capsule, plus the client and server escripts
QPACKsrc/qpack/: quic_qpack, quic_qpack_huffman, quic_qpack_prefix
Distributionsrc/dist/: quic_dist, quic_dist_controller, quic_dist_dispatch, quic_dist_auth, quic_dist_tickets, quic_epmd, quic_discovery*
Interopsrc/interop/: the runner client and server escripts

What depends on what

Most called, so most expensive to change:

ModuleLinesCalled byCalls
quic97686
quic_varint11280
quic_crypto67161
quic_listener1,41158
quic_connection12,691522
quic_cc40141
quic_h383642

quic_connection calling 22 other modules and being called by 5 is the shape to keep in mind: it is the hub, and almost any protocol change lands in it.

Modules no grep will lead you to

Sixteen modules have no caller anywhere in src. None is dead, and each is reached a different way:

ModuleHow it is reached
quic_cc_cubic, quic_cc_bbrquic_cc maps the cc_algorithm option to one of these modules internally and calls it through the quic_cc behaviour. quic_cc_newreno is not here: quic_cc also calls it by name on a fast path
quic_epmdNamed in a VM argument, -epmd_module quic_epmd
quic_h3_client, quic_h3_server, quic_interop_client, quic_interop_serverescript entry points, built per rebar3 profile
quic_app, quic_dist_sup, quic_dist_tickets, quic_listener_sup_supStarted by a supervisor as a child spec, by name
quic_discovery_static, quic_discovery_dnsSelected by dist configuration
quic_flow, quic_streamStandalone helpers. The connection implements its own flow control and stream state inline
quic_h3_capsuleA primitive for extension libraries, used by erlang_masque

Reading quic_connection

The file carries section banners, and the module header lists them in order. The ones worth knowing:

  • API and gen_statem callbacks, then the five state functions: idle, handshaking, connected, draining, closed.
  • TLS handshake, then PSK validation and the session ticket store, then the handshake's server flight. Its second half, the TLS message driver, sits inside the packet-processing region because that is where CRYPTO frames arrive.
  • Packet send layer: frames and payloads become packets, at all three levels.
  • Packet processing, the largest region, covering decrypt, parse and the batched receive path.
  • Stream processing and reassembly; socket I/O; ACK emission and decimation; delivery to the owner.
  • Send path, then the send queue and its urgency priority queue.
  • Timers: retransmission, PTO, idle, keep-alive, pacing.
  • Key update, migration, PMTU.

The two hot paths have their own walkthroughs: SEND_PATH.md and RECV_PATH.md.

#state{} lives in src/quic_connection_state.hrl and has 186 fields. When you change one, grep for the field name rather than reading the function you are in: most fields are touched in several regions.

Where tests live

test/ is flat: quic_*_tests.erl for EUnit, prop_quic_*.erl for properties, quic_*_SUITE.erl for Common Test. A subsystem's tests are named after it, so quic_loss_time_threshold_tests.erl is the place to learn loss detection by example.