@@ -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 :: {
@@ -105,6 +105,31 @@ macro_rules! apply_params {
105
105
} ;
106
106
}
107
107
108
+ /// Array with all supported transport parameter IDs
109
+ const SUPPORTED_TRANSPORT_PARAMETERS : [ TransportParameterId ; 21 ] = [
110
+ TransportParameterId :: MaxIdleTimeout ,
111
+ TransportParameterId :: MaxUdpPayloadSize ,
112
+ TransportParameterId :: InitialMaxData ,
113
+ TransportParameterId :: InitialMaxStreamDataBidiLocal ,
114
+ TransportParameterId :: InitialMaxStreamDataBidiRemote ,
115
+ TransportParameterId :: InitialMaxStreamDataUni ,
116
+ TransportParameterId :: InitialMaxStreamsBidi ,
117
+ TransportParameterId :: InitialMaxStreamsUni ,
118
+ TransportParameterId :: AckDelayExponent ,
119
+ TransportParameterId :: MaxAckDelay ,
120
+ TransportParameterId :: ActiveConnectionIdLimit ,
121
+ TransportParameterId :: ReservedTransportParameter ,
122
+ TransportParameterId :: StatelessResetToken ,
123
+ TransportParameterId :: DisableActiveMigration ,
124
+ TransportParameterId :: MaxDatagramFrameSize ,
125
+ TransportParameterId :: PreferredAddress ,
126
+ TransportParameterId :: OriginalDestinationConnectionId ,
127
+ TransportParameterId :: InitialSourceConnectionId ,
128
+ TransportParameterId :: RetrySourceConnectionId ,
129
+ TransportParameterId :: GreaseQuicBit ,
130
+ TransportParameterId :: MinAckDelayDraft07 ,
131
+ ] ;
132
+
108
133
macro_rules! make_struct {
109
134
{ $( $( #[ $doc: meta] ) * $name: ident ( $id: ident) = $default: expr, ) * } => {
110
135
/// Transport parameters used to negotiate connection-level preferences between peers
@@ -145,6 +170,9 @@ macro_rules! make_struct {
145
170
/// of transport parameter extensions.
146
171
/// When present, it is included during serialization but ignored during deserialization.
147
172
pub ( crate ) grease_transport_parameter: Option <ReservedTransportParameter >,
173
+
174
+ /// The order in which transport parameters are serialized
175
+ pub ( crate ) write_order: Option <[ u8 ; SUPPORTED_TRANSPORT_PARAMETERS . len( ) ] >,
148
176
}
149
177
150
178
// We deliberately don't implement the `Default` trait, since that would be public, and
@@ -167,6 +195,7 @@ macro_rules! make_struct {
167
195
stateless_reset_token: None ,
168
196
preferred_address: None ,
169
197
grease_transport_parameter: None ,
198
+ write_order: None ,
170
199
}
171
200
}
172
201
}
@@ -209,6 +238,11 @@ impl TransportParameters {
209
238
VarInt :: from_u64 ( u64:: try_from ( TIMER_GRANULARITY . as_micros ( ) ) . unwrap ( ) ) . unwrap ( ) ,
210
239
) ,
211
240
grease_transport_parameter : Some ( ReservedTransportParameter :: random ( rng) ) ,
241
+ write_order : Some ( {
242
+ let mut order = std:: array:: from_fn ( |i| i as u8 ) ;
243
+ order. shuffle ( rng) ;
244
+ order
245
+ } ) ,
212
246
..Self :: default ( )
213
247
}
214
248
}
@@ -336,68 +370,100 @@ impl From<UnexpectedEnd> for Error {
336
370
impl TransportParameters {
337
371
/// Encode `TransportParameters` into buffer
338
372
pub fn write < W : BufMut > ( & self , w : & mut W ) {
339
- macro_rules! write_params {
340
- { $( $( #[ $doc: meta] ) * $name: ident ( $id: ident) = $default: expr, ) * } => {
341
- $(
342
- if self . $name. 0 != $default {
343
- w. write_var( TransportParameterId :: $id as u64 ) ;
344
- w. write( VarInt :: try_from( self . $name. size( ) ) . unwrap( ) ) ;
345
- w. write( self . $name) ;
373
+ for idx in self
374
+ . write_order
375
+ . as_ref ( )
376
+ . unwrap_or ( & std:: array:: from_fn ( |i| i as u8 ) )
377
+ {
378
+ let id = SUPPORTED_TRANSPORT_PARAMETERS [ * idx as usize ] ;
379
+ match id {
380
+ TransportParameterId :: ReservedTransportParameter => {
381
+ if let Some ( param) = self . grease_transport_parameter {
382
+ param. write ( w) ;
346
383
}
347
- ) *
348
- }
349
- }
350
- apply_params ! ( write_params) ;
351
-
352
- if let Some ( param) = self . grease_transport_parameter {
353
- param. write ( w) ;
354
- }
355
-
356
- if let Some ( ref x) = self . stateless_reset_token {
357
- w. write_var ( 0x02 ) ;
358
- w. write_var ( 16 ) ;
359
- w. put_slice ( x) ;
360
- }
361
-
362
- if self . disable_active_migration {
363
- w. write_var ( 0x0c ) ;
364
- w. write_var ( 0 ) ;
365
- }
366
-
367
- if let Some ( x) = self . max_datagram_frame_size {
368
- w. write_var ( 0x20 ) ;
369
- w. write_var ( x. size ( ) as u64 ) ;
370
- w. write ( x) ;
371
- }
372
-
373
- if let Some ( ref x) = self . preferred_address {
374
- w. write_var ( 0x000d ) ;
375
- w. write_var ( x. wire_size ( ) as u64 ) ;
376
- x. write ( w) ;
377
- }
378
-
379
- for & ( tag, cid) in & [
380
- ( 0x00 , & self . original_dst_cid ) ,
381
- ( 0x0f , & self . initial_src_cid ) ,
382
- ( 0x10 , & self . retry_src_cid ) ,
383
- ] {
384
- if let Some ( ref cid) = * cid {
385
- w. write_var ( tag) ;
386
- w. write_var ( cid. len ( ) as u64 ) ;
387
- w. put_slice ( cid) ;
384
+ }
385
+ TransportParameterId :: StatelessResetToken => {
386
+ if let Some ( ref x) = self . stateless_reset_token {
387
+ w. write_var ( id as u64 ) ;
388
+ w. write_var ( 16 ) ;
389
+ w. put_slice ( x) ;
390
+ }
391
+ }
392
+ TransportParameterId :: DisableActiveMigration => {
393
+ if self . disable_active_migration {
394
+ w. write_var ( id as u64 ) ;
395
+ w. write_var ( 0 ) ;
396
+ }
397
+ }
398
+ TransportParameterId :: MaxDatagramFrameSize => {
399
+ if let Some ( x) = self . max_datagram_frame_size {
400
+ w. write_var ( id as u64 ) ;
401
+ w. write_var ( x. size ( ) as u64 ) ;
402
+ w. write ( x) ;
403
+ }
404
+ }
405
+ TransportParameterId :: PreferredAddress => {
406
+ if let Some ( ref x) = self . preferred_address {
407
+ w. write_var ( id as u64 ) ;
408
+ w. write_var ( x. wire_size ( ) as u64 ) ;
409
+ x. write ( w) ;
410
+ }
411
+ }
412
+ TransportParameterId :: OriginalDestinationConnectionId => {
413
+ if let Some ( ref cid) = self . original_dst_cid {
414
+ w. write_var ( id as u64 ) ;
415
+ w. write_var ( cid. len ( ) as u64 ) ;
416
+ w. put_slice ( cid) ;
417
+ }
418
+ }
419
+ TransportParameterId :: InitialSourceConnectionId => {
420
+ if let Some ( ref cid) = self . initial_src_cid {
421
+ w. write_var ( id as u64 ) ;
422
+ w. write_var ( cid. len ( ) as u64 ) ;
423
+ w. put_slice ( cid) ;
424
+ }
425
+ }
426
+ TransportParameterId :: RetrySourceConnectionId => {
427
+ if let Some ( ref cid) = self . retry_src_cid {
428
+ w. write_var ( id as u64 ) ;
429
+ w. write_var ( cid. len ( ) as u64 ) ;
430
+ w. put_slice ( cid) ;
431
+ }
432
+ }
433
+ TransportParameterId :: GreaseQuicBit => {
434
+ if self . grease_quic_bit {
435
+ w. write_var ( id as u64 ) ;
436
+ w. write_var ( 0 ) ;
437
+ }
438
+ }
439
+ TransportParameterId :: MinAckDelayDraft07 => {
440
+ if let Some ( x) = self . min_ack_delay {
441
+ w. write_var ( id as u64 ) ;
442
+ w. write_var ( x. size ( ) as u64 ) ;
443
+ w. write ( x) ;
444
+ }
445
+ }
446
+ id => {
447
+ macro_rules! write_params {
448
+ { $( $( #[ $doc: meta] ) * $name: ident ( $id: ident) = $default: expr, ) * } => {
449
+ match id {
450
+ $( TransportParameterId :: $id => {
451
+ if self . $name. 0 != $default {
452
+ w. write_var( id as u64 ) ;
453
+ w. write( VarInt :: try_from( self . $name. size( ) ) . unwrap( ) ) ;
454
+ w. write( self . $name) ;
455
+ }
456
+ } ) * ,
457
+ _ => {
458
+ unimplemented!( "Missing implementation of write for transport parameter with code {id:?}" ) ;
459
+ }
460
+ }
461
+ }
462
+ }
463
+ apply_params ! ( write_params) ;
464
+ }
388
465
}
389
466
}
390
-
391
- if self . grease_quic_bit {
392
- w. write_var ( 0x2ab2 ) ;
393
- w. write_var ( 0 ) ;
394
- }
395
-
396
- if let Some ( x) = self . min_ack_delay {
397
- w. write_var ( 0xff04de1b ) ;
398
- w. write_var ( x. size ( ) as u64 ) ;
399
- w. write ( x) ;
400
- }
401
467
}
402
468
403
469
/// Decode `TransportParameters` from buffer
0 commit comments