processDuplicateAck method

void processDuplicateAck(
  1. int frameLargestAcked
)

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
}