Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions rtc-ice/src/agent/agent_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2859,6 +2859,25 @@ fn test_handle_inbound_request_defers_failing_connectivity_check() -> Result<()>
assert!(a.selected_pair.is_none());
assert!(a.nominated_pair.is_none());

// A failed agent must not pin `poll_timeout` in the past. `contact`
// runs no checks in `Failed`, but the next wake-up is scheduled as
// `last_checking_time + interval`; if the `Failed` path does not
// advance the clock, every `handle_timeout` leaves the same expired
// deadline armed, and a driver that re-polls after handling spins at
// loop speed (observed live at ~4.5M loop passes per second,
// starving its whole runtime). The periodic twin of the
// `force_candidate_contact` reset asserted above. Asserted well past
// the creation-time deadline, because that is where the frozen clock
// is distinguishable from a fresh one.
let later = Instant::now() + Duration::from_secs(3600);
a.handle_timeout(later)?;
if let Some(deadline) = a.poll_timeout() {
assert!(
deadline > later,
"a failed agent left an expired wake-up deadline armed"
);
}

a.close()?;
Ok(())
}
Expand Down
9 changes: 9 additions & 0 deletions rtc-ice/src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,15 @@ impl Agent {
// The connection is currently failed so don't send any checks
// In the future it may be restarted though
self.last_connection_state = self.connection_state;
// Advance the checking clock even though no checks run:
// `poll_timeout` schedules the next wake-up as
// `last_checking_time + interval`, so a value frozen at the
// last real check pins the deadline in the past. Every
// `handle_timeout` then lands back here without advancing
// it, and a driver that re-polls after handling spins at
// loop speed, forever. This is the periodic twin of the
// `force_candidate_contact` reset above (issue #88).
self.last_checking_time = now;
return;
}
if self.connection_state == ConnectionState::Checking {
Expand Down