github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/internal/ackhandler/received_packet_tracker.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol"
     8  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/utils"
     9  	"github.com/danielpfeifer02/quic-go-prio-packs/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  
   106  	if err := h.receivedPacketTracker.ReceivedPacket(pn, ecn, rcvTime, ackEliciting); err != nil {
   107  		return err
   108  	}
   109  	if pn >= h.largestObserved {
   110  		h.largestObserved = pn
   111  		h.largestObservedRcvdTime = rcvTime
   112  	}
   113  	if !ackEliciting {
   114  		return nil
   115  	}
   116  	h.ackElicitingPacketsReceivedSinceLastAck++
   117  	isMissing := h.isMissing(pn)
   118  	if !h.ackQueued && h.shouldQueueACK(pn, ecn, isMissing) {
   119  		h.ackQueued = true
   120  		h.ackAlarm = time.Time{} // cancel the ack alarm
   121  	}
   122  	if !h.ackQueued {
   123  		// No ACK queued, but we'll need to acknowledge the packet after max_ack_delay.
   124  		h.ackAlarm = rcvTime.Add(h.maxAckDelay)
   125  		if h.logger.Debug() {
   126  			h.logger.Debugf("\tSetting ACK timer to max ack delay: %s", h.maxAckDelay)
   127  		}
   128  	}
   129  	return nil
   130  }
   131  
   132  // IgnoreBelow sets a lower limit for acknowledging packets.
   133  // Packets with packet numbers smaller than p will not be acked.
   134  func (h *appDataReceivedPacketTracker) IgnoreBelow(pn protocol.PacketNumber) {
   135  	if pn <= h.ignoreBelow {
   136  		return
   137  	}
   138  	h.ignoreBelow = pn
   139  	h.packetHistory.DeleteBelow(pn)
   140  	if h.logger.Debug() {
   141  		h.logger.Debugf("\tIgnoring all packets below %d.", pn)
   142  	}
   143  }
   144  
   145  // isMissing says if a packet was reported missing in the last ACK.
   146  func (h *appDataReceivedPacketTracker) isMissing(p protocol.PacketNumber) bool {
   147  	if h.lastAck == nil || p < h.ignoreBelow {
   148  		return false
   149  	}
   150  	return p < h.lastAck.LargestAcked() && !h.lastAck.AcksPacket(p)
   151  }
   152  
   153  func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
   154  	if h.lastAck == nil {
   155  		return false
   156  	}
   157  	highestRange := h.packetHistory.GetHighestAckRange()
   158  	return highestRange.Smallest > h.lastAck.LargestAcked()+1 && highestRange.Len() == 1
   159  }
   160  
   161  func (h *appDataReceivedPacketTracker) shouldQueueACK(pn protocol.PacketNumber, ecn protocol.ECN, wasMissing bool) bool {
   162  	// always acknowledge the first packet
   163  	if h.lastAck == nil {
   164  		h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.")
   165  		return true
   166  	}
   167  
   168  	// Send an ACK if this packet was reported missing in an ACK sent before.
   169  	// Ack decimation with reordering relies on the timer to send an ACK, but if
   170  	// missing packets we reported in the previous ACK, send an ACK immediately.
   171  	if wasMissing {
   172  		if h.logger.Debug() {
   173  			h.logger.Debugf("\tQueueing ACK because packet %d was missing before.", pn)
   174  		}
   175  		return true
   176  	}
   177  
   178  	// send an ACK every 2 ack-eliciting packets
   179  	if h.ackElicitingPacketsReceivedSinceLastAck >= packetsBeforeAck {
   180  		if h.logger.Debug() {
   181  			h.logger.Debugf("\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d).", h.ackElicitingPacketsReceivedSinceLastAck, packetsBeforeAck)
   182  		}
   183  		return true
   184  	}
   185  
   186  	// queue an ACK if there are new missing packets to report
   187  	if h.hasNewMissingPackets() {
   188  		h.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
   189  		return true
   190  	}
   191  
   192  	// queue an ACK if the packet was ECN-CE marked
   193  	if ecn == protocol.ECNCE {
   194  		h.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
   195  		return true
   196  	}
   197  	return false
   198  }
   199  
   200  func (h *appDataReceivedPacketTracker) GetAckFrame(onlyIfQueued bool) *wire.AckFrame {
   201  	now := time.Now()
   202  	if onlyIfQueued && !h.ackQueued {
   203  		if h.ackAlarm.IsZero() || h.ackAlarm.After(now) {
   204  			return nil
   205  		}
   206  		if h.logger.Debug() && !h.ackAlarm.IsZero() {
   207  			h.logger.Debugf("Sending ACK because the ACK timer expired.")
   208  		}
   209  	}
   210  	ack := h.receivedPacketTracker.GetAckFrame()
   211  	if ack == nil {
   212  		return nil
   213  	}
   214  	ack.DelayTime = max(0, now.Sub(h.largestObservedRcvdTime))
   215  	h.ackQueued = false
   216  	h.ackAlarm = time.Time{}
   217  	h.ackElicitingPacketsReceivedSinceLastAck = 0
   218  	return ack
   219  }
   220  
   221  func (h *appDataReceivedPacketTracker) GetAlarmTimeout() time.Time { return h.ackAlarm }