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 }