forked from quic-go/quic-go
We used to reject duplicate and packets with packet numbers lower than the LeastUnacked we received in a STOP_WAITING frame, because we didn't accept overlapping stream data. For all other frames, duplicates never were an issue. Now that we accept overlapping stream data, there's no need to reject those packets, in fact, processing a delayed packet will be beneficial for performance.
151 lines
4.2 KiB
Go
151 lines
4.2 KiB
Go
package ackhandler
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go/frames"
|
|
"github.com/lucas-clemente/quic-go/protocol"
|
|
)
|
|
|
|
var errInvalidPacketNumber = errors.New("ReceivedPacketHandler: Invalid packet number")
|
|
|
|
type receivedPacketHandler struct {
|
|
largestObserved protocol.PacketNumber
|
|
ignorePacketsBelow protocol.PacketNumber
|
|
largestObservedReceivedTime time.Time
|
|
|
|
packetHistory *receivedPacketHistory
|
|
|
|
ackSendDelay time.Duration
|
|
|
|
packetsReceivedSinceLastAck int
|
|
retransmittablePacketsReceivedSinceLastAck int
|
|
ackQueued bool
|
|
ackAlarm time.Time
|
|
ackAlarmResetCallback func(time.Time)
|
|
lastAck *frames.AckFrame
|
|
}
|
|
|
|
// NewReceivedPacketHandler creates a new receivedPacketHandler
|
|
func NewReceivedPacketHandler(ackAlarmResetCallback func(time.Time)) ReceivedPacketHandler {
|
|
// create a stopped timer, see https://github.com/golang/go/issues/12721#issuecomment-143010182
|
|
timer := time.NewTimer(0)
|
|
<-timer.C
|
|
|
|
return &receivedPacketHandler{
|
|
packetHistory: newReceivedPacketHistory(),
|
|
ackAlarmResetCallback: ackAlarmResetCallback,
|
|
ackSendDelay: protocol.AckSendDelay,
|
|
}
|
|
}
|
|
|
|
func (h *receivedPacketHandler) ReceivedPacket(packetNumber protocol.PacketNumber, shouldInstigateAck bool) error {
|
|
if packetNumber == 0 {
|
|
return errInvalidPacketNumber
|
|
}
|
|
|
|
if packetNumber > h.ignorePacketsBelow {
|
|
if err := h.packetHistory.ReceivedPacket(packetNumber); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if packetNumber > h.largestObserved {
|
|
h.largestObserved = packetNumber
|
|
h.largestObservedReceivedTime = time.Now()
|
|
}
|
|
|
|
h.maybeQueueAck(packetNumber, shouldInstigateAck)
|
|
return nil
|
|
}
|
|
|
|
func (h *receivedPacketHandler) ReceivedStopWaiting(f *frames.StopWaitingFrame) error {
|
|
// ignore if StopWaiting is unneeded, because we already received a StopWaiting with a higher LeastUnacked
|
|
if h.ignorePacketsBelow >= f.LeastUnacked {
|
|
return nil
|
|
}
|
|
|
|
h.ignorePacketsBelow = f.LeastUnacked - 1
|
|
|
|
h.packetHistory.DeleteBelow(f.LeastUnacked)
|
|
return nil
|
|
}
|
|
|
|
func (h *receivedPacketHandler) maybeQueueAck(packetNumber protocol.PacketNumber, shouldInstigateAck bool) {
|
|
var ackAlarmSet bool
|
|
h.packetsReceivedSinceLastAck++
|
|
|
|
if shouldInstigateAck {
|
|
h.retransmittablePacketsReceivedSinceLastAck++
|
|
}
|
|
|
|
// always ack the first packet
|
|
if h.lastAck == nil {
|
|
h.ackQueued = true
|
|
}
|
|
|
|
// Always send an ack every 20 packets in order to allow the peer to discard
|
|
// information from the SentPacketManager and provide an RTT measurement.
|
|
if h.packetsReceivedSinceLastAck >= protocol.MaxPacketsReceivedBeforeAckSend {
|
|
h.ackQueued = true
|
|
}
|
|
|
|
// if the packet number is smaller than the largest acked packet, it must have been reported missing with the last ACK
|
|
// note that it cannot be a duplicate because they're already filtered out by ReceivedPacket()
|
|
if h.lastAck != nil && packetNumber < h.lastAck.LargestAcked {
|
|
h.ackQueued = true
|
|
}
|
|
|
|
// check if a new missing range above the previously was created
|
|
if h.lastAck != nil && h.packetHistory.GetHighestAckRange().FirstPacketNumber > h.lastAck.LargestAcked {
|
|
h.ackQueued = true
|
|
}
|
|
|
|
if !h.ackQueued && shouldInstigateAck {
|
|
if h.retransmittablePacketsReceivedSinceLastAck >= protocol.RetransmittablePacketsBeforeAck {
|
|
h.ackQueued = true
|
|
} else {
|
|
if h.ackAlarm.IsZero() {
|
|
h.ackAlarm = time.Now().Add(h.ackSendDelay)
|
|
ackAlarmSet = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if h.ackQueued {
|
|
// cancel the ack alarm
|
|
h.ackAlarm = time.Time{}
|
|
ackAlarmSet = false
|
|
}
|
|
|
|
if ackAlarmSet {
|
|
h.ackAlarmResetCallback(h.ackAlarm)
|
|
}
|
|
}
|
|
|
|
func (h *receivedPacketHandler) GetAckFrame() *frames.AckFrame {
|
|
if !h.ackQueued && (h.ackAlarm.IsZero() || h.ackAlarm.After(time.Now())) {
|
|
return nil
|
|
}
|
|
|
|
ackRanges := h.packetHistory.GetAckRanges()
|
|
ack := &frames.AckFrame{
|
|
LargestAcked: h.largestObserved,
|
|
LowestAcked: ackRanges[len(ackRanges)-1].FirstPacketNumber,
|
|
PacketReceivedTime: h.largestObservedReceivedTime,
|
|
}
|
|
|
|
if len(ackRanges) > 1 {
|
|
ack.AckRanges = ackRanges
|
|
}
|
|
|
|
h.lastAck = ack
|
|
h.ackAlarm = time.Time{}
|
|
h.ackQueued = false
|
|
h.packetsReceivedSinceLastAck = 0
|
|
h.retransmittablePacketsReceivedSinceLastAck = 0
|
|
|
|
return ack
|
|
}
|