in neqo-transport/src/tracking.rs [418:505]
fn write_frame(
&mut self,
now: Instant,
rtt: Duration,
builder: &mut PacketBuilder,
tokens: &mut Vec<RecoveryToken>,
stats: &mut FrameStats,
) {
// Check that we aren't delaying ACKs.
if !self.ack_now(now, rtt) {
return;
}
// Drop extra ACK ranges to fit the available space. Do this based on
// a worst-case estimate of frame size for simplicity.
//
// When congestion limited, ACK-only packets are 255 bytes at most
// (`recovery::ACK_ONLY_SIZE_LIMIT - 1`). This results in limiting the
// ranges to 13 here.
let max_ranges = if let Some(avail) = builder.remaining().checked_sub(Self::USEFUL_ACK_LEN)
{
// Apply a hard maximum to keep plenty of space for other stuff.
min(1 + (avail / 16), MAX_ACKS_PER_FRAME)
} else {
return;
};
let ranges = self
.ranges
.iter()
.filter(|r| r.ack_needed())
.take(max_ranges)
.cloned()
.collect::<Vec<_>>();
if ranges.is_empty() {
return;
}
builder.encode_varint(if self.ecn_count.is_some() {
FrameType::AckEcn
} else {
FrameType::Ack
});
let mut iter = ranges.iter();
let Some(first) = iter.next() else { return };
builder.encode_varint(first.largest);
stats.largest_acknowledged = first.largest;
stats.ack += 1;
let Some(largest_pn_time) = self.largest_pn_time else {
return;
};
let elapsed = now.duration_since(largest_pn_time);
// We use the default exponent, so delay is in multiples of 8 microseconds.
let ack_delay = u64::try_from(elapsed.as_micros() / 8).unwrap_or(u64::MAX);
let ack_delay = min((1 << 62) - 1, ack_delay);
builder.encode_varint(ack_delay);
let Ok(extra_ranges) = u64::try_from(ranges.len() - 1) else {
return;
};
builder.encode_varint(extra_ranges); // extra ranges
builder.encode_varint(first.len() - 1); // first range
let mut last = first.smallest;
for r in iter {
// the difference must be at least 2 because 0-length gaps,
// (difference 1) are illegal.
builder.encode_varint(last - r.largest - 2); // Gap
builder.encode_varint(r.len() - 1); // Range
last = r.smallest;
}
if self.ecn_count.is_some() {
builder.encode_varint(self.ecn_count[IpTosEcn::Ect0]);
builder.encode_varint(self.ecn_count[IpTosEcn::Ect1]);
builder.encode_varint(self.ecn_count[IpTosEcn::Ce]);
}
// We've sent an ACK, reset the timer.
self.ack_time = None;
self.last_ack_time = Some(now);
self.unacknowledged_count = 0;
tokens.push(RecoveryToken::Ack(AckToken {
space: self.space,
ranges,
}));
}