@@ -12,7 +12,7 @@ use std::{
12
12
} ;
13
13
14
14
use bytes:: { Buf , BufMut } ;
15
- use rand:: { Rng as _, RngCore } ;
15
+ use rand:: { seq :: SliceRandom as _ , Rng as _, RngCore } ;
16
16
use thiserror:: Error ;
17
17
18
18
use crate :: {
@@ -104,6 +104,12 @@ macro_rules! make_struct {
104
104
/// of transport parameter extensions.
105
105
/// When present, it is included during serialization but ignored during deserialization.
106
106
pub ( crate ) grease_transport_parameter: Option <ReservedTransportParameter >,
107
+
108
+ /// Defines the order in which transport parameters are serialized.
109
+ ///
110
+ /// This field is initialized only for outgoing `TransportParameters` instances and
111
+ /// is set to `None` for `TransportParameters` received from a peer.
112
+ pub ( crate ) write_order: Option <[ u8 ; TransportParameterId :: SUPPORTED . len( ) ] >,
107
113
}
108
114
109
115
// We deliberately don't implement the `Default` trait, since that would be public, and
@@ -126,6 +132,7 @@ macro_rules! make_struct {
126
132
stateless_reset_token: None ,
127
133
preferred_address: None ,
128
134
grease_transport_parameter: None ,
135
+ write_order: None ,
129
136
}
130
137
}
131
138
}
@@ -168,6 +175,11 @@ impl TransportParameters {
168
175
VarInt :: from_u64 ( u64:: try_from ( TIMER_GRANULARITY . as_micros ( ) ) . unwrap ( ) ) . unwrap ( ) ,
169
176
) ,
170
177
grease_transport_parameter : Some ( ReservedTransportParameter :: random ( rng) ) ,
178
+ write_order : Some ( {
179
+ let mut order = std:: array:: from_fn ( |i| i as u8 ) ;
180
+ order. shuffle ( rng) ;
181
+ order
182
+ } ) ,
171
183
..Self :: default ( )
172
184
}
173
185
}
@@ -295,68 +307,100 @@ impl From<UnexpectedEnd> for Error {
295
307
impl TransportParameters {
296
308
/// Encode `TransportParameters` into buffer
297
309
pub fn write < W : BufMut > ( & self , w : & mut W ) {
298
- macro_rules! write_params {
299
- { $( $( #[ $doc: meta] ) * $name: ident ( $id: ident) = $default: expr, ) * } => {
300
- $(
301
- if self . $name. 0 != $default {
302
- w. write_var( TransportParameterId :: $id as u64 ) ;
303
- w. write( VarInt :: try_from( self . $name. size( ) ) . unwrap( ) ) ;
304
- w. write( self . $name) ;
310
+ for idx in self
311
+ . write_order
312
+ . as_ref ( )
313
+ . unwrap_or ( & std:: array:: from_fn ( |i| i as u8 ) )
314
+ {
315
+ let id = TransportParameterId :: SUPPORTED [ * idx as usize ] ;
316
+ match id {
317
+ TransportParameterId :: ReservedTransportParameter => {
318
+ if let Some ( param) = self . grease_transport_parameter {
319
+ param. write ( w) ;
305
320
}
306
- ) *
307
- }
308
- }
309
- apply_params ! ( write_params) ;
310
-
311
- if let Some ( param) = self . grease_transport_parameter {
312
- param. write ( w) ;
313
- }
314
-
315
- if let Some ( ref x) = self . stateless_reset_token {
316
- w. write_var ( 0x02 ) ;
317
- w. write_var ( 16 ) ;
318
- w. put_slice ( x) ;
319
- }
320
-
321
- if self . disable_active_migration {
322
- w. write_var ( 0x0c ) ;
323
- w. write_var ( 0 ) ;
324
- }
325
-
326
- if let Some ( x) = self . max_datagram_frame_size {
327
- w. write_var ( 0x20 ) ;
328
- w. write_var ( x. size ( ) as u64 ) ;
329
- w. write ( x) ;
330
- }
331
-
332
- if let Some ( ref x) = self . preferred_address {
333
- w. write_var ( 0x000d ) ;
334
- w. write_var ( x. wire_size ( ) as u64 ) ;
335
- x. write ( w) ;
336
- }
337
-
338
- for & ( tag, cid) in & [
339
- ( 0x00 , & self . original_dst_cid ) ,
340
- ( 0x0f , & self . initial_src_cid ) ,
341
- ( 0x10 , & self . retry_src_cid ) ,
342
- ] {
343
- if let Some ( ref cid) = * cid {
344
- w. write_var ( tag) ;
345
- w. write_var ( cid. len ( ) as u64 ) ;
346
- w. put_slice ( cid) ;
321
+ }
322
+ TransportParameterId :: StatelessResetToken => {
323
+ if let Some ( ref x) = self . stateless_reset_token {
324
+ w. write_var ( id as u64 ) ;
325
+ w. write_var ( 16 ) ;
326
+ w. put_slice ( x) ;
327
+ }
328
+ }
329
+ TransportParameterId :: DisableActiveMigration => {
330
+ if self . disable_active_migration {
331
+ w. write_var ( id as u64 ) ;
332
+ w. write_var ( 0 ) ;
333
+ }
334
+ }
335
+ TransportParameterId :: MaxDatagramFrameSize => {
336
+ if let Some ( x) = self . max_datagram_frame_size {
337
+ w. write_var ( id as u64 ) ;
338
+ w. write_var ( x. size ( ) as u64 ) ;
339
+ w. write ( x) ;
340
+ }
341
+ }
342
+ TransportParameterId :: PreferredAddress => {
343
+ if let Some ( ref x) = self . preferred_address {
344
+ w. write_var ( id as u64 ) ;
345
+ w. write_var ( x. wire_size ( ) as u64 ) ;
346
+ x. write ( w) ;
347
+ }
348
+ }
349
+ TransportParameterId :: OriginalDestinationConnectionId => {
350
+ if let Some ( ref cid) = self . original_dst_cid {
351
+ w. write_var ( id as u64 ) ;
352
+ w. write_var ( cid. len ( ) as u64 ) ;
353
+ w. put_slice ( cid) ;
354
+ }
355
+ }
356
+ TransportParameterId :: InitialSourceConnectionId => {
357
+ if let Some ( ref cid) = self . initial_src_cid {
358
+ w. write_var ( id as u64 ) ;
359
+ w. write_var ( cid. len ( ) as u64 ) ;
360
+ w. put_slice ( cid) ;
361
+ }
362
+ }
363
+ TransportParameterId :: RetrySourceConnectionId => {
364
+ if let Some ( ref cid) = self . retry_src_cid {
365
+ w. write_var ( id as u64 ) ;
366
+ w. write_var ( cid. len ( ) as u64 ) ;
367
+ w. put_slice ( cid) ;
368
+ }
369
+ }
370
+ TransportParameterId :: GreaseQuicBit => {
371
+ if self . grease_quic_bit {
372
+ w. write_var ( id as u64 ) ;
373
+ w. write_var ( 0 ) ;
374
+ }
375
+ }
376
+ TransportParameterId :: MinAckDelayDraft07 => {
377
+ if let Some ( x) = self . min_ack_delay {
378
+ w. write_var ( id as u64 ) ;
379
+ w. write_var ( x. size ( ) as u64 ) ;
380
+ w. write ( x) ;
381
+ }
382
+ }
383
+ id => {
384
+ macro_rules! write_params {
385
+ { $( $( #[ $doc: meta] ) * $name: ident ( $id: ident) = $default: expr, ) * } => {
386
+ match id {
387
+ $( TransportParameterId :: $id => {
388
+ if self . $name. 0 != $default {
389
+ w. write_var( id as u64 ) ;
390
+ w. write( VarInt :: try_from( self . $name. size( ) ) . unwrap( ) ) ;
391
+ w. write( self . $name) ;
392
+ }
393
+ } ) * ,
394
+ _ => {
395
+ unimplemented!( "Missing implementation of write for transport parameter with code {id:?}" ) ;
396
+ }
397
+ }
398
+ }
399
+ }
400
+ apply_params ! ( write_params) ;
401
+ }
347
402
}
348
403
}
349
-
350
- if self . grease_quic_bit {
351
- w. write_var ( 0x2ab2 ) ;
352
- w. write_var ( 0 ) ;
353
- }
354
-
355
- if let Some ( x) = self . min_ack_delay {
356
- w. write_var ( 0xff04de1b ) ;
357
- w. write_var ( x. size ( ) as u64 ) ;
358
- w. write ( x) ;
359
- }
360
404
}
361
405
362
406
/// Decode `TransportParameters` from buffer
@@ -598,6 +642,33 @@ pub(crate) enum TransportParameterId {
598
642
MinAckDelayDraft07 = 0xFF04DE1B ,
599
643
}
600
644
645
+ impl TransportParameterId {
646
+ /// Array with all supported transport parameter IDs
647
+ const SUPPORTED : [ Self ; 21 ] = [
648
+ Self :: MaxIdleTimeout ,
649
+ Self :: MaxUdpPayloadSize ,
650
+ Self :: InitialMaxData ,
651
+ Self :: InitialMaxStreamDataBidiLocal ,
652
+ Self :: InitialMaxStreamDataBidiRemote ,
653
+ Self :: InitialMaxStreamDataUni ,
654
+ Self :: InitialMaxStreamsBidi ,
655
+ Self :: InitialMaxStreamsUni ,
656
+ Self :: AckDelayExponent ,
657
+ Self :: MaxAckDelay ,
658
+ Self :: ActiveConnectionIdLimit ,
659
+ Self :: ReservedTransportParameter ,
660
+ Self :: StatelessResetToken ,
661
+ Self :: DisableActiveMigration ,
662
+ Self :: MaxDatagramFrameSize ,
663
+ Self :: PreferredAddress ,
664
+ Self :: OriginalDestinationConnectionId ,
665
+ Self :: InitialSourceConnectionId ,
666
+ Self :: RetrySourceConnectionId ,
667
+ Self :: GreaseQuicBit ,
668
+ Self :: MinAckDelayDraft07 ,
669
+ ] ;
670
+ }
671
+
601
672
impl std:: cmp:: PartialEq < u64 > for TransportParameterId {
602
673
fn eq ( & self , other : & u64 ) -> bool {
603
674
* other == ( * self as u64 )
0 commit comments