in neqo-transport/src/connection/mod.rs [2251:2297]
fn maybe_probe(
&mut self,
path: &PathRef,
force_probe: bool,
builder: &mut PacketBuilder,
ack_end: usize,
tokens: &mut Vec<RecoveryToken>,
now: Instant,
) -> bool {
let untracked = self.received_untracked && !self.state.connected();
self.received_untracked = false;
// Anything written after an ACK already elicits acknowledgment.
// If we need to probe and nothing has been written, send a PING.
if builder.len() > ack_end {
return true;
}
let pto = path.borrow().rtt().pto(self.confirmed());
let mut probe = if untracked && builder.packet_empty() || force_probe {
// If we received an untracked packet and we aren't probing already
// or the PTO timer fired: probe.
true
} else if !builder.packet_empty() {
// The packet only contains an ACK. Check whether we want to
// force an ACK with a PING so we can stop tracking packets.
self.loss_recovery.should_probe(pto, now)
} else {
false
};
if self.streams.need_keep_alive() {
// We need to keep the connection alive, including sending a PING
// again. If a PING is already scheduled (i.e. `probe` is `true`)
// piggy back on it. If not, schedule one.
probe |= self.idle_timeout.send_keep_alive(now, pto, tokens);
}
if probe {
// Nothing ack-eliciting and we need to probe; send PING.
debug_assert_ne!(builder.remaining(), 0);
builder.encode_varint(FrameType::Ping);
let stats = &mut self.stats.borrow_mut().frame_tx;
stats.ping += 1;
}
probe
}