From bcea31aac443158f7af1c36404096f9ab17b7477 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Thu, 24 Sep 2026 23:36:19 +0700 Subject: [PATCH] fix(probe): require fresh reflector responses during reselection --- src/reflector_selector.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/reflector_selector.rs b/src/reflector_selector.rs index 5b7a9ce..0752fa0 100644 --- a/src/reflector_selector.rs +++ b/src/reflector_selector.rs @@ -98,9 +98,14 @@ fn receive_snapshots_until( } } -fn recent_rtt_for_peer(snapshot: Option<&ControlSnapshot>, peer: &IpAddr) -> Option { +fn recent_rtt_for_peer( + snapshot: Option<&ControlSnapshot>, + peer: &IpAddr, + baseline_started_at: Instant, +) -> Option { snapshot .and_then(|snapshot| snapshot.reflectors.get(peer)) + .filter(|state| state.last_receive_at >= baseline_started_at) .map(|state| (state.recent.down + state.recent.up) as u64) } @@ -186,6 +191,7 @@ impl ReflectorSelector { // Clone next_peers because we need it again after the baseline sleep // to iterate over candidates for RTT measurement. + let baseline_started_at = Instant::now(); *reflectors_peers = next_peers.clone(); // Drop the MutexGuard explicitly, as Rust won't unlock the mutex by default @@ -206,7 +212,9 @@ impl ReflectorSelector { let mut candidates = Vec::new(); for peer in next_peers { - if let Some(rtt) = recent_rtt_for_peer(latest_snapshot.as_ref(), &peer) { + if let Some(rtt) = + recent_rtt_for_peer(latest_snapshot.as_ref(), &peer, baseline_started_at) + { candidates.push((peer, rtt)); info!("Candidate reflector: {} RTT: {}", peer, rtt); } else { @@ -400,8 +408,20 @@ mod tests { ); assert_eq!( - recent_rtt_for_peer(latest_snapshot.as_ref(), &peer), + recent_rtt_for_peer( + latest_snapshot.as_ref(), + &peer, + generated_at - Duration::from_millis(1), + ), Some(42) ); + assert_eq!( + recent_rtt_for_peer( + latest_snapshot.as_ref(), + &peer, + generated_at + Duration::from_secs(1), + ), + None + ); } }