github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/internal/ackhandler/received_packet_tracker.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/daeuniverse/quic-go/internal/protocol"
     8  	"github.com/daeuniverse/quic-go/internal/utils"
     9  	"github.com/daeuniverse/quic-go/internal/wire"
    10  )
    11  
    12  // The receivedPacketTracker tracks packets for the Initial and Handshake packet number space.
    13  // Every received packet is acknowledged immediately.
    14  type receivedPacketTracker struct {
    15  	ect0, ect1, ecnce uint64
    16  
    17  	packetHistory receivedPacketHistory
    18  
    19  	lastAck   *wire.AckFrame
    20  	hasNewAck bool // true as soon as we received an ack-eliciting new packet
    21  }
    22  
    23  func newReceivedPacketTracker() *receivedPacketTracker {
    24  	return &receivedPacketTracker{packetHistory: *newReceivedPacketHistory()}
    25  }
    26  
    27  func (h *receivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, ackEliciting bool) error {
    28  	if isNew := h.packetHistory.ReceivedPacket(pn); !isNew {
    29  		return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", pn)
    30  	}
    31  
    32  	//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
    33  	switch ecn {
    34  	case protocol.ECT0:
    35  		h.ect0++
    36  	case protocol.ECT1:
    37  		h.ect1++
    38  	case protocol.ECNCE:
    39  		h.ecnce++
    40  	}
    41  	if !ackEliciting {
    42  		return nil
    43  	}
    44  	h.hasNewAck = true
    45  	return nil
    46  }
    47  
    48  func (h *receivedPacketTracker) GetAckFrame() *wire.AckFrame {
    49  	if !h.hasNewAck {
    50  		return nil
    51  	}
    52  
    53  	// This function always returns the same ACK frame struct, filled with the most recent values.
    54  	ack := h.lastAck
    55  	if ack == nil {
    56  		ack = &wire.AckFrame{}
    57  	}
    58  	ack.Reset()
    59  	ack.ECT0 = h.ect0
    60  	ack.ECT1 = h.ect1
    61  	ack.ECNCE = h.ecnce
    62  	ack.AckRanges = h.packetHistory.AppendAckRanges(ack.AckRanges)
    63  
    64  	h.lastAck = ack
    65  	h.hasNewAck = false
    66  	return ack
    67  }
    68  
    69  func (h *receivedPacketTracker) IsPotentiallyDuplicate(pn protocol.PacketNumber) bool {
    70  	return h.packetHistory.IsPotentiallyDuplicate(pn)
    71  }
    72  
    73  // number of ack-eliciting packets received before sending an ACK
    74  const packetsBeforeAck = 2
    75  
    76  // The appDataReceivedPacketTracker tracks packets received in the Application Data packet number space.
    77  // It waits until at least 2 packets were received before queueing an ACK, or until the max_ack_delay was reached.
    78  type appDataReceivedPacketTracker struct {
    79  	receivedPacketTracker
    80  
    81  	largestObservedRcvdTime time.Time
    82  
    83  	largestObserved protocol.PacketNumber
    84  	ignoreBelow     protocol.PacketNumber
    85  
    86  	maxAckDelay time.Duration
    87  	ackQueued   bool // true if we need send a new ACK
    88  
    89  	ackElicitingPacketsReceivedSinceLastAck int
    90  	ackAlarm                                time.Time
    91  
    92  	logger utils.Logger
    93  }
    94  
    95  func newAppDataReceivedPacketTracker(logger utils.Logger) *appDataReceivedPacketTracker {
    96  	h := &appDataReceivedPacketTracker{
    97  		receivedPacketTracker: *newReceivedPacketTracker(),
    98  		maxAckDelay:           protocol.MaxAckDelay,
    99  		logger:                logger,
   100  	}
   101  	return h
   102  }
   103  
   104  func (h *appDataReceivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, ackEliciting bool) error {
   105  	if err := h.receivedPacketTracker.ReceivedPacket(pn, ecn, rcvTime, ackEliciting); err != nil {
   106  		return err
   107  	}
   108  	if pn >= h.largestObserved {
   109  		h.largestObserved = pn
   110  		h.largestObservedRcvdTime = rcvTime
   111  	}
   112  	if !ackEliciting {
   113  		return nil
   114  	}
   115  	h.ackElicitingPacketsReceivedSinceLastAck++
   116  	isMissing := h.isMissing(pn)
   117  	if !h.ackQueued && h.shouldQueueACK(pn, ecn, isMissing) {
   118  		h.ackQueued = true
   119  		h.ackAlarm = time.Time{} // cancel the ack alarm
   120  	}
   121  	if !h.ackQueued {
   122  		// No ACK queued, but we'll need to acknowledge the packet after max_ack_delay.
   123  		h.ackAlarm = rcvTime.Add(h.maxAckDelay)
   124  		if h.logger.Debug() {
   125  			h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", h.maxAckDelay)
   126  		}
   127  	}
   128  	return nil
   129  }
   130  
   131  // IgnoreBelow sets a lower limit for acknowledging packets.
   132  // Packets with packet numbers smaller than p will not be acked.
   133  func (h *appDataReceivedPacketTracker) IgnoreBelow(pn protocol.PacketNumber) {
   134  	if pn <= h.ignoreBelow {
   135  		return
   136  	}
   137  	h.ignoreBelow = pn
   138  	h.packetHistory.DeleteBelow(pn)
   139  	if h.logger.Debug() {
   140  		h.logger.Debugf("\tIgnoring all packets below %d.", pn)
   141  	}
   142  }
   143  
   144  // isMissing says if a packet was reported missing in the last ACK.
   145  func (h *appDataReceivedPacketTracker) isMissing(p protocol.PacketNumber) bool {
   146  	if h.lastAck == nil || p < h.ignoreBelow {
   147  		return false
   148  	}
   149  	return p < h.lastAck.LargestAcked() && !h.lastAck.AcksPacket(p)
   150  }
   151  
   152  func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
   153  	if h.lastAck == nil {
   154  		return false
   155  	}
   156  	highestRange := h.packetHistory.GetHighestAckRange()
   157  	return highestRange.Smallest > h.lastAck.LargestAcked()+1 && highestRange.Len() == 1
   158  }
   159  
   160  func (h *appDataReceivedPacketTracker) shouldQueueACK(pn protocol.PacketNumber, ecn protocol.ECN, wasMissing bool) bool {
   161  	// always acknowledge the first packet
   162  	if h.lastAck == nil {
   163  		h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.")
   164  		return true
   165  	}
   166  
   167  	// Send an ACK if this packet was reported missing in an ACK sent before.
   168  	// Ack decimation with reordering relies on the timer to send an ACK, but if
   169  	// missing packets we reported in the previous ACK, send an ACK immediately.
   170  	if wasMissing {
   171  		if h.logger.Debug() {
   172  			h.logger.Debugf("\tQueueing ACK because packet %d was missing before.", pn)
   173  		}
   174  		return true
   175  	}
   176  
   177  	// send an ACK every 2 ack-eliciting packets
   178  	if h.ackElicitingPacketsReceivedSinceLastAck >= packetsBeforeAck {
   179  		if h.logger.Debug() {
   180  			h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", h.ackElicitingPacketsReceivedSinceLastAck, packetsBeforeAck)
   181  		}
   182  		return true
   183  	}
   184  
   185  	// queue an ACK if there are new missing packets to report
   186  	if h.hasNewMissingPackets() {
   187  		h.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
   188  		return true
   189  	}
   190  
   191  	// queue an ACK if the packet was ECN-CE marked
   192  	if ecn == protocol.ECNCE {
   193  		h.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
   194  		return true
   195  	}
   196  	return false
   197  }
   198  
   199  func (h *appDataReceivedPacketTracker) GetAckFrame(onlyIfQueued bool) *wire.AckFrame {
   200  	now := time.Now()
   201  	if onlyIfQueued && !h.ackQueued {
   202  		if h.ackAlarm.IsZero() || h.ackAlarm.After(now) {
   203  			return nil
   204  		}
   205  		if h.logger.Debug() && !h.ackAlarm.IsZero() {
   206  			h.logger.Debugf("Sending ACK because the ACK timer expired.")
   207  		}
   208  	}
   209  	ack := h.receivedPacketTracker.GetAckFrame()
   210  	if ack == nil {
   211  		return nil
   212  	}
   213  	ack.DelayTime = max(0, now.Sub(h.largestObservedRcvdTime))
   214  	h.ackQueued = false
   215  	h.ackAlarm = time.Time{}
   216  	h.ackElicitingPacketsReceivedSinceLastAck = 0
   217  	return ack
   218  }
   219  
   220  func (h *appDataReceivedPacketTracker) GetAlarmTimeout() time.Time { return h.ackAlarm }