# flare.quic.transport_params

> A module of flare_mlake's API.

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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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`

```mojo
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

### `TP_ID_ORIGINAL_DCID`

```mojo
comptime TP_ID_ORIGINAL_DCID = Int(0)
```

### `TP_ID_MAX_IDLE_TIMEOUT`

```mojo
comptime TP_ID_MAX_IDLE_TIMEOUT = Int(1)
```

### `TP_ID_STATELESS_RESET_TOKEN`

```mojo
comptime TP_ID_STATELESS_RESET_TOKEN = Int(2)
```

### `TP_ID_MAX_UDP_PAYLOAD_SIZE`

```mojo
comptime TP_ID_MAX_UDP_PAYLOAD_SIZE = Int(3)
```

### `TP_ID_INITIAL_MAX_DATA`

```mojo
comptime TP_ID_INITIAL_MAX_DATA = Int(4)
```

### `TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL`

```mojo
comptime TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL = Int(5)
```

### `TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE`

```mojo
comptime TP_ID_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE = Int(6)
```

### `TP_ID_INITIAL_MAX_STREAM_DATA_UNI`

```mojo
comptime TP_ID_INITIAL_MAX_STREAM_DATA_UNI = Int(7)
```

### `TP_ID_INITIAL_MAX_STREAMS_BIDI`

```mojo
comptime TP_ID_INITIAL_MAX_STREAMS_BIDI = Int(8)
```

### `TP_ID_INITIAL_MAX_STREAMS_UNI`

```mojo
comptime TP_ID_INITIAL_MAX_STREAMS_UNI = Int(9)
```

### `TP_ID_ACK_DELAY_EXPONENT`

```mojo
comptime TP_ID_ACK_DELAY_EXPONENT = Int(10)
```

### `TP_ID_MAX_ACK_DELAY`

```mojo
comptime TP_ID_MAX_ACK_DELAY = Int(11)
```

### `TP_ID_DISABLE_ACTIVE_MIGRATION`

```mojo
comptime TP_ID_DISABLE_ACTIVE_MIGRATION = Int(12)
```

### `TP_ID_PREFERRED_ADDRESS`

```mojo
comptime TP_ID_PREFERRED_ADDRESS = Int(13)
```

### `TP_ID_ACTIVE_CONNECTION_ID_LIMIT`

```mojo
comptime TP_ID_ACTIVE_CONNECTION_ID_LIMIT = Int(14)
```

### `TP_ID_INITIAL_SCID`

```mojo
comptime TP_ID_INITIAL_SCID = Int(15)
```

### `TP_ID_RETRY_SCID`

```mojo
comptime TP_ID_RETRY_SCID = Int(16)
```

### `TP_ID_MAX_DATAGRAM_FRAME_SIZE`

```mojo
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.

### `TP_ID_MIN_ACK_DELAY`

```mojo
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.

### `DEFAULT_MAX_UDP_PAYLOAD_SIZE`

```mojo
comptime DEFAULT_MAX_UDP_PAYLOAD_SIZE = UInt64(65527)
```

### `DEFAULT_ACK_DELAY_EXPONENT`

```mojo
comptime DEFAULT_ACK_DELAY_EXPONENT = UInt64(3)
```

### `DEFAULT_MAX_ACK_DELAY`

```mojo
comptime DEFAULT_MAX_ACK_DELAY = UInt64(25)
```

### `DEFAULT_ACTIVE_CONNECTION_ID_LIMIT`

```mojo
comptime DEFAULT_ACTIVE_CONNECTION_ID_LIMIT = UInt64(2)
```
