mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 20:57:36 +03:00
The RTTStats are used by the logging package. In order to instrument the congestion package, the RTTStats can't be part of that package any more (to avoid an import loop).
156 lines
5.2 KiB
Go
156 lines
5.2 KiB
Go
package ackhandler
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/utils"
|
|
"github.com/lucas-clemente/quic-go/internal/wire"
|
|
)
|
|
|
|
const (
|
|
// initial maximum number of ack-eliciting packets received before sending an ack.
|
|
initialAckElicitingPacketsBeforeAck = 2
|
|
// number of ack-eliciting that an ACK is sent for
|
|
ackElicitingPacketsBeforeAck = 10
|
|
// 1/5 RTT delay when doing ack decimation
|
|
ackDecimationDelay = 1.0 / 4
|
|
// 1/8 RTT delay when doing ack decimation
|
|
shortAckDecimationDelay = 1.0 / 8
|
|
// Minimum number of packets received before ack decimation is enabled.
|
|
// This intends to avoid the beginning of slow start, when CWNDs may be
|
|
// rapidly increasing.
|
|
minReceivedBeforeAckDecimation = 100
|
|
// Maximum number of packets to ack immediately after a missing packet for
|
|
// fast retransmission to kick in at the sender. This limit is created to
|
|
// reduce the number of acks sent that have no benefit for fast retransmission.
|
|
// Set to the number of nacks needed for fast retransmit plus one for protection
|
|
// against an ack loss
|
|
maxPacketsAfterNewMissing = 4
|
|
)
|
|
|
|
type receivedPacketHandler struct {
|
|
sentPackets sentPacketTracker
|
|
|
|
initialPackets *receivedPacketTracker
|
|
handshakePackets *receivedPacketTracker
|
|
appDataPackets *receivedPacketTracker
|
|
|
|
lowest1RTTPacket protocol.PacketNumber
|
|
}
|
|
|
|
var _ ReceivedPacketHandler = &receivedPacketHandler{}
|
|
|
|
func newReceivedPacketHandler(
|
|
sentPackets sentPacketTracker,
|
|
rttStats *utils.RTTStats,
|
|
logger utils.Logger,
|
|
version protocol.VersionNumber,
|
|
) ReceivedPacketHandler {
|
|
return &receivedPacketHandler{
|
|
sentPackets: sentPackets,
|
|
initialPackets: newReceivedPacketTracker(rttStats, logger, version),
|
|
handshakePackets: newReceivedPacketTracker(rttStats, logger, version),
|
|
appDataPackets: newReceivedPacketTracker(rttStats, logger, version),
|
|
lowest1RTTPacket: protocol.InvalidPacketNumber,
|
|
}
|
|
}
|
|
|
|
func (h *receivedPacketHandler) ReceivedPacket(
|
|
pn protocol.PacketNumber,
|
|
encLevel protocol.EncryptionLevel,
|
|
rcvTime time.Time,
|
|
shouldInstigateAck bool,
|
|
) error {
|
|
h.sentPackets.ReceivedPacket(encLevel)
|
|
switch encLevel {
|
|
case protocol.EncryptionInitial:
|
|
h.initialPackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck)
|
|
case protocol.EncryptionHandshake:
|
|
h.handshakePackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck)
|
|
case protocol.Encryption0RTT:
|
|
if h.lowest1RTTPacket != protocol.InvalidPacketNumber && pn > h.lowest1RTTPacket {
|
|
return fmt.Errorf("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet", pn, h.lowest1RTTPacket)
|
|
}
|
|
h.appDataPackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck)
|
|
case protocol.Encryption1RTT:
|
|
if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
|
|
h.lowest1RTTPacket = pn
|
|
}
|
|
h.appDataPackets.IgnoreBelow(h.sentPackets.GetLowestPacketNotConfirmedAcked())
|
|
h.appDataPackets.ReceivedPacket(pn, rcvTime, shouldInstigateAck)
|
|
default:
|
|
panic(fmt.Sprintf("received packet with unknown encryption level: %s", encLevel))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *receivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
|
switch encLevel {
|
|
case protocol.EncryptionInitial:
|
|
h.initialPackets = nil
|
|
case protocol.EncryptionHandshake:
|
|
h.handshakePackets = nil
|
|
case protocol.Encryption0RTT:
|
|
// Nothing to do here.
|
|
// If we are rejecting 0-RTT, no 0-RTT packets will have been decrypted.
|
|
default:
|
|
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
|
|
}
|
|
}
|
|
|
|
func (h *receivedPacketHandler) GetAlarmTimeout() time.Time {
|
|
var initialAlarm, handshakeAlarm time.Time
|
|
if h.initialPackets != nil {
|
|
initialAlarm = h.initialPackets.GetAlarmTimeout()
|
|
}
|
|
if h.handshakePackets != nil {
|
|
handshakeAlarm = h.handshakePackets.GetAlarmTimeout()
|
|
}
|
|
oneRTTAlarm := h.appDataPackets.GetAlarmTimeout()
|
|
return utils.MinNonZeroTime(utils.MinNonZeroTime(initialAlarm, handshakeAlarm), oneRTTAlarm)
|
|
}
|
|
|
|
func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel, onlyIfQueued bool) *wire.AckFrame {
|
|
var ack *wire.AckFrame
|
|
switch encLevel {
|
|
case protocol.EncryptionInitial:
|
|
if h.initialPackets != nil {
|
|
ack = h.initialPackets.GetAckFrame(onlyIfQueued)
|
|
}
|
|
case protocol.EncryptionHandshake:
|
|
if h.handshakePackets != nil {
|
|
ack = h.handshakePackets.GetAckFrame(onlyIfQueued)
|
|
}
|
|
case protocol.Encryption1RTT:
|
|
// 0-RTT packets can't contain ACK frames
|
|
return h.appDataPackets.GetAckFrame(onlyIfQueued)
|
|
default:
|
|
return nil
|
|
}
|
|
// For Initial and Handshake ACKs, the delay time is ignored by the receiver.
|
|
// Set it to 0 in order to save bytes.
|
|
if ack != nil {
|
|
ack.DelayTime = 0
|
|
}
|
|
return ack
|
|
}
|
|
|
|
func (h *receivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) bool {
|
|
switch encLevel {
|
|
case protocol.EncryptionInitial:
|
|
if h.initialPackets != nil {
|
|
return h.initialPackets.IsPotentiallyDuplicate(pn)
|
|
}
|
|
case protocol.EncryptionHandshake:
|
|
if h.handshakePackets != nil {
|
|
return h.handshakePackets.IsPotentiallyDuplicate(pn)
|
|
}
|
|
case protocol.Encryption0RTT, protocol.Encryption1RTT:
|
|
if h.appDataPackets != nil {
|
|
return h.appDataPackets.IsPotentiallyDuplicate(pn)
|
|
}
|
|
}
|
|
panic("unexpected encryption level")
|
|
}
|