resend method

int? resend(
  1. UDXPacket packet
)

Gives a packet a FRESH sequence number for another transmission and tracks it under that number, returning the number, or null when the packet has been acknowledged and must not go out again.

Reusing the original number is what made loss fatal: the retry budget rode on the packet, so exhausting it left a hole the stream could never fill. QUIC never reuses a packet number (RFC 9000 section 12.3); it re-frames lost data into a new packet. Both v3 stacks reassemble streams on byte offsets, so a fresh number is safe: a duplicate is discarded by its offset, and the retransmission is acknowledged unambiguously.

The packet may be tracked (a PTO probe re-sends the oldest outstanding packet, which stays outstanding) or not (loss detection removed it): either way it is tracked under the new number afterwards, with UDXPacket.lastSentTime reset so the RTT sample and loss detection measure from this send; UDXPacket.sentTime stays the first send. Congestion accounting is the caller's: a probe's bytes are still in flight, a lost packet's left flight when it was declared lost and are booked again by the caller when it goes out.

Implementation

int? resend(UDXPacket packet) {
  if (packet.isAcked || packet.isProbe) return null;
  if (identical(_sentPackets[packet.sequence], packet)) {
    _sentPackets.remove(packet.sequence);
  }
  final now = clock.now();
  final newSeq = nextSequence;
  packet.sequence = newSeq;
  packet.retransmitCount++;
  packet.lastRetransmit = now;
  packet.lastSentTime = now;
  packet.sentTime ??= now;
  lastSentPacketNumber = newSeq;
  _sentPackets[newSeq] = packet;
  return newSeq;
}