From 20e628627752cee2511ee9179e0217a1a2a07fd0 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Fri, 8 May 2026 10:47:14 +0700 Subject: [PATCH] fix(client): report counter overflows clearly --- crates/irtt-client/src/client.rs | 22 +++++--- .../src/client/tests/probes_replies.rs | 50 ++++++++++++++++++- crates/irtt-client/src/error.rs | 2 + 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/crates/irtt-client/src/client.rs b/crates/irtt-client/src/client.rs index f28428a..54bdbc1 100644 --- a/crates/irtt-client/src/client.rs +++ b/crates/irtt-client/src/client.rs @@ -241,14 +241,20 @@ impl Client { session.pending.insert(pending)?; session.next_wire_seq = session.next_wire_seq.wrapping_add(1); - session.next_logical_seq = session - .next_logical_seq - .checked_add(1) - .ok_or(ClientError::DurationOverflow)?; - session.packets_sent = session - .packets_sent - .checked_add(1) - .ok_or(ClientError::DurationOverflow)?; + session.next_logical_seq = + session + .next_logical_seq + .checked_add(1) + .ok_or(ClientError::CounterOverflow { + counter: "next_logical_seq", + })?; + session.packets_sent = + session + .packets_sent + .checked_add(1) + .ok_or(ClientError::CounterOverflow { + counter: "packets_sent", + })?; let negotiated = self .negotiated diff --git a/crates/irtt-client/src/client/tests/probes_replies.rs b/crates/irtt-client/src/client/tests/probes_replies.rs index 239a47a..bfa7232 100644 --- a/crates/irtt-client/src/client/tests/probes_replies.rs +++ b/crates/irtt-client/src/client/tests/probes_replies.rs @@ -302,7 +302,7 @@ fn send_probe_reports_schedule_overflow() { }; let mut client = Client::connect(config).unwrap(); assert_open_started(client.open(ClientTimestamp::now()).unwrap()); - client.session.as_mut().unwrap().packets_sent = u64::MAX; + client.session.as_mut().unwrap().packets_sent = u64::MAX - 1; assert!(matches!( client.send_probe(), @@ -311,6 +311,54 @@ fn send_probe_reports_schedule_overflow() { server.join(); } +#[test] +fn send_probe_reports_logical_sequence_counter_overflow() { + let params = default_params(); + let server = silent_open_server(params); + let config = ClientConfig { + socket_config: crate::SocketConfig { + recv_timeout: Some(Duration::from_millis(200)), + ..Default::default() + }, + ..default_test_config(server.addr) + }; + let mut client = Client::connect(config).unwrap(); + assert_open_started(client.open(ClientTimestamp::now()).unwrap()); + client.session.as_mut().unwrap().next_logical_seq = u64::MAX; + + assert!(matches!( + client.send_probe(), + Err(ClientError::CounterOverflow { + counter: "next_logical_seq" + }) + )); + server.join(); +} + +#[test] +fn send_probe_reports_packets_sent_counter_overflow() { + let params = default_params(); + let server = silent_open_server(params); + let config = ClientConfig { + socket_config: crate::SocketConfig { + recv_timeout: Some(Duration::from_millis(200)), + ..Default::default() + }, + ..default_test_config(server.addr) + }; + let mut client = Client::connect(config).unwrap(); + assert_open_started(client.open(ClientTimestamp::now()).unwrap()); + client.session.as_mut().unwrap().packets_sent = u64::MAX; + + assert!(matches!( + client.send_probe(), + Err(ClientError::CounterOverflow { + counter: "packets_sent" + }) + )); + server.join(); +} + #[test] fn recv_once_returns_empty_on_timeout() { let params = default_params(); diff --git a/crates/irtt-client/src/error.rs b/crates/irtt-client/src/error.rs index 9c5179e..584b153 100644 --- a/crates/irtt-client/src/error.rs +++ b/crates/irtt-client/src/error.rs @@ -49,6 +49,8 @@ pub enum ClientError { AlreadyClosed, #[error("duration is too large to encode as nanoseconds")] DurationOverflow, + #[error("counter {counter} overflowed")] + CounterOverflow { counter: &'static str }, #[error("pending probe limit exceeded ({limit})")] PendingLimitExceeded { limit: usize }, #[error("invalid configuration: {reason}")]