flare_mlake · API · quic

flare.quic.transport_params

QUIC transport-parameter codec (RFC 9000 §18 + §19.1.1).

QUIC peers exchange transport parameters during the TLS handshake (carried in the TLS extension quic_transport_parameters, codepoint 0x39). Each parameter is encoded as varint(id) || varint(length) || bytes[length]; the codec is fully self-describing so unknown parameters are silently ignored (RFC 9000 §7.4.2 -- forward compatibility).

Public surface:

  • :class:TransportParameters -- typed carrier for the v1 parameter set with sensible defaults from §18.2.
  • :func:encode_transport_parameters -- serialise a populated :class:TransportParameters into a byte list. Unset parameters whose default is the wire absence are not emitted; explicitly set parameters always are.
  • :func:decode_transport_parameters -- parse a byte buffer into a :class:TransportParameters; unknown ids are dropped on the floor per RFC.

Parameter ids covered (RFC 9000 §18.2 + RFC 9221 §3 for datagram):

  • 0x00 original_destination_connection_id (server only)
  • 0x01 max_idle_timeout (ms; 0 means no timeout)
  • 0x02 stateless_reset_token (server only; 16 bytes)
  • 0x03 max_udp_payload_size (default 65527)
  • 0x04 initial_max_data
  • 0x05 initial_max_stream_data_bidi_local
  • 0x06 initial_max_stream_data_bidi_remote
  • 0x07 initial_max_stream_data_uni
  • 0x08 initial_max_streams_bidi
  • 0x09 initial_max_streams_uni
  • 0x0a ack_delay_exponent (default 3)
  • 0x0b max_ack_delay (default 25 ms)
  • 0x0c disable_active_migration (flag, zero-length value)
  • 0x0d preferred_address (layout validated, value not kept)
  • 0x0e active_connection_id_limit (default 2; minimum 2)
  • 0x0f initial_source_connection_id
  • 0x10 retry_source_connection_id (server only)
  • 0x20 max_datagram_frame_size (RFC 9221 §3; enables DATAGRAM)

The 0x0d preferred_address parameter carries a peer's preferred IP/port for migration, which flare does not use: decode checks its fixed layout (RFC 9000 §18.2: 4 + 2 + 16 + 2 bytes, a CID length of 1..20, the CID, a 16-byte reset token) and raises on a violation, but does not store the value.

Sans-I/O contract: zero I/O imports; registered in tests/tools/check_sans_io.sh so the contract is lint-enforced.

References:

  • RFC 9000 §18 "Transport Parameter Encoding".
  • RFC 9000 §7.4.2 "New Transport Parameters" (forward-compat).
  • aioquic packet.PullQuicTransportParameters (Python ref).

Structs

TransportParameters

struct TransportParameters

Decoded QUIC transport parameters (RFC 9000 §18).

Optional fields default to None to distinguish "absent on the wire" from "explicit zero". The caller treats None as the RFC default per parameter (encoded inline above each field's docstring); the codec only emits a parameter when its Optional is populated.

Connection-id fields and the stateless reset token are stored as List[UInt8] so the caller can move them out into the connection-state-machine layer without a copy.

Implements Copyable, Movable

Fields
original_destination_connection_id: List[UInt8]
max_idle_timeout: Optional[UInt64]
stateless_reset_token: List[UInt8]
max_udp_payload_size: Optional[UInt64]
initial_max_data: Optional[UInt64]
initial_max_stream_data_bidi_local: Optional[UInt64]
initial_max_stream_data_bidi_remote: Optional[UInt64]
initial_max_stream_data_uni: Optional[UInt64]
initial_max_streams_bidi: Optional[UInt64]
initial_max_streams_uni: Optional[UInt64]
ack_delay_exponent: Optional[UInt64]
max_ack_delay: Optional[UInt64]
disable_active_migration: Bool
active_connection_id_limit: Optional[UInt64]
initial_source_connection_id: List[UInt8]
retry_source_connection_id: List[UInt8]
max_datagram_frame_size: Optional[UInt64]: RFC 9221 §3 max_datagram_frame_size (id 0x20). When populated and non-zero, the peer may send DATAGRAM frames up to this size; absent / 0 disables datagrams for this connection.
min_ack_delay: Optional[UInt64]

PeerSendLimits

struct PeerSendLimits

The subset of a peer's transport parameters that constrains what we may send, with RFC 9000 §18.2 defaults already applied.

A client decodes the server's quic_transport_parameters after the handshake (:meth:flare.tls.rustls_quic.RustlsQuicSession. peer_transport_params) and derives this view via :func:derive_peer_send_limits. The QUIC driver then clamps its egress datagram size to :attr:max_udp_payload_size and refuses stream / connection sends that would exceed :attr:max_stream_data_bidi_remote / :attr:max_data.

Flow-control directions are from the sender's perspective: for a bidi stream the client opens, the server's receive limit is its initial_max_stream_data_bidi_remote (remote = peer-initiated from the server's point of view). The flow-control limits default to 0 when absent (RFC 9000 §18.2 -- no data may be sent until a MAX_DATA / MAX_STREAM_DATA frame raises them).

Implements Copyable, Movable

Fields
max_data: UInt64
max_stream_data_bidi_remote: UInt64
max_stream_data_uni: UInt64
max_udp_payload_size: UInt64
max_datagram_frame_size: UInt64
max_streams_bidi: UInt64
max_streams_uni: UInt64

Functions

empty_transport_parameters

def empty_transport_parameters() -> TransportParameters

Return a :class:TransportParameters with every field cleared (every Optional is None and every byte buffer is empty). Build up the carrier by populating the fields the caller wants on the wire, then pass to :func:encode_transport_parameters.

derive_peer_send_limits

def derive_peer_send_limits(params: TransportParameters) -> PeerSendLimits

Project a decoded :class:TransportParameters onto the send-constraining :class:PeerSendLimits view, applying the RFC 9000 §18.2 defaults for any absent parameter.

The flow-control parameters default to 0 (absence means "no initial allowance"); max_udp_payload_size defaults to 65527; max_datagram_frame_size defaults to 0 (peer forbids DATAGRAM frames). Pure / sans-I/O so it is unit-testable against :func:encode_transport_parameters round-trips.

encode_transport_parameters

def encode_transport_parameters(params: TransportParameters) -> List[UInt8]

Serialise params to bytes.

Only fields that have been populated (Optional is Some or a byte list is non-empty) are emitted; absent parameters are silently dropped so the receiver picks up the RFC default. The one exception is :data:disable_active_migration, which is emitted as a zero-length parameter whenever params.disable_ active_migration is True.

decode_transport_parameters

def decode_transport_parameters(buf: Span[UInt8]) -> TransportParameters

Parse a transport-parameters extension payload.

Loops varint(id) || varint(length) || bytes[length] until the buffer is drained. Unknown ids are silently dropped per RFC 9000 §7.4.2. Duplicate parameter ids are rejected (the RFC requires each parameter to appear at most once).

transport_parameter_present

def transport_parameter_present(buf: Span[UInt8], id: Int) -> Bool

Whether parameter id occurs in the TLV list buf.

:func:decode_transport_parameters stores a CID parameter as a list that is empty both when the parameter is absent and when it is present with length 0, so a check that must tell the two apart (RFC 9000 §7.3, §18.2) scans the raw bytes instead. A malformed list reports False: the caller has already run (or will run) the decoder, which raises on it.

check_client_transport_params

def check_client_transport_params(buf: Span[UInt8], client_scid: List[UInt8])

Validate the transport parameters a server received from a client.

Raises TRANSPORT_PARAMETER_ERROR (RFC 9000 §18.2, §7.3, §7.4) when the blob does not decode (truncation, duplicates, invalid values), when it carries a server-only parameter (original_destination_connection_id, stateless_reset_token, preferred_address or retry_source_connection_id), or when initial_source_connection_id is absent or differs from client_scid, the Source Connection ID of the client's Initial packet (which may legitimately be zero-length).

check_server_transport_params

def check_server_transport_params(buf: Span[UInt8], first_dcid: List[UInt8], server_scid: List[UInt8], retried: Bool, retry_scid: List[UInt8])

Validate the transport parameters a client received from a server.

Raises TRANSPORT_PARAMETER_ERROR (RFC 9000 §7.3, §18.2) when the blob does not decode, when original_destination_connection_id is absent or is not the DCID of the client's first Initial, when initial_source_connection_id is absent or is not the Source Connection ID the server used (a zero-length one must still be present), when retry_source_connection_id is present without a Retry (or absent after one, or different from the Retry's Source Connection ID), or when the server used a zero-length connection ID and sent a preferred_address.

Presence is read from the raw bytes (:func:transport_parameter_present) because the decoded record stores an absent CID parameter and a zero-length one alike as an empty list.

Aliases

comptime TP_ID_ORIGINAL_DCID = Int(0)
comptime TP_ID_MAX_IDLE_TIMEOUT = Int(1)
comptime TP_ID_STATELESS_RESET_TOKEN = Int(2)
comptime TP_ID_MAX_UDP_PAYLOAD_SIZE = Int(3)
comptime TP_ID_INITIAL_MAX_DATA = Int(4)
comptime TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = Int(5)
comptime TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = Int(6)
comptime TP_ID_INITIAL_MAX_STREAM_DATA_UNI = Int(7)
comptime TP_ID_INITIAL_MAX_STREAMS_BIDI = Int(8)
comptime TP_ID_INITIAL_MAX_STREAMS_UNI = Int(9)
comptime TP_ID_ACK_DELAY_EXPONENT = Int(10)
comptime TP_ID_MAX_ACK_DELAY = Int(11)
comptime TP_ID_DISABLE_ACTIVE_MIGRATION = Int(12)
comptime TP_ID_PREFERRED_ADDRESS = Int(13)
comptime TP_ID_ACTIVE_CONNECTION_ID_LIMIT = Int(14)
comptime TP_ID_INITIAL_SCID = Int(15)
comptime TP_ID_RETRY_SCID = Int(16)
comptime TP_ID_MAX_DATAGRAM_FRAME_SIZE = Int(32)

RFC 9221 §3: max DATAGRAM frame size the endpoint will accept. Absent or 0 means the peer MUST NOT send DATAGRAM frames.

comptime TP_ID_MIN_ACK_DELAY = Int(4278509083)

The draft-ietf-quic-ack-frequency minimum: the smallest ACK delay (microseconds) the endpoint can honour; present means it accepts ACK_FREQUENCY.

comptime DEFAULT_MAX_UDP_PAYLOAD_SIZE = UInt64(65527)
comptime DEFAULT_ACK_DELAY_EXPONENT = UInt64(3)
comptime DEFAULT_MAX_ACK_DELAY = UInt64(25)
comptime DEFAULT_ACTIVE_CONNECTION_ID_LIMIT = UInt64(2)