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
)
2024-03-26 19:56:06 +01:00
// The receivedPacketTracker tracks packets for the Initial and Handshake packet number space.
// Every received packet is acknowledged immediately.
2022-07-21 18:50:10 +02:00
type receivedPacketTracker struct {
2024-03-26 19:56:06 +01:00
ect0 , ect1 , ecnce uint64
2022-07-21 18:50:10 +02:00
2024-03-26 19:56:06 +01:00
packetHistory receivedPacketHistory
2022-07-21 18:50:10 +02:00
2024-03-26 19:56:06 +01:00
lastAck * wire . AckFrame
2022-07-21 18:50:10 +02:00
hasNewAck bool // true as soon as we received an ack-eliciting new packet
}
2024-03-26 19:56:06 +01:00
func newReceivedPacketTracker ( ) * receivedPacketTracker {
return & receivedPacketTracker { packetHistory : * newReceivedPacketHistory ( ) }
2022-07-21 18:50:10 +02:00
}
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
}
2024-01-18 23:47:00 +01:00
//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
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 ++
}
2024-01-18 23:47:00 +01:00
if ! ackEliciting {
return nil
}
h . hasNewAck = true
2024-03-26 19:56:06 +01:00
return nil
}
func ( h * receivedPacketTracker ) GetAckFrame ( ) * wire . AckFrame {
if ! h . hasNewAck {
return nil
}
// 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 ( )
ack . ECT0 = h . ect0
ack . ECT1 = h . ect1
ack . ECNCE = h . ecnce
ack . AckRanges = h . packetHistory . AppendAckRanges ( ack . AckRanges )
h . lastAck = ack
h . hasNewAck = false
return ack
}
func ( h * receivedPacketTracker ) IsPotentiallyDuplicate ( pn protocol . PacketNumber ) bool {
return h . packetHistory . IsPotentiallyDuplicate ( pn )
}
// number of ack-eliciting packets received before sending an ACK
const packetsBeforeAck = 2
// The appDataReceivedPacketTracker tracks packets received in the Application Data packet number space.
// It waits until at least 2 packets were received before queueing an ACK, or until the max_ack_delay was reached.
type appDataReceivedPacketTracker struct {
receivedPacketTracker
largestObservedRcvdTime time . Time
largestObserved protocol . PacketNumber
ignoreBelow protocol . PacketNumber
maxAckDelay time . Duration
ackQueued bool // true if we need send a new ACK
ackElicitingPacketsReceivedSinceLastAck int
ackAlarm time . Time
logger utils . Logger
}
func newAppDataReceivedPacketTracker ( logger utils . Logger ) * appDataReceivedPacketTracker {
h := & appDataReceivedPacketTracker {
receivedPacketTracker : * newReceivedPacketTracker ( ) ,
maxAckDelay : protocol . MaxAckDelay ,
logger : logger ,
}
return h
}
func ( h * appDataReceivedPacketTracker ) ReceivedPacket ( pn protocol . PacketNumber , ecn protocol . ECN , rcvTime time . Time , ackEliciting bool ) error {
if err := h . receivedPacketTracker . ReceivedPacket ( pn , ecn , rcvTime , ackEliciting ) ; err != nil {
return err
}
if pn >= h . largestObserved {
h . largestObserved = pn
h . largestObservedRcvdTime = rcvTime
}
if ! ackEliciting {
return nil
}
2024-01-18 23:47:00 +01:00
h . ackElicitingPacketsReceivedSinceLastAck ++
2024-03-26 19:56:06 +01:00
isMissing := h . isMissing ( pn )
2024-01-18 23:47:00 +01:00
if ! h . ackQueued && h . shouldQueueACK ( pn , ecn , isMissing ) {
h . ackQueued = true
h . ackAlarm = time . Time { } // cancel the ack alarm
}
if ! h . ackQueued {
// No ACK queued, but we'll need to acknowledge the packet after max_ack_delay.
h . ackAlarm = rcvTime . Add ( h . maxAckDelay )
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tSetting ACK timer to max ack delay: %s" , h . maxAckDelay )
}
}
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.
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) IgnoreBelow ( pn protocol . PacketNumber ) {
2023-10-12 15:53:53 +02:00
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.
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) isMissing ( p protocol . PacketNumber ) bool {
2022-07-21 18:50:10 +02:00
if h . lastAck == nil || p < h . ignoreBelow {
return false
}
return p < h . lastAck . LargestAcked ( ) && ! h . lastAck . AcksPacket ( p )
}
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) hasNewMissingPackets ( ) bool {
2022-07-21 18:50:10 +02:00
if h . lastAck == nil {
return false
}
highestRange := h . packetHistory . GetHighestAckRange ( )
return highestRange . Smallest > h . lastAck . LargestAcked ( ) + 1 && highestRange . Len ( ) == 1
}
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) shouldQueueACK ( pn protocol . PacketNumber , ecn protocol . ECN , wasMissing bool ) bool {
2022-07-21 18:50:10 +02:00
// always acknowledge the first packet
if h . lastAck == nil {
2024-01-18 23:47:00 +01:00
h . logger . Debugf ( "\tQueueing ACK because the first packet should be acknowledged." )
return true
2022-07-21 18:50:10 +02:00
}
// 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
2024-03-26 19:56:06 +01:00
// missing packets we reported in the previous ACK, send an ACK immediately.
2022-07-21 18:50:10 +02:00
if wasMissing {
if h . logger . Debug ( ) {
h . logger . Debugf ( "\tQueueing ACK because packet %d was missing before." , pn )
}
2024-01-18 23:47:00 +01:00
return true
2022-07-21 18:50:10 +02:00
}
// 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 )
}
2024-01-18 23:47:00 +01:00
return true
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
// queue an ACK if there are new missing packets to report
2022-07-21 18:50:10 +02:00
if h . hasNewMissingPackets ( ) {
h . logger . Debugf ( "\tQueuing ACK because there's a new missing packet to report." )
2024-01-18 23:47:00 +01:00
return true
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
// queue an ACK if the packet was ECN-CE marked
if ecn == protocol . ECNCE {
h . logger . Debugf ( "\tQueuing ACK because the packet was ECN-CE marked." )
return true
2022-07-21 18:50:10 +02:00
}
2024-01-18 23:47:00 +01:00
return false
2022-07-21 18:50:10 +02:00
}
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) GetAckFrame ( onlyIfQueued bool ) * wire . AckFrame {
2022-07-21 18:50:10 +02:00
now := time . Now ( )
2024-03-26 19:56:06 +01:00
if onlyIfQueued && ! h . ackQueued {
if h . ackAlarm . IsZero ( ) || h . ackAlarm . After ( now ) {
2022-07-21 18:50:10 +02:00
return nil
}
2024-03-26 19:56:06 +01:00
if h . logger . Debug ( ) && ! h . ackAlarm . IsZero ( ) {
2022-07-21 18:50:10 +02:00
h . logger . Debugf ( "Sending ACK because the ACK timer expired." )
}
}
2024-03-26 19:56:06 +01:00
ack := h . receivedPacketTracker . GetAckFrame ( )
2023-07-03 12:37:42 +02:00
if ack == nil {
2024-03-26 19:56:06 +01:00
return nil
2023-07-03 12:37:42 +02:00
}
2024-01-18 23:47:00 +01:00
ack . DelayTime = max ( 0 , now . Sub ( h . largestObservedRcvdTime ) )
2022-07-21 18:50:10 +02:00
h . ackQueued = false
2024-03-26 19:56:06 +01:00
h . ackAlarm = time . Time { }
2022-07-21 18:50:10 +02:00
h . ackElicitingPacketsReceivedSinceLastAck = 0
return ack
}
2024-03-26 19:56:06 +01:00
func ( h * appDataReceivedPacketTracker ) GetAlarmTimeout ( ) time . Time { return h . ackAlarm }