2022-07-21 18:50:10 +02:00
package ackhandler
import (
2022-10-24 10:20:25 +02:00
"fmt"
2022-07-21 18:50:10 +02:00
"time"
2023-02-02 12:42:11 +01:00
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/wire"
2022-07-21 18:50:10 +02:00
)
// number of ack-eliciting packets received before sending an ack.
const packetsBeforeAck = 2
type receivedPacketTracker struct {
2023-10-12 15:53:53 +02:00
largestObserved protocol . PacketNumber
ignoreBelow protocol . PacketNumber
largestObservedRcvdTime time . Time
ect0 , ect1 , ecnce uint64
2022-07-21 18:50:10 +02:00
packetHistory * receivedPacketHistory
maxAckDelay time . Duration
rttStats * utils . RTTStats
hasNewAck bool // true as soon as we received an ack-eliciting new packet
ackQueued bool // true once we received more than 2 (or later in the connection 10) ack-eliciting packets
ackElicitingPacketsReceivedSinceLastAck int
ackAlarm time . Time
lastAck * wire . AckFrame
logger utils . Logger
}
func newReceivedPacketTracker (
rttStats * utils . RTTStats ,
logger utils . Logger ,
) * receivedPacketTracker {
return & receivedPacketTracker {
packetHistory : newReceivedPacketHistory ( ) ,
maxAckDelay : protocol . MaxAckDelay ,
rttStats : rttStats ,
logger : logger ,
}
}
2023-10-12 15:53:53 +02:00
func ( h * receivedPacketTracker ) ReceivedPacket ( pn protocol . PacketNumber , ecn protocol . ECN , rcvTime time . Time , ackEliciting bool ) error {
if isNew := h . packetHistory . ReceivedPacket ( pn ) ; ! isNew {
return fmt . Errorf ( "recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d" , pn )
2022-07-21 18:50:10 +02:00
}
2023-10-12 15:53:53 +02:00
isMissing := h . isMissing ( pn )
if pn >= h . largestObserved {
h . largestObserved = pn
h . largestObservedRcvdTime = rcvTime
2022-07-21 18:50:10 +02:00
}
2023-10-12 15:53:53 +02:00
if ackEliciting {
2022-07-21 18:50:10 +02:00
h . hasNewAck = true
}
2023-10-12 15:53:53 +02:00
if ackEliciting {
h . maybeQueueACK ( pn , rcvTime , isMissing )
2022-07-21 18:50:10 +02:00
}
2023-10-12 15:53:53 +02:00
//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECNCE.
2022-07-21 18:50:10 +02:00
switch ecn {
case protocol . ECT0 :
h . ect0 ++
case protocol . ECT1 :
h . ect1 ++
case protocol . ECNCE :
h . ecnce ++
}
2022-10-24 10:20:25 +02:00
return nil
2022-07-21 18:50:10 +02:00
}
// IgnoreBelow sets a lower limit for acknowledging packets.
// Packets with packet numbers smaller than p will not be acked.
2023-10-12 15:53:53 +02:00
func ( h * receivedPacketTracker ) IgnoreBelow ( pn protocol . PacketNumber ) {
if pn <= h . ignoreBelow {
2022-07-21 18:50:10 +02:00
return
}
2023-10-12 15:53:53 +02:00
h . ignoreBelow = pn
h . packetHistory . DeleteBelow ( pn )
2022-07-21 18:50:10 +02:00
if h . logger . Debug ( ) {
2023-10-12 15:53:53 +02:00
h . logger . Debugf ( "\tIgnoring all packets below %d." , pn )
2022-07-21 18:50:10 +02:00
}
}
// isMissing says if a packet was reported missing in the last ACK.
func ( h * receivedPacketTracker ) isMissing ( p protocol . PacketNumber ) bool {
if h . lastAck == nil || p < h . ignoreBelow {
return false
}
return p < h . lastAck . LargestAcked ( ) && ! h . lastAck . AcksPacket ( p )
}
func ( h * receivedPacketTracker ) hasNewMissingPackets ( ) bool {
if h . lastAck == nil {
return false
}
highestRange := h . packetHistory . GetHighestAckRange ( )
return highestRange . Smallest > h . lastAck . LargestAcked ( ) + 1 && highestRange . Len ( ) == 1
}
2023-10-12 15:53:53 +02:00
// maybeQueueACK queues an ACK, if necessary.
func ( h * receivedPacketTracker ) maybeQueueACK ( pn protocol . PacketNumber , rcvTime time . Time , wasMissing bool ) {
2022-07-21 18:50:10 +02:00
// always acknowledge the first packet
if h . lastAck == nil {
if ! h . ackQueued {
h . logger . Debugf ( "\tQueueing ACK because the first packet should be acknowledged." )
}
h . ackQueued = true
return
}
if h . ackQueued {
return
}
h . ackElicitingPacketsReceivedSinceLastAck ++
// Send an ACK if this packet was reported missing in an ACK sent before.
// Ack decimation with reordering relies on the timer to send an ACK, but if
// missing packets we reported in the previous ack, send an ACK immediately.
if wasMissing {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %d was missing before." , pn )
}
h . ackQueued = true
}
// send an ACK every 2 ack-eliciting packets
if h . ackElicitingPacketsReceivedSinceLastAck >= packetsBeforeAck {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %d packets were received after the last ACK (using initial threshold: %d)." , h . ackElicitingPacketsReceivedSinceLastAck , packetsBeforeAck )
}
h . ackQueued = true
} else if h . ackAlarm . IsZero ( ) {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tSetting ACK timer to max ack delay: %s" , h . maxAckDelay )
}
h . ackAlarm = rcvTime . Add ( h . maxAckDelay )
}
// Queue an ACK if there are new missing packets to report.
if h . hasNewMissingPackets ( ) {
h . logger . Debugf ( "\tQueuing ACK because there's a new missing packet to report." )
h . ackQueued = true
}
if h . ackQueued {
// cancel the ack alarm
h . ackAlarm = time . Time { }
}
}
func ( h * receivedPacketTracker ) GetAckFrame ( onlyIfQueued bool ) * wire . AckFrame {
if ! h . hasNewAck {
return nil
}
now := time . Now ( )
if onlyIfQueued {
if ! h . ackQueued && ( h . ackAlarm . IsZero ( ) || h . ackAlarm . After ( now ) ) {
return nil
}
if h . logger . Debug ( ) && ! h . ackQueued && ! h . ackAlarm . IsZero ( ) {
h . logger . Debugf ( "Sending ACK because the ACK timer expired." )
}
}
2023-07-03 12:37:42 +02:00
// This function always returns the same ACK frame struct, filled with the most recent values.
ack := h . lastAck
if ack == nil {
ack = & wire . AckFrame { }
}
ack . Reset ( )
2023-10-12 15:53:53 +02:00
ack . DelayTime = utils . Max ( 0 , now . Sub ( h . largestObservedRcvdTime ) )
2022-10-24 10:20:25 +02:00
ack . ECT0 = h . ect0
ack . ECT1 = h . ect1
ack . ECNCE = h . ecnce
ack . AckRanges = h . packetHistory . AppendAckRanges ( ack . AckRanges )
2022-07-21 18:50:10 +02:00
h . lastAck = ack
h . ackAlarm = time . Time { }
h . ackQueued = false
h . hasNewAck = false
h . ackElicitingPacketsReceivedSinceLastAck = 0
return ack
}
func ( h * receivedPacketTracker ) GetAlarmTimeout ( ) time . Time { return h . ackAlarm }
func ( h * receivedPacketTracker ) IsPotentiallyDuplicate ( pn protocol . PacketNumber ) bool {
return h . packetHistory . IsPotentiallyDuplicate ( pn )
}