github.com/sagernet/quic-go@v0.43.1-beta.1/internal/ackhandler/received_packet_tracker.go (about) 1 package ackhandler 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/sagernet/quic-go/internal/protocol" 8 "github.com/sagernet/quic-go/internal/utils" 9 "github.com/sagernet/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 = utils.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 }