@@ -148,7 +148,7 @@ pub struct Connection {
148
148
/// This needs to be ordered because [`Connection::poll_transmit`] needs to
149
149
/// deterministically select the next PathId to send on.
150
150
///
151
- /// TODO(flub): well does it really? But deterministic is nice for now.
151
+ // TODO(flub): well does it really? But deterministic is nice for now.
152
152
paths : BTreeMap < PathId , PathState > ,
153
153
/// Whether MTU detection is supported in this environment
154
154
allow_mtud : bool ,
@@ -244,6 +244,20 @@ pub struct Connection {
244
244
stats : ConnectionStats ,
245
245
/// QUIC version used for the connection.
246
246
version : u32 ,
247
+
248
+ /// Local maximum [`PathId`] to be used.
249
+ ///
250
+ /// This is initially set to [`TransportConfig::initial_max_path_id`] when multipath is enabled, or to
251
+ /// [`PathId::ZERO`] otherwise.
252
+ // TODO(@divma): we probably need an API to imcrease upon the original value
253
+ local_max_path_id : PathId ,
254
+
255
+ /// Remote's maximum [`PathId`] to be used.
256
+ ///
257
+ /// This is initially set to the peer's [`TransportParameters::initial_max_path_id`] when
258
+ /// multipath is enabled, or to [`PathId::ZERO`] otherwise. A peer may increase this limit by
259
+ /// sending [`Frame::MaxPathId`] frames.
260
+ remote_max_path_id : PathId ,
247
261
}
248
262
249
263
struct PathState {
@@ -377,6 +391,9 @@ impl Connection {
377
391
rng,
378
392
stats : ConnectionStats :: default ( ) ,
379
393
version,
394
+ // peer params are not yet known, so multipath is not enabled
395
+ local_max_path_id : PathId :: ZERO ,
396
+ remote_max_path_id : PathId :: ZERO ,
380
397
} ;
381
398
if path_validated {
382
399
this. on_path_validated ( PathId ( 0 ) ) ;
@@ -2894,9 +2911,7 @@ impl Connection {
2894
2911
2895
2912
// Multipath can only be enabled after the state has reached Established.
2896
2913
// So this can not happen any earlier.
2897
- if self . is_multipath_enabled ( ) {
2898
- self . issue_first_path_cids ( now) ;
2899
- }
2914
+ self . issue_first_path_cids ( now) ;
2900
2915
Ok ( ( ) )
2901
2916
}
2902
2917
Header :: Initial ( InitialHeader {
@@ -3396,8 +3411,15 @@ impl Connection {
3396
3411
Frame :: PathAvailable ( _) => {
3397
3412
// TODO(@divma): do stuff
3398
3413
}
3399
- Frame :: MaxPathId ( _) => {
3400
- // TODO(@divma): do stuff
3414
+ Frame :: MaxPathId ( path_id) => {
3415
+ if self . is_multipath_enabled ( ) {
3416
+ // frames that do not increase the path id are ignored
3417
+ self . remote_max_path_id = self . remote_max_path_id . max ( path_id) ;
3418
+ } else {
3419
+ return Err ( TransportError :: PROTOCOL_VIOLATION (
3420
+ "received MAX_PATH_ID frame when not multipath was not negotiated" ,
3421
+ ) ) ;
3422
+ }
3401
3423
}
3402
3424
Frame :: PathsBlocked ( _) => {
3403
3425
// TODO(@divma): do stuff
@@ -3566,14 +3588,14 @@ impl Connection {
3566
3588
. push_back ( EndpointEventInner :: NeedIdentifiers ( PathId ( 0 ) , now, n) ) ;
3567
3589
}
3568
3590
3569
- /// Issues an initial set of CIDs to the peer for PathId > 0
3591
+ /// Issues an initial set of CIDs to the peer for PathId > 0; CIDs for [`PathId::ZERO`] are
3592
+ /// issued earlier in the connection process.
3570
3593
// TODO(flub): Whenever we close paths we need to issue new CIDs as well. Once we do
3571
3594
// that we probably want to re-use this function but with a max_path_id parameter or
3572
3595
// something.
3573
3596
fn issue_first_path_cids ( & mut self , now : Instant ) {
3574
- debug_assert ! ( self . is_multipath_enabled( ) ) ;
3575
- if let Some ( max_path_id) = self . config . initial_max_path_id {
3576
- for n in 1 ..( max_path_id + 1 ) {
3597
+ if let Some ( PathId ( max_path_id) ) = self . max_path_id ( ) {
3598
+ for n in 1 ..=max_path_id {
3577
3599
self . endpoint_events
3578
3600
. push_back ( EndpointEventInner :: NeedIdentifiers (
3579
3601
PathId ( n) ,
@@ -4072,6 +4094,15 @@ impl Connection {
4072
4094
self . set_reset_token ( remote, info. stateless_reset_token ) ;
4073
4095
}
4074
4096
self . ack_frequency . peer_max_ack_delay = get_max_ack_delay ( & params) ;
4097
+
4098
+ if let ( Some ( local_max_path_id) , Some ( remote_max_path_id) ) =
4099
+ ( self . config . initial_max_path_id , params. initial_max_path_id )
4100
+ {
4101
+ // multipath is enabled, register the local and remote maximums
4102
+ self . local_max_path_id = local_max_path_id;
4103
+ self . remote_max_path_id = remote_max_path_id;
4104
+ }
4105
+
4075
4106
self . peer_params = params;
4076
4107
let peer_max_udp_payload_size =
4077
4108
u16:: try_from ( self . peer_params . max_udp_payload_size . into_inner ( ) ) . unwrap_or ( u16:: MAX ) ;
@@ -4411,6 +4442,18 @@ impl Connection {
4411
4442
new_tokens. push ( remote_addr) ;
4412
4443
}
4413
4444
}
4445
+
4446
+ /// Returns the maximum [`PathId`] to be used in this connection.
4447
+ ///
4448
+ /// This is calculated as minimum between the local and remote's maximums when multipath is
4449
+ /// enabled, or `None` when disabled.
4450
+ fn max_path_id ( & self ) -> Option < PathId > {
4451
+ if self . is_multipath_enabled ( ) {
4452
+ Some ( self . remote_max_path_id . min ( self . local_max_path_id ) )
4453
+ } else {
4454
+ None
4455
+ }
4456
+ }
4414
4457
}
4415
4458
4416
4459
impl fmt:: Debug for Connection {
0 commit comments