PacketManager class

Manages packet sending and receiving for a UDXStream Tracks sent packets, matches ACKs to them, and declares loss the way RFC 9002 section 6.1 does: from acknowledgements, never from a per-packet timer. The port of go-udx's PacketManager.

A packet is lost once a later one has been acknowledged and it is either lossReorderThreshold sequences behind the largest acknowledged or older than lossDelay (9/8 of the RTT). Packets behind but not yet old enough wait on the loss timer, which declares them lost when the delay elapses without another ACK. What is lost is handed to onPacketsLost; the socket contracts its window once per recovery epoch and re-sends the data under fresh sequences through the congestion window and the pacer (LostQueue).

This replaced one retransmission timer per packet, armed at the RTO and backing off to a 2 s cap. On a radio gap every timer fired together and the whole window went out again at once, past the congestion window, and again every 2 s into a dead path; the resends did not contract the window either. QUIC's one PTO per connection (CongestionController) sends a probe or two instead, backing off until the idle timeout, and loss is declared only once an ACK proves it.

Constructors

PacketManager({CongestionController? congestionController, Clock? clock})
Creates a new packet manager

Properties

clock → Clock
The clock send times and the loss timer run on; see Clock.
final
congestionController ↔ CongestionController
The congestion control algorithm
getter/setter pair
hashCode → int
The hash code for this object.
no setterinherited
largestAcked → int
The largest sequence the peer has acknowledged, -1 if none; when the last ACK that acknowledged something arrived; and the one before the ACK (or timer) that last declared loss: persistent congestion asks whether anything was acknowledged since the oldest lost packet went out, which the ACK that revealed the loss does not answer.
no setter
lastSentPacketNumber ↔ int
The sequence number of the last packet that was sent.
getter/setter pair
lossDelay → Duration
How long a packet must have been outstanding before age alone marks it lost: 9/8 of the larger of the smoothed and latest RTT, floored at the timer granularity (RFC 9002 section 6.1.2). The larger of the two: after a sudden increase in delay the smoothed estimate lags, and alone it would declare a window of packets lost for being slower than they used to be.
no setter
lossTimerArmed → bool
Whether a packet is waiting on the time threshold.
no setter
nextSequence → int
The next sequence number to use
no setter
onPacketLossEvent ↔ void Function(int sequence, String lossType)?
Callback for metrics when packet loss is detected. Provides sequence number and loss type ('ack' or 'time').
getter/setter pair
onPacketRetransmitEvent ↔ void Function(int sequence, int attemptCount, Duration rto)?
Callback for metrics when a packet is retransmitted. Provides sequence number, attempt count, and the current PTO.
getter/setter pair
onPacketsLost ↔ void Function(List<UDXPacket> lost)?
Told what loss detection declared lost, oldest first. The packets are no longer tracked: the receiver re-sends them (resend) and books them.
getter/setter pair
onRetransmit ↔ void Function(UDXPacket packet)?
Puts a packet back on the wire. By the time it is called the packet's sequence has been advanced to a fresh number (resend), so this only encodes and sends.
getter/setter pair
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
sentPackets → List<UDXPacket>
no setter

Methods

destroy() → void
Stops the loss timer and forgets every packet.
detectLostPackets() → List<UDXPacket>
Runs loss detection over everything outstanding (RFC 9002 section 6.1) and returns what it declared lost, also handed to onPacketsLost. The socket calls it after each ACK that acknowledged something; the loss timer calls it when the time threshold elapses.
drop(UDXPacket packet) → void
Forgets a tracked packet that is being replaced by others (fitToPath), neither acknowledged nor lost.
fitToPath(UDXPacket packet, int limit) → List<UDXPacket>
Re-chunks a packet larger than the path now carries (the size fell back after a black hole, MtuDiscovery) into packets that fit, in its place: the original is dropped from tracking and the pieces take fresh sequences when they are re-sent (resend). A packet that fits is returned as it is. Only a packet carrying one STREAM frame is split, which is every data packet a stream sends.
forget(int sequence) → void
Stops tracking sequence, if it is still tracked.
getPacket(int sequence) → UDXPacket?
Gets a sent packet by its sequence number
getSentPacketsTestHook() → Map<int, UDXPacket>
handleAckFrame(AckFrame frame) → List<UDXPacket>
Processes an incoming AckFrame, marking packets as acknowledged.
handleData(UDXPacket packet) → void
Handles received data
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
oldestUnacked(int n) → List<UDXPacket>
Up to n outstanding packets, lowest sequence first: what a PTO probe re-sends. A re-send takes a fresh sequence, so the lowest numbers are the longest unsent.
persistentCongestion(List<UDXPacket> lost) → bool
Whether lost, as just declared, is persistent congestion (RFC 9002 section 7.6): the sender has an RTT sample, the newest lost packet went out at least three PTOs after the oldest, and nothing was acknowledged between the oldest going out and the ACK (or timer) that revealed the loss. The socket then collapses the window.
resend(UDXPacket packet) → int?
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.
sendPacket(UDXPacket packet) → void
Sends a packet
sendProbe({int? maxDatagram}) → bool
Sends the PTO's probes: the ptoProbes oldest outstanding packets, re-sent under fresh sequences (RFC 9002 section 6.2.4: a probe carries data when there is data to carry). They are not declared lost (an ACK will say), their bytes stay in flight, and neither the window nor the pacer is consulted: a probe is allowed out when nothing else is (RFC 9002 section 7.7 exempts probes from pacing), though it is drawn from the pacing budget so that what follows it is paced as if it had been. maxDatagram, when given, is what the path carries now: a larger packet is re-chunked to fit. Returns whether anything went out.
toString() → String
A string representation of this object.
inherited
trackUntilAcked(UDXPacket packet) → void
Tracks a packet the caller sends itself, so that handleAckFrame returns it when acknowledged, without ever retransmitting it: a PING sent to test liveness (UDPSocket.ping). The caller forgets it (forget) when it stops waiting, so a lost ACK leaves nothing behind.

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

lossReorderThreshold → const int
How many sequences a packet must trail the largest acknowledged before a gap counts as loss (kPacketThreshold, RFC 9002 section 6.1.1).
lossTimerGranularity → const Duration
The floor on the loss delay (kGranularity).
ptoProbes → const int
How many outstanding packets a PTO re-sends, the oldest first (RFC 9002 section 6.2.4 allows up to two).