Skip to content

Commit a6cea3a

Browse files
authored
Do PTO calculations correct (#95)
- PTO is computed for the right path - crypto keys update uses 3 * max PTO of all paths - draining state uses 3 * max PTO of all paths
2 parents 8a6d695 + 07cc577 commit a6cea3a

File tree

1 file changed

+36
-11
lines changed
  • quinn-proto/src/connection

1 file changed

+36
-11
lines changed

quinn-proto/src/connection/mod.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,8 +2016,10 @@ impl Connection {
20162016
.expect("update not acknowledged yet")
20172017
.1
20182018
};
2019+
2020+
// QUIC-MULTIPATH § 2.5 Key Phase Update Process: use largest PTO off all paths.
20192021
self.timers
2020-
.set(Timer::KeyDiscard, start + self.pto(space) * 3);
2022+
.set(Timer::KeyDiscard, start + self.pto_max_path(space) * 3);
20212023
}
20222024

20232025
/// Handle a [`Timer::LossDetection`] timeout.
@@ -2103,7 +2105,7 @@ impl Connection {
21032105
// lost packet, including the edges, are marked lost. PTO computation must always
21042106
// include max ACK delay, i.e. operate as if in Data space (see RFC9001 §7.6.1).
21052107
let congestion_period =
2106-
self.pto(SpaceId::Data) * self.config.persistent_congestion_threshold;
2108+
self.pto(SpaceId::Data, path_id) * self.config.persistent_congestion_threshold;
21072109
let mut persistent_congestion_start: Option<Instant> = None;
21082110
let mut prev_packet = None;
21092111
let mut in_persistent_congestion = false;
@@ -2368,15 +2370,31 @@ impl Connection {
23682370
}
23692371
}
23702372

2373+
/// The maximum probe timeout across all paths
2374+
///
2375+
/// See [`Connection::pto`]
2376+
fn pto_max_path(&self, space: SpaceId) -> Duration {
2377+
match space {
2378+
SpaceId::Initial | SpaceId::Handshake => self.pto(space, PathId::ZERO),
2379+
SpaceId::Data => self
2380+
.paths
2381+
.keys()
2382+
.map(|path_id| self.pto(space, *path_id))
2383+
.max()
2384+
.expect("there should be one at least path"),
2385+
}
2386+
}
2387+
23712388
/// Probe Timeout
2372-
// TODO(flub): This needs a PathId parameter
2373-
fn pto(&self, space: SpaceId) -> Duration {
2389+
///
2390+
/// The PTO is logically the time in which you'd expect to receive an acknowledgement
2391+
/// for a packet. So approximately RTT + max_ack_delay.
2392+
fn pto(&self, space: SpaceId, path_id: PathId) -> Duration {
23742393
let max_ack_delay = match space {
23752394
SpaceId::Initial | SpaceId::Handshake => Duration::ZERO,
23762395
SpaceId::Data => self.ack_frequency.max_ack_delay_for_pto(),
23772396
};
2378-
// TODO(@divma): fix
2379-
self.path_data(PathId(0)).rtt.pto_base() + max_ack_delay
2397+
self.path_data(path_id).rtt.pto_base() + max_ack_delay
23802398
}
23812399

23822400
fn on_packet_authenticated(
@@ -2429,6 +2447,8 @@ impl Connection {
24292447
}
24302448
}
24312449

2450+
// TODO(flub): figure out if this should take a PathId. We could use an idle timeout on
2451+
// each path. We will need to figure out.
24322452
fn reset_idle_timeout(&mut self, now: Instant, space: SpaceId) {
24332453
let timeout = match self.idle_timeout {
24342454
None => return,
@@ -2438,7 +2458,8 @@ impl Connection {
24382458
self.timers.stop(Timer::Idle);
24392459
return;
24402460
}
2441-
let dt = cmp::max(timeout, 3 * self.pto(space));
2461+
// TODO(flub): Wrong PathId, see comment above.
2462+
let dt = cmp::max(timeout, 3 * self.pto(space, PathId::ZERO));
24422463
self.timers.set(Timer::Idle, now + dt);
24432464
}
24442465

@@ -3755,7 +3776,7 @@ impl Connection {
37553776
// Reset rtt/congestion state for new path unless it looks like a NAT rebinding.
37563777
// Note that the congestion window will not grow until validation terminates. Helps mitigate
37573778
// amplification attacks performed by spoofing source addresses.
3758-
let prev_pto = self.pto(SpaceId::Data);
3779+
let prev_pto = self.pto(SpaceId::Data, path_id);
37593780
let known_path = self.paths.get_mut(&path_id).expect("known path");
37603781
let path = &mut known_path.data;
37613782
let mut new_path = if remote.is_ipv4() && remote.ip() == path.remote.ip() {
@@ -3794,7 +3815,7 @@ impl Connection {
37943815

37953816
self.timers.set(
37963817
Timer::PathValidation(path_id),
3797-
now + 3 * cmp::max(self.pto(SpaceId::Data), prev_pto),
3818+
now + 3 * cmp::max(self.pto(SpaceId::Data, path_id), prev_pto),
37983819
);
37993820
}
38003821

@@ -4388,8 +4409,12 @@ impl Connection {
43884409
}
43894410

43904411
fn set_close_timer(&mut self, now: Instant) {
4391-
self.timers
4392-
.set(Timer::Close, now + 3 * self.pto(self.highest_space));
4412+
// QUIC-MULTIPATH § 2.6 Connection Closure: draining for 3*PTO with PTO the max of
4413+
// the PTO for all paths.
4414+
self.timers.set(
4415+
Timer::Close,
4416+
now + 3 * self.pto_max_path(self.highest_space),
4417+
);
43934418
}
43944419

43954420
/// Handle transport parameters received from the peer

0 commit comments

Comments
 (0)