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 }