processDuplicateAck method
Called by UDXStream when an ACK frame is received that does not advance the _highestProcessedCumulativeAck.
frameLargestAcked
is the 'largest_acked' value from this duplicate ACK frame.
Implementation
void processDuplicateAck(int frameLargestAcked) {
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] INPUT: frameLargestAcked=$frameLargestAcked');
// //print('[CC processDuplicateAck] PRE-STATE: _lastAckedForDupCount=$_lastAckedForDupCount, _dupAcks=$_dupAcks, _inRecovery=$_inRecovery, _lostPacketInRecovery=$_lostPacketInRecovery');
// DIAGNOSTIC LOGGING END
int oldDupAcks = _dupAcks;
bool dupAcksIncremented = false;
if (frameLargestAcked == _lastAckedForDupCount) {
_dupAcks++;
dupAcksIncremented = true;
} else {
// This is the first time we've seen 'frameLargestAcked' as the duplicate frontier.
_dupAcks = 1;
_lastAckedForDupCount = frameLargestAcked;
dupAcksIncremented = true; // Technically it was set to 1, but it's a change.
}
// //print('[CC] processDuplicateAck: frameLargestAcked=$frameLargestAcked, _lastAckedForDupCount=$_lastAckedForDupCount, _dupAcks=$_dupAcks, _inRecovery=$_inRecovery');
if (_dupAcks >= 3) {
// If not already in recovery, or if this dup ack signals a loss beyond the current recovery target
if (!_inRecovery || (_inRecovery && _lastAckedForDupCount < _lostPacketInRecovery -1) ) { // The condition for _lostPacketInRecovery seems off, should be _lastAckedForDupCount + 1 == _lostPacketInRecovery for same loss, or < for earlier.
// For now, keeping original logic but logging it.
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] Condition for entering recovery met: !_inRecovery ($_inRecovery) || (_inRecovery ($_inRecovery) && _lastAckedForDupCount ($_lastAckedForDupCount) < _lostPacketInRecovery -1 ($_lostPacketInRecovery))');
// DIAGNOSTIC LOGGING END
bool enteredRecoveryThisCall = false;
if (!_inRecovery) {
_inRecovery = true;
enteredRecoveryThisCall = true;
}
_lostPacketInRecovery = _lastAckedForDupCount + 1; // Packet presumed lost
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] Set _lostPacketInRecovery=$_lostPacketInRecovery');
// DIAGNOSTIC LOGGING END
// Trigger fast retransmit only once per loss event (when _dupAcks hits 3 for this _lostPacketInRecovery)
// Or if a new, earlier loss is detected by subsequent dupacks.
if (_dupAcks == 3 && enteredRecoveryThisCall) { // Trigger if this is the transition to >=3 AND we just entered recovery for this loss
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] Fast Retransmit TRIGGERED for: $_lostPacketInRecovery (because _dupAcks == 3 and enteredRecoveryThisCall)');
// DIAGNOSTIC LOGGING END
onFastRetransmit?.call(_lostPacketInRecovery);
} else if (_dupAcks >= 3 && _inRecovery && (_lastAckedForDupCount + 1) < _lostPacketInRecovery) {
// This case handles if we are already in recovery for packet X, but now we get 3 dupacks for packet Y (where Y < X)
// This implies an earlier packet was also lost.
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] Fast Retransmit TRIGGERED for earlier packet: $_lostPacketInRecovery (because _dupAcks >= 3, in recovery, and new loss is earlier)');
// DIAGNOSTIC LOGGING END
onFastRetransmit?.call(_lostPacketInRecovery); // Retransmit the newly identified earlier lost packet
}
// Reduce congestion window only if not already in a recovery period.
if (!_inRecovery) {
_inRecovery = true;
_recoveryEndPacketNumber = packetManager.lastSentPacketNumber;
int oldSsthresh = _ssthresh;
_ssthresh = max(_cwnd ~/ 2, minCwnd); // ssthresh is half of cwnd, min 2*MSS
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] Ssthresh updated: old=$oldSsthresh, new=$_ssthresh');
// DIAGNOSTIC LOGGING END
int oldCwnd = _cwnd;
_cwnd = _ssthresh; // Enter congestion avoidance phase of recovery
pacingController.updateRate(_cwnd, _minRtt);
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] CWND updated: old=$oldCwnd, new=$_cwnd (set to ssthresh)');
// DIAGNOSTIC LOGGING END
// //print('[CC] Entered recovery. Ssthresh: $_ssthresh, CWND: $_cwnd');
}
} else {
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] _dupAcks >= 3 but NOT entering/re-entering recovery. _inRecovery=$_inRecovery, _lastAckedForDupCount=$_lastAckedForDupCount, _lostPacketInRecovery=$_lostPacketInRecovery');
// DIAGNOSTIC LOGGING END
}
}
// DIAGNOSTIC LOGGING START
// //print('[CC processDuplicateAck] POST-STATE: _lastAckedForDupCount=$_lastAckedForDupCount, _dupAcks=$_dupAcks (old: $oldDupAcks, incremented: $dupAcksIncremented), _inRecovery=$_inRecovery, _lostPacketInRecovery=$_lostPacketInRecovery');
// DIAGNOSTIC LOGGING END
}