in quic/s2n-quic-transport/src/recovery/manager/tests.rs [2755:2891]
fn update_pto_timer() {
let space = PacketNumberSpace::ApplicationData;
let mut manager = ServerManager::new(space);
let now = time::now() + Duration::from_secs(10);
let is_handshake_confirmed = true;
let mut path_manager = helper_generate_path_manager(Duration::from_millis(10));
let ecn = ExplicitCongestionNotification::default();
let mut context = MockContext::new(&mut path_manager);
let mut publisher = Publisher::snapshot();
context.path_mut().rtt_estimator.update_rtt(
Duration::from_millis(0),
Duration::from_millis(500),
now,
true,
space,
);
context.path_mut().rtt_estimator.update_rtt(
Duration::from_millis(0),
Duration::from_millis(1000),
now,
true,
space,
);
// The path will be at the anti-amplification limit
let amplification_outcome = context.path_mut().on_bytes_received(1200);
assert!(amplification_outcome.is_active_path_unblocked());
context.path_mut().on_bytes_transmitted((1200 * 3) + 1);
// Arm the PTO so we can verify it is cancelled
manager.pto.update(now, Duration::from_secs(10));
manager.pto_update_pending = true;
manager.update_pto_timer(context.path(), now, is_handshake_confirmed);
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.2.1
//= type=test
//# If no additional data can be sent, the server's PTO timer MUST NOT be
//# armed until datagrams have been received from the client, because
//# packets sent on PTO count against the anti-amplification limit.
assert!(!manager.pto.is_armed());
assert!(!manager.pto_update_pending);
// Arm the PTO so we can verify it is cancelled
manager.pto.update(now, Duration::from_secs(10));
manager.pto_update_pending = true;
// Validate the path so it is not at the anti-amplification limit
//
// simulate receiving a handshake packet to force path validation
context.path_mut().on_handshake_packet();
context.path_mut().on_peer_validated();
manager.update_pto_timer(context.path(), now, is_handshake_confirmed);
// Since the path is peer validated and sent packets is empty, PTO is cancelled
assert!(!manager.pto.is_armed());
assert!(!manager.pto_update_pending);
// Reset the path back to not peer validated
let path_id = unsafe { path::Id::new(0) };
let mut rtt_estimator = RttEstimator::default();
rtt_estimator.on_max_ack_delay(Duration::from_millis(10).try_into().unwrap());
context.path_manager[path_id] = Path::new(
Default::default(),
connection::PeerId::TEST_ID,
connection::LocalId::TEST_ID,
rtt_estimator,
MockCongestionController::default(),
false,
mtu::Config::default(),
ANTI_AMPLIFICATION_MULTIPLIER,
);
context.path_manager.activate_path_for_test(path_id);
// simulate receiving a handshake packet to force path validation
context.path_mut().on_handshake_packet();
context.path_mut().pto_backoff = 2;
manager.pto_update_pending = true;
let is_handshake_confirmed = false;
manager.update_pto_timer(context.path(), now, is_handshake_confirmed);
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.1
//= type=test
//# An endpoint MUST NOT set its PTO timer for the Application Data
//# packet number space until the handshake is confirmed.
assert!(!manager.pto.is_armed());
assert!(!manager.pto_update_pending);
// Set is handshake confirmed back to true
let is_handshake_confirmed = true;
manager.pto_update_pending = true;
manager.update_pto_timer(context.path(), now, is_handshake_confirmed);
// Now the PTO is armed
assert!(manager.pto.is_armed());
assert!(!manager.pto_update_pending);
// Send a packet to validate behavior when sent_packets is not empty
manager.on_packet_sent(
space.new_packet_number(VarInt::from_u8(1)),
transmission::Outcome {
ack_elicitation: AckElicitation::Eliciting,
is_congestion_controlled: true,
bytes_sent: 1,
bytes_progressed: 0,
},
now,
ecn,
transmission::Mode::Normal,
None,
&mut context,
&mut publisher,
);
let expected_pto_base_timestamp = now - Duration::from_secs(5);
manager.time_of_last_ack_eliciting_packet = Some(expected_pto_base_timestamp);
// This will update the smoother_rtt to 2000, and rtt_var to 1000
context.path_mut().rtt_estimator.update_rtt(
Duration::from_millis(0),
Duration::from_millis(2000),
now,
true,
space,
);
manager.pto_update_pending = true;
manager.update_pto_timer(context.path(), now, is_handshake_confirmed);
//= https://www.rfc-editor.org/rfc/rfc9002#section-6.2.1
//# When an ack-eliciting packet is transmitted, the sender schedules a
//# timer for the PTO period as follows:
//#
//# PTO = smoothed_rtt + max(4*rttvar, kGranularity) + max_ack_delay
// Including the pto backoff (2) =:
// PTO = (2000 + max(4*1000, 1) + 10) * 2 = 12020
assert!(manager.pto.is_armed());
assert_eq!(
manager.pto.next_expiration().unwrap(),
expected_pto_base_timestamp + Duration::from_millis(12020)
);
assert!(!manager.pto_update_pending);
}