From 4f2338d7b23b05d65e5f177d527a1d33074ddd5d Mon Sep 17 00:00:00 2001 From: Yury Yarashevich Date: Tue, 26 Nov 2024 10:28:42 +0100 Subject: [PATCH] #2057: Extract known transport parameter IDs into enum. --- quinn-proto/src/transport_parameters.rs | 101 ++++++++++++++++++------ 1 file changed, 75 insertions(+), 26 deletions(-) diff --git a/quinn-proto/src/transport_parameters.rs b/quinn-proto/src/transport_parameters.rs index 381968059c..c4eb7d30a6 100644 --- a/quinn-proto/src/transport_parameters.rs +++ b/quinn-proto/src/transport_parameters.rs @@ -25,6 +25,47 @@ use crate::{ RESET_TOKEN_SIZE, TIMER_GRANULARITY, }; +#[repr(u64)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum TransportParameterId { + // https://www.rfc-editor.org/rfc/rfc9000.html#iana-tp-table + OriginalDestinationConnectionId = 0x00, + MaxIdleTimeout = 0x01, + StatelessResetToken = 0x02, + MaxUdpPayloadSize = 0x03, + InitialMaxData = 0x04, + InitialMaxStreamDataBidiLocal = 0x05, + InitialMaxStreamDataBidiRemote = 0x06, + InitialMaxStreamDataUni = 0x07, + InitialMaxStreamsBidi = 0x08, + InitialMaxStreamsUni = 0x09, + AckDelayExponent = 0x0A, + MaxAckDelay = 0x0B, + DisableActiveMigration = 0x0C, + PreferredAddress = 0x0D, + ActiveConnectionIdLimit = 0x0E, + InitialSourceConnectionId = 0x0F, + RetrySourceConnectionId = 0x10, + + // Smallest possible ID of reserved transport parameter https://datatracker.ietf.org/doc/html/rfc9000#section-22.3 + ReservedTransportParameter = 0x1B, + + // https://www.rfc-editor.org/rfc/rfc9221.html#section-3 + MaxDatagramFrameSize = 0x20, + + // https://www.rfc-editor.org/rfc/rfc9287.html#section-3 + GreaseQuicBit = 0x2AB2, + + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-ack-frequency#section-10.1 + MinAckDelayDraft07 = 0xFF04DE1B, +} + +impl std::cmp::PartialEq for TransportParameterId { + fn eq(&self, other: &u64) -> bool { + *other == (*self as u64) + } +} + // Apply a given macro to a list of all the transport parameters having integer types, along with // their codes and default values. Using this helps us avoid error-prone duplication of the // contained information across decoding, encoding, and the `Default` impl. Whenever we want to do @@ -35,37 +76,37 @@ macro_rules! apply_params { $macro! { // #[doc] name (id) = default, /// Milliseconds, disabled if zero - max_idle_timeout(0x0001) = 0, + max_idle_timeout(MaxIdleTimeout) = 0, /// Limits the size of UDP payloads that the endpoint is willing to receive - max_udp_payload_size(0x0003) = 65527, + max_udp_payload_size(MaxUdpPayloadSize) = 65527, /// Initial value for the maximum amount of data that can be sent on the connection - initial_max_data(0x0004) = 0, + initial_max_data(InitialMaxData) = 0, /// Initial flow control limit for locally-initiated bidirectional streams - initial_max_stream_data_bidi_local(0x0005) = 0, + initial_max_stream_data_bidi_local(InitialMaxStreamDataBidiLocal) = 0, /// Initial flow control limit for peer-initiated bidirectional streams - initial_max_stream_data_bidi_remote(0x0006) = 0, + initial_max_stream_data_bidi_remote(InitialMaxStreamDataBidiRemote) = 0, /// Initial flow control limit for unidirectional streams - initial_max_stream_data_uni(0x0007) = 0, + initial_max_stream_data_uni(InitialMaxStreamDataUni) = 0, /// Initial maximum number of bidirectional streams the peer may initiate - initial_max_streams_bidi(0x0008) = 0, + initial_max_streams_bidi(InitialMaxStreamsBidi) = 0, /// Initial maximum number of unidirectional streams the peer may initiate - initial_max_streams_uni(0x0009) = 0, + initial_max_streams_uni(InitialMaxStreamsUni) = 0, /// Exponent used to decode the ACK Delay field in the ACK frame - ack_delay_exponent(0x000a) = 3, + ack_delay_exponent(AckDelayExponent) = 3, /// Maximum amount of time in milliseconds by which the endpoint will delay sending /// acknowledgments - max_ack_delay(0x000b) = 25, + max_ack_delay(MaxAckDelay) = 25, /// Maximum number of connection IDs from the peer that an endpoint is willing to store - active_connection_id_limit(0x000e) = 2, + active_connection_id_limit(ActiveConnectionIdLimit) = 2, } }; } macro_rules! make_struct { - {$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => { + {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => { /// Transport parameters used to negotiate connection-level preferences between peers #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct TransportParameters { @@ -296,10 +337,10 @@ impl TransportParameters { /// Encode `TransportParameters` into buffer pub fn write(&self, w: &mut W) { macro_rules! write_params { - {$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => { + {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => { $( if self.$name.0 != $default { - w.write_var($code); + w.write_var(TransportParameterId::$id as u64); w.write(VarInt::try_from(self.$name.size()).unwrap()); w.write(self.$name); } @@ -366,7 +407,7 @@ impl TransportParameters { // State to check for duplicate transport parameters. macro_rules! param_state { - {$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {{ + {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{ struct ParamState { $($name: bool,)* } @@ -387,8 +428,10 @@ impl TransportParameters { let len = len as usize; match id { - 0x00 => decode_cid(len, &mut params.original_dst_cid, r)?, - 0x02 => { + id if TransportParameterId::OriginalDestinationConnectionId == id => { + decode_cid(len, &mut params.original_dst_cid, r)? + } + id if TransportParameterId::StatelessResetToken == id => { if len != 16 || params.stateless_reset_token.is_some() { return Err(Error::Malformed); } @@ -396,36 +439,42 @@ impl TransportParameters { r.copy_to_slice(&mut tok); params.stateless_reset_token = Some(tok.into()); } - 0x0c => { + id if TransportParameterId::DisableActiveMigration == id => { if len != 0 || params.disable_active_migration { return Err(Error::Malformed); } params.disable_active_migration = true; } - 0x0d => { + id if TransportParameterId::PreferredAddress == id => { if params.preferred_address.is_some() { return Err(Error::Malformed); } params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?); } - 0x0f => decode_cid(len, &mut params.initial_src_cid, r)?, - 0x10 => decode_cid(len, &mut params.retry_src_cid, r)?, - 0x20 => { + id if TransportParameterId::InitialSourceConnectionId == id => { + decode_cid(len, &mut params.initial_src_cid, r)? + } + id if TransportParameterId::RetrySourceConnectionId == id => { + decode_cid(len, &mut params.retry_src_cid, r)? + } + id if TransportParameterId::MaxDatagramFrameSize == id => { if len > 8 || params.max_datagram_frame_size.is_some() { return Err(Error::Malformed); } params.max_datagram_frame_size = Some(r.get().unwrap()); } - 0x2ab2 => match len { + id if TransportParameterId::GreaseQuicBit == id => match len { 0 => params.grease_quic_bit = true, _ => return Err(Error::Malformed), }, - 0xff04de1b => params.min_ack_delay = Some(r.get().unwrap()), + id if TransportParameterId::MinAckDelayDraft07 == id => { + params.min_ack_delay = Some(r.get().unwrap()) + } _ => { macro_rules! parse { - {$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => { + {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => { match id { - $($code => { + $(id if TransportParameterId::$id == id => { let value = r.get::()?; if len != value.size() || got.$name { return Err(Error::Malformed); } params.$name = value.into();