// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build go1.21 package quic import ( "time" ) // ackState tracks packets received from a peer within a number space. // It handles packet deduplication (don't process the same packet twice) and // determines the timing and content of ACK frames. type ackState struct { seen rangeset[packetNumber] // The time at which we must send an ACK frame, even if we have no other data to send. nextAck time.Time // The time we received the largest-numbered packet in seen. maxRecvTime time.Time // The largest-numbered ack-eliciting packet in seen. maxAckEliciting packetNumber // The number of ack-eliciting packets in seen that we have not yet acknowledged. unackedAckEliciting int } // shouldProcess reports whether a packet should be handled or discarded. func (acks *ackState) shouldProcess(num packetNumber) bool { if packetNumber(acks.seen.min()) > num { // We've discarded the state for this range of packet numbers. // Discard the packet rather than potentially processing a duplicate. // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.3-5 return false } if acks.seen.contains(num) { // Discard duplicate packets. return false } return true } // receive records receipt of a packet. func (acks *ackState) receive(now time.Time, space numberSpace, num packetNumber, ackEliciting bool) { if ackEliciting { acks.unackedAckEliciting++ if acks.mustAckImmediately(space, num) { acks.nextAck = now } else if acks.nextAck.IsZero() { // This packet does not need to be acknowledged immediately, // but the ack must not be intentionally delayed by more than // the max_ack_delay transport parameter we sent to the peer. // // We always delay acks by the maximum allowed, less the timer // granularity. ("[max_ack_delay] SHOULD include the receiver's // expected delays in alarms firing.") // // https://www.rfc-editor.org/rfc/rfc9000#section-18.2-4.28.1 acks.nextAck = now.Add(maxAckDelay - timerGranularity) } if num > acks.maxAckEliciting { acks.maxAckEliciting = num } } acks.seen.add(num, num+1) if num == acks.seen.max() { acks.maxRecvTime = now } // Limit the total number of ACK ranges by dropping older ranges. // // Remembering more ranges results in larger ACK frames. // // Remembering a large number of ranges could result in ACK frames becoming // too large to fit in a packet, in which case we will silently drop older // ranges during packet construction. // // Remembering fewer ranges can result in unnecessary retransmissions, // since we cannot accept packets older than the oldest remembered range. // // The limit here is completely arbitrary. If it seems wrong, it probably is. // // https://www.rfc-editor.org/rfc/rfc9000#section-13.2.3 const maxAckRanges = 8 if overflow := acks.seen.numRanges() - maxAckRanges; overflow > 0 { acks.seen.removeranges(0, overflow) } } // mustAckImmediately reports whether an ack-eliciting packet must be acknowledged immediately, // or whether the ack may be deferred. func (acks *ackState) mustAckImmediately(space numberSpace, num packetNumber) bool { // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1 if space != appDataSpace { // "[...] all ack-eliciting Initial and Handshake packets [...]" // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-2 return true } if num < acks.maxAckEliciting { // "[...] when the received packet has a packet number less than another // ack-eliciting packet that has been received [...]" // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-8.1 return true } if acks.seen.rangeContaining(acks.maxAckEliciting).end != num { // "[...] when the packet has a packet number larger than the highest-numbered // ack-eliciting packet that has been received and there are missing packets // between that packet and this packet." // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.1-8.2 // // This case is a bit tricky. Let's say we've received: // 0, ack-eliciting // 1, ack-eliciting // 3, NOT ack eliciting // // We have sent ACKs for 0 and 1. If we receive ack-eliciting packet 2, // we do not need to send an immediate ACK, because there are no missing // packets between it and the highest-numbered ack-eliciting packet (1). // If we receive ack-eliciting packet 4, we do need to send an immediate ACK, // because there's a gap (the missing packet 2). // // We check for this by looking up the ACK range which contains the // highest-numbered ack-eliciting packet: [0, 1) in the above example. // If the range ends just before the packet we are now processing, // there are no gaps. If it does not, there must be a gap. return true } if acks.unackedAckEliciting >= 2 { // "[...] after receiving at least two ack-eliciting packets." // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.2 return true } return false } // shouldSendAck reports whether the connection should send an ACK frame at this time, // in an ACK-only packet if necessary. func (acks *ackState) shouldSendAck(now time.Time) bool { return !acks.nextAck.IsZero() && !acks.nextAck.After(now) } // acksToSend returns the set of packet numbers to ACK at this time, and the current ack delay. // It may return acks even if shouldSendAck returns false, when there are unacked // ack-eliciting packets whose ack is being delayed. func (acks *ackState) acksToSend(now time.Time) (nums rangeset[packetNumber], ackDelay time.Duration) { if acks.nextAck.IsZero() && acks.unackedAckEliciting == 0 { return nil, 0 } // "[...] the delays intentionally introduced between the time the packet with the // largest packet number is received and the time an acknowledgement is sent." // https://www.rfc-editor.org/rfc/rfc9000#section-13.2.5-1 delay := now.Sub(acks.maxRecvTime) if delay < 0 { delay = 0 } return acks.seen, delay } // sentAck records that an ACK frame has been sent. func (acks *ackState) sentAck() { acks.nextAck = time.Time{} acks.unackedAckEliciting = 0 } // handleAck records that an ack has been received for a ACK frame we sent // containing the given Largest Acknowledged field. func (acks *ackState) handleAck(largestAcked packetNumber) { // We can stop acking packets less or equal to largestAcked. // https://www.rfc-editor.org/rfc/rfc9000.html#section-13.2.4-1 // // We rely on acks.seen containing the largest packet number that has been successfully // processed, so we retain the range containing largestAcked and discard previous ones. acks.seen.sub(0, acks.seen.rangeContaining(largestAcked).start) } // largestSeen reports the largest seen packet. func (acks *ackState) largestSeen() packetNumber { return acks.seen.max() }