// QUIC transport parameters (RFC 9000 §18). Each endpoint declares its limits — flow
// control, connection IDs, idle timeout — in a block carried by the TLS handshake.
// The wire form is a sequence of (id, length, value), all lengths and integer values
// varint-encoded (§18.1).
///|
/// The transport-parameter identifiers this build recognizes by name (RFC 9000 §18.2).
/// The block is still encoded and decoded generically, so unknown ids pass through.
pub let tp_max_idle_timeout : UInt64 = 0x01
///|
/// The largest UDP payload this endpoint is willing to receive.
pub let tp_max_udp_payload_size : UInt64 = 0x03
///|
/// Connection-level flow-control credit the peer starts with.
pub let tp_initial_max_data : UInt64 = 0x04
///|
/// Starting credit on bidirectional streams this endpoint opens.
pub let tp_initial_max_stream_data_bidi_local : UInt64 = 0x05
///|
/// Starting credit on bidirectional streams the peer opens.
pub let tp_initial_max_stream_data_bidi_remote : UInt64 = 0x06
///|
/// Starting credit on unidirectional streams.
pub let tp_initial_max_stream_data_uni : UInt64 = 0x07
///|
/// How many bidirectional streams the peer may open.
pub let tp_initial_max_streams_bidi : UInt64 = 0x08
///|
/// How many unidirectional streams the peer may open.
pub let tp_initial_max_streams_uni : UInt64 = 0x09
///|
/// The exponent the peer's ACK Delay field is scaled by.
pub let tp_ack_delay_exponent : UInt64 = 0x0a
///|
/// The longest this endpoint will sit on an acknowledgement.
pub let tp_max_ack_delay : UInt64 = 0x0b
///|
/// How many connection ids this endpoint will keep active at once.
pub let tp_active_connection_id_limit : UInt64 = 0x0e
///|
/// The source connection id this endpoint used on its first packet, which is what binds the handshake to the addresses it ran over.
pub let tp_initial_source_connection_id : UInt64 = 0x0f
///|
/// A transport parameter: an identifier and its raw value bytes. Integer parameters
/// carry a varint-encoded value; use `transport_param_int` / `transport_param_as_int`
/// to build and read those.
pub(all) struct TransportParam {
id : UInt64
value : Bytes
} derive(Eq, Debug)
///|
/// A transport parameter whose value is a single varint integer (RFC 9000 §18.2).
pub fn transport_param_int(id : UInt64, value : UInt64) -> TransportParam {
{ id, value: quic_varint_encode(value), }
}
///|
/// Read a varint-valued transport parameter's integer, or `None` if its value is not
/// a single well-formed varint.
pub fn transport_param_as_int(p : TransportParam) -> UInt64? {
guard quic_varint_decode(p.value[:]) is Some((v, n)) else { return None }
if n == p.value.length() {
Some(v)
} else {
None
}
}
///|
/// Encode a transport-parameter block: each parameter as its id varint, a length
/// varint, then the value bytes (RFC 9000 §18).
pub fn encode_transport_params(params : Array[TransportParam]) -> Bytes {
let buf = Buffer()
for p in params {
buf.write_bytes(quic_varint_encode(p.id)[:])
buf.write_bytes(quic_varint_encode(p.value.length().to_uint64())[:])
buf.write_bytes(p.value[:])
}
buf.to_bytes()
}
///|
/// Decode a transport-parameter block, preserving order and duplicates so the caller
/// can apply RFC 9000 §7.4's rules. Returns `None` on a truncated parameter.
pub fn decode_transport_params(b : BytesView) -> Array[TransportParam]? {
let out : Array[TransportParam] = []
let mut off = 0
while off < b.length() {
guard quic_varint_decode(b[off:]) is Some((id, il)) else { return None }
off = off + il
guard quic_varint_decode(b[off:]) is Some((length, ll)) else { return None }
off = off + ll
let n = length.to_int()
if b.length() < off + n {
return None
}
out.push({ id, value: b[off:off + n].to_owned(), })
off = off + n
}
Some(out)
}