github.com/MerlinKodo/quic-go@v0.39.2/internal/ackhandler/received_packet_tracker.go (about)

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