in neqo-transport/src/connection/mod.rs [2302:2393]
fn write_frames(
&mut self,
path: &PathRef,
space: PacketNumberSpace,
profile: &SendProfile,
builder: &mut PacketBuilder,
coalesced: bool, // Whether this packet is coalesced behind another one.
now: Instant,
) -> (Vec<RecoveryToken>, bool, bool) {
let mut tokens = Vec::new();
let primary = path.borrow().is_primary();
let mut ack_eliciting = false;
if primary {
let stats = &mut self.stats.borrow_mut().frame_tx;
self.acks.write_frame(
space,
now,
path.borrow().rtt().estimate(),
builder,
&mut tokens,
stats,
);
}
let ack_end = builder.len();
// Avoid sending path validation probes until the handshake completes,
// but send them even when we don't have space.
let full_mtu = profile.limit() == path.borrow().plpmtu();
if space == PacketNumberSpace::ApplicationData && self.state.connected() {
// Path validation probes should only be padded if the full MTU is available.
// The probing code needs to know so it can track that.
if path.borrow_mut().write_frames(
builder,
&mut self.stats.borrow_mut().frame_tx,
full_mtu,
now,
) {
builder.enable_padding(true);
}
}
if profile.ack_only(space) {
// If we are CC limited we can only send ACKs!
return (tokens, false, false);
}
if primary {
if space == PacketNumberSpace::ApplicationData {
if self.state.connected()
&& path.borrow().pmtud().needs_probe()
&& !coalesced // Only send PMTUD probes using non-coalesced packets.
&& full_mtu
{
path.borrow_mut()
.pmtud_mut()
.send_probe(builder, &mut self.stats.borrow_mut());
ack_eliciting = true;
}
self.write_appdata_frames(builder, &mut tokens, now);
} else {
let stats = &mut self.stats.borrow_mut().frame_tx;
self.crypto.write_frame(
space,
self.conn_params.sni_slicing_enabled(),
builder,
&mut tokens,
stats,
);
}
}
// Maybe send a probe now, either to probe for losses or to keep the connection live.
let force_probe = profile.should_probe(space);
ack_eliciting |= self.maybe_probe(path, force_probe, builder, ack_end, &mut tokens, now);
// If this is not the primary path, this should be ack-eliciting.
debug_assert!(primary || ack_eliciting);
// Add padding. Only pad 1-RTT packets so that we don't prevent coalescing.
// And avoid padding packets that otherwise only contain ACK because adding PADDING
// causes those packets to consume congestion window, which is not tracked (yet).
// And avoid padding if we don't have a full MTU available.
let stats = &mut self.stats.borrow_mut().frame_tx;
let padded = if ack_eliciting && full_mtu && builder.pad() {
stats.padding += 1;
true
} else {
false
};
(tokens, ack_eliciting, padded)
}