Skip to content

Commit 1f78a7b

Browse files
committed
quinn-rs#2057: Store IDs of transport parameters in enum.
1 parent a750a82 commit 1f78a7b

File tree

1 file changed

+114
-52
lines changed

1 file changed

+114
-52
lines changed

quinn-proto/src/transport_parameters.rs

+114-52
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,41 @@ use crate::{
2525
RESET_TOKEN_SIZE, TIMER_GRANULARITY,
2626
};
2727

28+
#[repr(u32)]
29+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30+
pub(crate) enum TransportParameterId {
31+
// https://www.rfc-editor.org/rfc/rfc9000.html#iana-tp-table
32+
OriginalDestinationConnectionId = 0x00,
33+
MaxIdleTimeout = 0x01,
34+
StatelessResetToken = 0x02,
35+
MaxUdpPayloadSize = 0x03,
36+
InitialMaxData = 0x04,
37+
InitialMaxStreamDataBidiLocal = 0x05,
38+
InitialMaxStreamDataBidiRemote = 0x06,
39+
InitialMaxStreamDataUni = 0x07,
40+
InitialMaxStreamsBidi = 0x08,
41+
InitialMaxStreamsUni = 0x09,
42+
AckDelayExponent = 0x0A,
43+
MaxAckDelay = 0x0B,
44+
DisableActiveMigration = 0x0C,
45+
PreferredAddress = 0x0D,
46+
ActiveConnectionIdLimit = 0x0E,
47+
InitialSourceConnectionId = 0x0F,
48+
RetrySourceConnectionId = 0x10,
49+
50+
// Smallest possible ID of reserved transport parameter https://datatracker.ietf.org/doc/html/rfc9000#section-22.3
51+
ReservedTransportParameter = 0x1B,
52+
53+
// https://www.rfc-editor.org/rfc/rfc9221.html#section-3
54+
MaxDatagramFrameSize = 0x20,
55+
56+
// https://www.rfc-editor.org/rfc/rfc9287.html#section-3
57+
GreaseQuicBit = 0x2AB2,
58+
59+
// https://datatracker.ietf.org/doc/html/draft-ietf-quic-ack-frequency#section-10.1
60+
MinAckDelayDraft07 = 0xFF04DE1B,
61+
}
62+
2863
// Apply a given macro to a list of all the transport parameters having integer types, along with
2964
// their codes and default values. Using this helps us avoid error-prone duplication of the
3065
// contained information across decoding, encoding, and the `Default` impl. Whenever we want to do
@@ -35,42 +70,61 @@ macro_rules! apply_params {
3570
$macro! {
3671
// #[doc] name (id) = default,
3772
/// Milliseconds, disabled if zero
38-
max_idle_timeout(0x0001) = 0,
73+
max_idle_timeout(MaxIdleTimeout) = 0,
3974
/// Limits the size of UDP payloads that the endpoint is willing to receive
40-
max_udp_payload_size(0x0003) = 65527,
75+
max_udp_payload_size(MaxUdpPayloadSize) = 65527,
4176

4277
/// Initial value for the maximum amount of data that can be sent on the connection
43-
initial_max_data(0x0004) = 0,
78+
initial_max_data(InitialMaxData) = 0,
4479
/// Initial flow control limit for locally-initiated bidirectional streams
45-
initial_max_stream_data_bidi_local(0x0005) = 0,
80+
initial_max_stream_data_bidi_local(InitialMaxStreamDataBidiLocal) = 0,
4681
/// Initial flow control limit for peer-initiated bidirectional streams
47-
initial_max_stream_data_bidi_remote(0x0006) = 0,
82+
initial_max_stream_data_bidi_remote(InitialMaxStreamDataBidiRemote) = 0,
4883
/// Initial flow control limit for unidirectional streams
49-
initial_max_stream_data_uni(0x0007) = 0,
84+
initial_max_stream_data_uni(InitialMaxStreamDataUni) = 0,
5085

5186
/// Initial maximum number of bidirectional streams the peer may initiate
52-
initial_max_streams_bidi(0x0008) = 0,
87+
initial_max_streams_bidi(InitialMaxStreamsBidi) = 0,
5388
/// Initial maximum number of unidirectional streams the peer may initiate
54-
initial_max_streams_uni(0x0009) = 0,
89+
initial_max_streams_uni(InitialMaxStreamsUni) = 0,
5590

5691
/// Exponent used to decode the ACK Delay field in the ACK frame
57-
ack_delay_exponent(0x000a) = 3,
92+
ack_delay_exponent(AckDelayExponent) = 3,
5893
/// Maximum amount of time in milliseconds by which the endpoint will delay sending
5994
/// acknowledgments
60-
max_ack_delay(0x000b) = 25,
95+
max_ack_delay(MaxAckDelay) = 25,
6196
/// Maximum number of connection IDs from the peer that an endpoint is willing to store
62-
active_connection_id_limit(0x000e) = 2,
97+
active_connection_id_limit(ActiveConnectionIdLimit) = 2,
6398
}
6499
};
65100
}
66101

67-
const DEFAULT_TRANSPORT_PARAMETERS_ORDER: [u32; 21] = [
68-
0x0001, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000e, 27,
69-
0x02, 0x0c, 0x20, 0x000d, 0x00, 0x0f, 0x10, 0x2ab2, 0xff04de1b,
102+
const DEFAULT_TRANSPORT_PARAMETERS_ORDER: [TransportParameterId; 21] = [
103+
TransportParameterId::MaxIdleTimeout,
104+
TransportParameterId::MaxUdpPayloadSize,
105+
TransportParameterId::InitialMaxData,
106+
TransportParameterId::InitialMaxStreamDataBidiLocal,
107+
TransportParameterId::InitialMaxStreamDataBidiRemote,
108+
TransportParameterId::InitialMaxStreamDataUni,
109+
TransportParameterId::InitialMaxStreamsBidi,
110+
TransportParameterId::InitialMaxStreamsUni,
111+
TransportParameterId::AckDelayExponent,
112+
TransportParameterId::MaxAckDelay,
113+
TransportParameterId::ActiveConnectionIdLimit,
114+
TransportParameterId::ReservedTransportParameter,
115+
TransportParameterId::StatelessResetToken,
116+
TransportParameterId::DisableActiveMigration,
117+
TransportParameterId::MaxDatagramFrameSize,
118+
TransportParameterId::PreferredAddress,
119+
TransportParameterId::OriginalDestinationConnectionId,
120+
TransportParameterId::InitialSourceConnectionId,
121+
TransportParameterId::RetrySourceConnectionId,
122+
TransportParameterId::GreaseQuicBit,
123+
TransportParameterId::MinAckDelayDraft07,
70124
];
71125

72126
macro_rules! make_struct {
73-
{$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {
127+
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
74128
/// Transport parameters used to negotiate connection-level preferences between peers
75129
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
76130
pub struct TransportParameters {
@@ -111,7 +165,7 @@ macro_rules! make_struct {
111165
pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,
112166

113167
/// The order in which transport parameters are serialized
114-
pub(crate) write_order: Option<[u32; 21]>,
168+
pub(crate) write_order: Option<[TransportParameterId; 21]>,
115169
}
116170

117171
// We deliberately don't implement the `Default` trait, since that would be public, and
@@ -309,91 +363,91 @@ impl From<UnexpectedEnd> for Error {
309363
impl TransportParameters {
310364
/// Encode `TransportParameters` into buffer
311365
pub fn write<W: BufMut>(&self, w: &mut W) {
312-
for id in self
366+
for &id in self
313367
.write_order
314368
.as_ref()
315369
.unwrap_or(&DEFAULT_TRANSPORT_PARAMETERS_ORDER)
316370
{
317371
match id {
318-
27 => {
372+
TransportParameterId::ReservedTransportParameter => {
319373
if let Some(param) = self.grease_transport_parameter {
320374
param.write(w);
321375
}
322376
}
323-
0x02 => {
377+
TransportParameterId::StatelessResetToken => {
324378
if let Some(ref x) = self.stateless_reset_token {
325-
w.write_var(0x02);
379+
w.write_var(id as u64);
326380
w.write_var(16);
327381
w.put_slice(x);
328382
}
329383
}
330-
0x0c => {
384+
TransportParameterId::DisableActiveMigration => {
331385
if self.disable_active_migration {
332-
w.write_var(0x0c);
386+
w.write_var(id as u64);
333387
w.write_var(0);
334388
}
335389
}
336-
0x20 => {
390+
TransportParameterId::MaxDatagramFrameSize => {
337391
if let Some(x) = self.max_datagram_frame_size {
338-
w.write_var(0x20);
392+
w.write_var(id as u64);
339393
w.write_var(x.size() as u64);
340394
w.write(x);
341395
}
342396
}
343-
0x0d => {
397+
TransportParameterId::PreferredAddress => {
344398
if let Some(ref x) = self.preferred_address {
345-
w.write_var(0x000d);
399+
w.write_var(id as u64);
346400
w.write_var(x.wire_size() as u64);
347401
x.write(w);
348402
}
349403
}
350-
0x00 => {
404+
TransportParameterId::OriginalDestinationConnectionId => {
351405
if let Some(ref cid) = self.original_dst_cid {
352-
w.write_var(0x00);
406+
w.write_var(id as u64);
353407
w.write_var(cid.len() as u64);
354408
w.put_slice(cid);
355409
}
356410
}
357-
0x0f => {
411+
TransportParameterId::InitialSourceConnectionId => {
358412
if let Some(ref cid) = self.initial_src_cid {
359-
w.write_var(0x0f);
413+
w.write_var(id as u64);
360414
w.write_var(cid.len() as u64);
361415
w.put_slice(cid);
362416
}
363417
}
364-
0x10 => {
418+
TransportParameterId::RetrySourceConnectionId => {
365419
if let Some(ref cid) = self.retry_src_cid {
366-
w.write_var(0x10);
420+
w.write_var(id as u64);
367421
w.write_var(cid.len() as u64);
368422
w.put_slice(cid);
369423
}
370424
}
371-
0x2ab2 => {
425+
TransportParameterId::GreaseQuicBit => {
372426
if self.grease_quic_bit {
373-
w.write_var(0x2ab2);
427+
w.write_var(id as u64);
374428
w.write_var(0);
375429
}
376430
}
377-
0xff04de1b => {
431+
TransportParameterId::MinAckDelayDraft07 => {
378432
if let Some(x) = self.min_ack_delay {
379-
w.write_var(0xff04de1b);
433+
w.write_var(id as u64);
380434
w.write_var(x.size() as u64);
381435
w.write(x);
382436
}
383437
}
384438
id => {
385439
macro_rules! write_params {
386-
{$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {
440+
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
387441
match id {
388-
$($code => {
442+
$(TransportParameterId::$id => {
389443
if self.$name.0 != $default {
390-
w.write_var($code);
444+
w.write_var(id as u64);
391445
w.write(VarInt::try_from(self.$name.size()).unwrap());
392446
w.write(self.$name);
393447
}
394448
})*,
395449
_ => {
396-
unreachable!("Missing implementation of write for transport parameter with code {id:X}");
450+
unimplemented!("Missing implementation of write for transport parameter with code {id:?}");
397451
}
398452
}
399453
}
@@ -411,7 +465,7 @@ impl TransportParameters {
411465

412466
// State to check for duplicate transport parameters.
413467
macro_rules! param_state {
414-
{$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {{
468+
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{
415469
struct ParamState {
416470
$($name: bool,)*
417471
}
@@ -432,45 +486,53 @@ impl TransportParameters {
432486
let len = len as usize;
433487

434488
match id {
435-
0x00 => decode_cid(len, &mut params.original_dst_cid, r)?,
436-
0x02 => {
489+
id if id == TransportParameterId::OriginalDestinationConnectionId as u64 => {
490+
decode_cid(len, &mut params.original_dst_cid, r)?
491+
}
492+
id if id == TransportParameterId::StatelessResetToken as u64 => {
437493
if len != 16 || params.stateless_reset_token.is_some() {
438494
return Err(Error::Malformed);
439495
}
440496
let mut tok = [0; RESET_TOKEN_SIZE];
441497
r.copy_to_slice(&mut tok);
442498
params.stateless_reset_token = Some(tok.into());
443499
}
444-
0x0c => {
500+
id if id == TransportParameterId::DisableActiveMigration as u64 => {
445501
if len != 0 || params.disable_active_migration {
446502
return Err(Error::Malformed);
447503
}
448504
params.disable_active_migration = true;
449505
}
450-
0x0d => {
506+
id if id == TransportParameterId::PreferredAddress as u64 => {
451507
if params.preferred_address.is_some() {
452508
return Err(Error::Malformed);
453509
}
454510
params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
455511
}
456-
0x0f => decode_cid(len, &mut params.initial_src_cid, r)?,
457-
0x10 => decode_cid(len, &mut params.retry_src_cid, r)?,
458-
0x20 => {
512+
id if id == TransportParameterId::InitialSourceConnectionId as u64 => {
513+
decode_cid(len, &mut params.initial_src_cid, r)?
514+
}
515+
id if id == TransportParameterId::RetrySourceConnectionId as u64 => {
516+
decode_cid(len, &mut params.retry_src_cid, r)?
517+
}
518+
id if id == TransportParameterId::MaxDatagramFrameSize as u64 => {
459519
if len > 8 || params.max_datagram_frame_size.is_some() {
460520
return Err(Error::Malformed);
461521
}
462522
params.max_datagram_frame_size = Some(r.get().unwrap());
463523
}
464-
0x2ab2 => match len {
524+
id if id == TransportParameterId::GreaseQuicBit as u64 => match len {
465525
0 => params.grease_quic_bit = true,
466526
_ => return Err(Error::Malformed),
467527
},
468-
0xff04de1b => params.min_ack_delay = Some(r.get().unwrap()),
528+
id if id == TransportParameterId::MinAckDelayDraft07 as u64 => {
529+
params.min_ack_delay = Some(r.get().unwrap())
530+
}
469531
_ => {
470532
macro_rules! parse {
471-
{$($(#[$doc:meta])* $name:ident ($code:expr) = $default:expr,)*} => {
533+
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
472534
match id {
473-
$($code => {
535+
$(id if TransportParameterId::$id as u64 == id => {
474536
let value = r.get::<VarInt>()?;
475537
if len != value.size() || got.$name { return Err(Error::Malformed); }
476538
params.$name = value.into();

0 commit comments

Comments
 (0)