forked from quic-go/quic-go
rename AckHandler package to AckHandlerLegacy
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCrypto(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "AckHandler Suite")
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import "github.com/lucas-clemente/quic-go/protocol"
|
||||
|
||||
// EntropyAccumulator accumulates the entropy according to the QUIC docs
|
||||
type EntropyAccumulator byte
|
||||
|
||||
// Add the contribution of the entropy flag of a given packet number
|
||||
func (e *EntropyAccumulator) Add(packetNumber protocol.PacketNumber, entropyFlag bool) {
|
||||
if entropyFlag {
|
||||
(*e) ^= 0x01 << (packetNumber % 8)
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract the contribution of the entropy flag of a given packet number
|
||||
func (e *EntropyAccumulator) Subtract(packetNumber protocol.PacketNumber, entropyFlag bool) {
|
||||
e.Add(packetNumber, entropyFlag)
|
||||
}
|
||||
|
||||
// Get the byte of entropy
|
||||
func (e *EntropyAccumulator) Get() byte {
|
||||
return byte(*e)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("EntropyAccumulator", func() {
|
||||
It("initializes as zero", func() {
|
||||
var e EntropyAccumulator
|
||||
Expect(e.Get()).To(BeZero())
|
||||
})
|
||||
|
||||
Context("Add", func() {
|
||||
It("adds entropy", func() {
|
||||
var e EntropyAccumulator
|
||||
e.Add(9, true)
|
||||
Expect(e.Get()).To(Equal(byte(0x02)))
|
||||
})
|
||||
|
||||
It("doesn't add entropy for zero entropy flags", func() {
|
||||
var e EntropyAccumulator
|
||||
e.Add(9, false)
|
||||
Expect(e.Get()).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Subtract", func() {
|
||||
It("calculates the correct entropy", func() {
|
||||
var e1 EntropyAccumulator
|
||||
e1.Add(3, true)
|
||||
|
||||
var e2 EntropyAccumulator
|
||||
e2.Add(1, true)
|
||||
e2.Add(3, true)
|
||||
e2.Subtract(1, true)
|
||||
|
||||
Expect(e1).To(Equal(e2))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,41 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
)
|
||||
|
||||
// SentPacketHandler handles ACKs received for outgoing packets
|
||||
type SentPacketHandler interface {
|
||||
SentPacket(packet *Packet) error
|
||||
ReceivedAck(ackFrame *frames.AckFrameLegacy) error
|
||||
|
||||
ProbablyHasPacketForRetransmission() bool
|
||||
DequeuePacketForRetransmission() (packet *Packet)
|
||||
|
||||
BytesInFlight() protocol.ByteCount
|
||||
GetLargestObserved() protocol.PacketNumber
|
||||
|
||||
CongestionAllowsSending() bool
|
||||
CheckForError() error
|
||||
|
||||
TimeOfFirstRTO() time.Time
|
||||
}
|
||||
|
||||
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
||||
type ReceivedPacketHandler interface {
|
||||
ReceivedPacket(packetNumber protocol.PacketNumber, entropyBit bool) error
|
||||
ReceivedStopWaiting(*frames.StopWaitingFrame) error
|
||||
|
||||
GetAckFrame(dequeue bool) (*frames.AckFrameLegacy, error)
|
||||
}
|
||||
|
||||
// StopWaitingManager manages StopWaitings for sent packets
|
||||
type StopWaitingManager interface {
|
||||
RegisterPacketForRetransmission(packet *Packet)
|
||||
GetStopWaitingFrame() *frames.StopWaitingFrame
|
||||
SentStopWaitingWithPacket(packetNumber protocol.PacketNumber)
|
||||
ReceivedAckForPacketNumber(packetNumber protocol.PacketNumber)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []frames.Frame
|
||||
EntropyBit bool
|
||||
Entropy EntropyAccumulator
|
||||
Length protocol.ByteCount
|
||||
|
||||
MissingReports uint8
|
||||
Retransmitted bool // has this Packet ever been retransmitted
|
||||
|
||||
sendTime time.Time
|
||||
}
|
||||
|
||||
// GetStreamFramesForRetransmission gets all the streamframes for retransmission
|
||||
func (p *Packet) GetStreamFramesForRetransmission() []*frames.StreamFrame {
|
||||
var streamFrames []*frames.StreamFrame
|
||||
for _, frame := range p.Frames {
|
||||
if streamFrame, isStreamFrame := frame.(*frames.StreamFrame); isStreamFrame {
|
||||
streamFrames = append(streamFrames, streamFrame)
|
||||
}
|
||||
}
|
||||
return streamFrames
|
||||
}
|
||||
|
||||
// GetControlFramesForRetransmission gets all the control frames for retransmission
|
||||
func (p *Packet) GetControlFramesForRetransmission() []frames.Frame {
|
||||
var controlFrames []frames.Frame
|
||||
for _, frame := range p.Frames {
|
||||
// omit ACKs
|
||||
if _, isStreamFrame := frame.(*frames.StreamFrame); isStreamFrame {
|
||||
continue
|
||||
}
|
||||
|
||||
_, isAck := frame.(*frames.AckFrameLegacy)
|
||||
_, isStopWaiting := frame.(*frames.StopWaitingFrame)
|
||||
if !isAck && !isStopWaiting {
|
||||
controlFrames = append(controlFrames, frame)
|
||||
}
|
||||
}
|
||||
return controlFrames
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Packet", func() {
|
||||
Context("getFramesForRetransmission", func() {
|
||||
var packet Packet
|
||||
var streamFrame1, streamFrame2 *frames.StreamFrame
|
||||
var ackFrame1, ackFrame2 *frames.AckFrameLegacy
|
||||
var stopWaitingFrame *frames.StopWaitingFrame
|
||||
var rstStreamFrame *frames.RstStreamFrame
|
||||
var windowUpdateFrame *frames.WindowUpdateFrame
|
||||
|
||||
BeforeEach(func() {
|
||||
streamFrame1 = &frames.StreamFrame{
|
||||
StreamID: 5,
|
||||
Data: []byte{0x13, 0x37},
|
||||
}
|
||||
streamFrame2 = &frames.StreamFrame{
|
||||
StreamID: 6,
|
||||
Data: []byte{0xDE, 0xCA, 0xFB, 0xAD},
|
||||
}
|
||||
ackFrame1 = &frames.AckFrameLegacy{
|
||||
LargestObserved: 13,
|
||||
Entropy: 5,
|
||||
}
|
||||
ackFrame2 = &frames.AckFrameLegacy{
|
||||
LargestObserved: 333,
|
||||
Entropy: 17,
|
||||
}
|
||||
rstStreamFrame = &frames.RstStreamFrame{
|
||||
StreamID: 555,
|
||||
ErrorCode: 1337,
|
||||
}
|
||||
stopWaitingFrame = &frames.StopWaitingFrame{
|
||||
LeastUnacked: 7331,
|
||||
Entropy: 10,
|
||||
}
|
||||
windowUpdateFrame = &frames.WindowUpdateFrame{
|
||||
StreamID: 999,
|
||||
}
|
||||
packet = Packet{
|
||||
PacketNumber: 1337,
|
||||
Frames: []frames.Frame{windowUpdateFrame, streamFrame1, ackFrame1, streamFrame2, rstStreamFrame, ackFrame2, stopWaitingFrame},
|
||||
}
|
||||
})
|
||||
|
||||
It("gets all StreamFrames", func() {
|
||||
streamFrames := packet.GetStreamFramesForRetransmission()
|
||||
Expect(streamFrames).To(HaveLen(2))
|
||||
Expect(streamFrames).To(ContainElement(streamFrame1))
|
||||
Expect(streamFrames).To(ContainElement(streamFrame2))
|
||||
})
|
||||
|
||||
It("gets all control frames", func() {
|
||||
controlFrames := packet.GetControlFramesForRetransmission()
|
||||
Expect(controlFrames).To(HaveLen(2))
|
||||
Expect(controlFrames).To(ContainElement(rstStreamFrame))
|
||||
Expect(controlFrames).To(ContainElement(windowUpdateFrame))
|
||||
})
|
||||
|
||||
It("does not return any ACK frames", func() {
|
||||
controlFrames := packet.GetControlFramesForRetransmission()
|
||||
Expect(controlFrames).ToNot(ContainElement(ackFrame1))
|
||||
Expect(controlFrames).ToNot(ContainElement(ackFrame2))
|
||||
})
|
||||
|
||||
It("does not return any ACK frames", func() {
|
||||
controlFrames := packet.GetControlFramesForRetransmission()
|
||||
Expect(controlFrames).ToNot(ContainElement(stopWaitingFrame))
|
||||
})
|
||||
|
||||
It("returns an empty slice of StreamFrames if no StreamFrames are queued", func() {
|
||||
// overwrite the globally defined packet here
|
||||
packet := Packet{
|
||||
PacketNumber: 1337,
|
||||
Frames: []frames.Frame{ackFrame1, rstStreamFrame},
|
||||
}
|
||||
streamFrames := packet.GetStreamFramesForRetransmission()
|
||||
Expect(streamFrames).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("returns an empty slice of control frames if no applicable control frames are queued", func() {
|
||||
// overwrite the globally defined packet here
|
||||
packet := Packet{
|
||||
PacketNumber: 1337,
|
||||
Frames: []frames.Frame{streamFrame1, ackFrame1, stopWaitingFrame},
|
||||
}
|
||||
controlFrames := packet.GetControlFramesForRetransmission()
|
||||
Expect(controlFrames).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,154 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
)
|
||||
|
||||
// ErrDuplicatePacket occurres when a duplicate packet is received
|
||||
var ErrDuplicatePacket = errors.New("ReceivedPacketHandler: Duplicate Packet")
|
||||
|
||||
var (
|
||||
errInvalidPacketNumber = errors.New("ReceivedPacketHandler: Invalid packet number")
|
||||
errTooManyOutstandingReceivedPackets = qerr.Error(qerr.TooManyOutstandingReceivedPackets, "")
|
||||
)
|
||||
|
||||
type packetHistoryEntry struct {
|
||||
EntropyBit bool
|
||||
TimeReceived time.Time
|
||||
}
|
||||
|
||||
type receivedPacketHandler struct {
|
||||
highestInOrderObserved protocol.PacketNumber
|
||||
highestInOrderObservedEntropy EntropyAccumulator
|
||||
largestObserved protocol.PacketNumber
|
||||
currentAckFrame *frames.AckFrameLegacy
|
||||
stateChanged bool // has an ACK for this state already been sent? Will be set to false every time a new packet arrives, and to false every time an ACK is sent
|
||||
|
||||
packetHistory map[protocol.PacketNumber]packetHistoryEntry
|
||||
smallestInPacketHistory protocol.PacketNumber
|
||||
}
|
||||
|
||||
// NewReceivedPacketHandler creates a new receivedPacketHandler
|
||||
func NewReceivedPacketHandler() ReceivedPacketHandler {
|
||||
return &receivedPacketHandler{
|
||||
packetHistory: make(map[protocol.PacketNumber]packetHistoryEntry),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) ReceivedPacket(packetNumber protocol.PacketNumber, entropyBit bool) error {
|
||||
if packetNumber == 0 {
|
||||
return errInvalidPacketNumber
|
||||
}
|
||||
_, ok := h.packetHistory[packetNumber]
|
||||
if packetNumber <= h.highestInOrderObserved || ok {
|
||||
return ErrDuplicatePacket
|
||||
}
|
||||
|
||||
h.stateChanged = true
|
||||
h.currentAckFrame = nil
|
||||
|
||||
if packetNumber > h.largestObserved {
|
||||
h.largestObserved = packetNumber
|
||||
}
|
||||
|
||||
if packetNumber == h.highestInOrderObserved+1 {
|
||||
h.highestInOrderObserved = packetNumber
|
||||
h.highestInOrderObservedEntropy.Add(packetNumber, entropyBit)
|
||||
}
|
||||
|
||||
h.packetHistory[packetNumber] = packetHistoryEntry{
|
||||
EntropyBit: entropyBit,
|
||||
TimeReceived: time.Now(),
|
||||
}
|
||||
|
||||
h.garbageCollect()
|
||||
|
||||
if uint32(len(h.packetHistory)) > protocol.MaxTrackedReceivedPackets {
|
||||
return errTooManyOutstandingReceivedPackets
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) ReceivedStopWaiting(f *frames.StopWaitingFrame) error {
|
||||
// Ignore if STOP_WAITING is unneeded
|
||||
if h.highestInOrderObserved >= f.LeastUnacked {
|
||||
return nil
|
||||
}
|
||||
|
||||
// the LeastUnacked is the smallest packet number of any packet for which the sender is still awaiting an ack. So the highestInOrderObserved is one less than that
|
||||
h.highestInOrderObserved = f.LeastUnacked - 1
|
||||
h.highestInOrderObservedEntropy = EntropyAccumulator(f.Entropy)
|
||||
|
||||
h.garbageCollect()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getNackRanges gets all the NACK ranges
|
||||
func (h *receivedPacketHandler) getNackRanges() ([]frames.NackRange, EntropyAccumulator) {
|
||||
// TODO: use a better data structure here
|
||||
var ranges []frames.NackRange
|
||||
inRange := false
|
||||
entropy := h.highestInOrderObservedEntropy
|
||||
for i := h.largestObserved; i > h.highestInOrderObserved; i-- {
|
||||
p, ok := h.packetHistory[i]
|
||||
if !ok {
|
||||
if !inRange {
|
||||
r := frames.NackRange{
|
||||
FirstPacketNumber: i,
|
||||
LastPacketNumber: i,
|
||||
}
|
||||
ranges = append(ranges, r)
|
||||
inRange = true
|
||||
} else {
|
||||
ranges[len(ranges)-1].FirstPacketNumber--
|
||||
}
|
||||
} else {
|
||||
inRange = false
|
||||
entropy.Add(i, p.EntropyBit)
|
||||
}
|
||||
}
|
||||
return ranges, entropy
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) GetAckFrame(dequeue bool) (*frames.AckFrameLegacy, error) {
|
||||
if !h.stateChanged {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if dequeue {
|
||||
h.stateChanged = false
|
||||
}
|
||||
|
||||
if h.currentAckFrame != nil {
|
||||
return h.currentAckFrame, nil
|
||||
}
|
||||
|
||||
p, ok := h.packetHistory[h.largestObserved]
|
||||
if !ok {
|
||||
return nil, ErrMapAccess
|
||||
}
|
||||
packetReceivedTime := p.TimeReceived
|
||||
|
||||
nackRanges, entropy := h.getNackRanges()
|
||||
h.currentAckFrame = &frames.AckFrameLegacy{
|
||||
LargestObserved: h.largestObserved,
|
||||
Entropy: byte(entropy),
|
||||
NackRanges: nackRanges,
|
||||
PacketReceivedTime: packetReceivedTime,
|
||||
}
|
||||
return h.currentAckFrame, nil
|
||||
}
|
||||
|
||||
func (h *receivedPacketHandler) garbageCollect() {
|
||||
for i := h.smallestInPacketHistory; i < h.highestInOrderObserved; i++ {
|
||||
delete(h.packetHistory, i)
|
||||
}
|
||||
h.smallestInPacketHistory = h.highestInOrderObserved
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("receivedPacketHandler", func() {
|
||||
var (
|
||||
handler *receivedPacketHandler
|
||||
expectedEntropy EntropyAccumulator
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
handler = NewReceivedPacketHandler().(*receivedPacketHandler)
|
||||
expectedEntropy = EntropyAccumulator(0)
|
||||
})
|
||||
|
||||
Context("accepting packets", func() {
|
||||
It("handles a packet that arrives late", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(3), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3)))
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(2), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
It("rejects packets with packet number 0", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(0), false)
|
||||
Expect(err).To(MatchError(errInvalidPacketNumber))
|
||||
})
|
||||
|
||||
It("rejects a duplicate package with PacketNumber equal to LargestObserved", func() {
|
||||
for i := 1; i < 5; i++ {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
err := handler.ReceivedPacket(4, false)
|
||||
Expect(err).To(MatchError(ErrDuplicatePacket))
|
||||
})
|
||||
|
||||
It("rejects a duplicate package with PacketNumber less than the LargestObserved", func() {
|
||||
for i := 1; i < 5; i++ {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
err := handler.ReceivedPacket(2, false)
|
||||
Expect(err).To(MatchError(ErrDuplicatePacket))
|
||||
})
|
||||
|
||||
It("saves the time when each packet arrived", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(3), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3)))
|
||||
Expect(handler.packetHistory[3].TimeReceived).To(BeTemporally("~", time.Now(), 10*time.Millisecond))
|
||||
})
|
||||
|
||||
It("doesn't store more than MaxTrackedReceivedPackets packets", func() {
|
||||
for i := uint32(0); i < protocol.MaxTrackedReceivedPackets; i++ {
|
||||
packetNumber := protocol.PacketNumber(1 + 2*i)
|
||||
err := handler.ReceivedPacket(packetNumber, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(3*protocol.MaxTrackedReceivedPackets), true)
|
||||
Expect(err).To(MatchError(errTooManyOutstandingReceivedPackets))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Entropy calculation", func() {
|
||||
It("calculates the entropy for continously received packets", func() {
|
||||
for i := 1; i < 100; i++ {
|
||||
entropyBit := false
|
||||
if i%3 == 0 || i%5 == 0 {
|
||||
entropyBit = true
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.highestInOrderObservedEntropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
|
||||
It("calculates the entropy if there is a NACK range", func() {
|
||||
for i := 1; i < 100; i++ {
|
||||
entropyBit := false
|
||||
if i%3 == 0 || i%5 == 0 {
|
||||
entropyBit = true
|
||||
}
|
||||
|
||||
if i == 10 || i == 11 || i == 12 {
|
||||
continue
|
||||
}
|
||||
if i < 10 {
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
}
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.highestInOrderObservedEntropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
})
|
||||
|
||||
Context("NACK range calculation", func() {
|
||||
It("Returns no NACK ranges for continously received packets", func() {
|
||||
for i := 1; i < 100; i++ {
|
||||
entropyBit := false
|
||||
if i%2 == 0 {
|
||||
entropyBit = true
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(99)))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(99)))
|
||||
nackRanges, entropy := handler.getNackRanges()
|
||||
Expect(nackRanges).To(BeEmpty())
|
||||
Expect(entropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
|
||||
It("handles a single lost package", func() {
|
||||
for i := 1; i < 10; i++ {
|
||||
entropyBit := true
|
||||
if i == 5 {
|
||||
continue
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(9)))
|
||||
nackRanges, entropy := handler.getNackRanges()
|
||||
Expect(nackRanges).To(HaveLen(1))
|
||||
Expect(nackRanges[0]).To(Equal(frames.NackRange{FirstPacketNumber: 5, LastPacketNumber: 5}))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(4)))
|
||||
Expect(entropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
|
||||
It("handles two consecutive lost packages", func() {
|
||||
for i := 1; i < 12; i++ {
|
||||
entropyBit := false
|
||||
if i%2 == 0 || i == 5 {
|
||||
entropyBit = true
|
||||
}
|
||||
if i == 5 || i == 6 {
|
||||
continue
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(11)))
|
||||
nackRanges, entropy := handler.getNackRanges()
|
||||
Expect(nackRanges).To(HaveLen(1))
|
||||
Expect(nackRanges[0]).To(Equal(frames.NackRange{FirstPacketNumber: 5, LastPacketNumber: 6}))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(4)))
|
||||
Expect(entropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
|
||||
It("handles two non-consecutively lost packages", func() {
|
||||
for i := 1; i < 10; i++ {
|
||||
entropyBit := false
|
||||
if i%2 != 0 {
|
||||
entropyBit = true
|
||||
}
|
||||
if i == 3 || i == 7 {
|
||||
continue
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(9)))
|
||||
nackRanges, entropy := handler.getNackRanges()
|
||||
Expect(nackRanges).To(HaveLen(2))
|
||||
Expect(nackRanges[0]).To(Equal(frames.NackRange{FirstPacketNumber: 7, LastPacketNumber: 7}))
|
||||
Expect(nackRanges[1]).To(Equal(frames.NackRange{FirstPacketNumber: 3, LastPacketNumber: 3}))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(entropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
|
||||
It("handles two sequences of lost packages", func() {
|
||||
for i := 1; i < 10; i++ {
|
||||
entropyBit := true
|
||||
if i == 2 || i == 3 || i == 4 || i == 7 || i == 8 {
|
||||
continue
|
||||
}
|
||||
expectedEntropy.Add(protocol.PacketNumber(i), entropyBit)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.largestObserved).To(Equal(protocol.PacketNumber(9)))
|
||||
nackRanges, entropy := handler.getNackRanges()
|
||||
Expect(nackRanges).To(HaveLen(2))
|
||||
Expect(nackRanges[0]).To(Equal(frames.NackRange{FirstPacketNumber: 7, LastPacketNumber: 8}))
|
||||
Expect(nackRanges[1]).To(Equal(frames.NackRange{FirstPacketNumber: 2, LastPacketNumber: 4}))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(entropy).To(Equal(expectedEntropy))
|
||||
})
|
||||
})
|
||||
|
||||
Context("handling STOP_WAITING frames", func() {
|
||||
It("resets the entropy", func() {
|
||||
// We simulate 20 packets, numbers 10, 11 and 12 lost
|
||||
expectedAfterStopWaiting := EntropyAccumulator(0)
|
||||
for i := 1; i < 20; i++ {
|
||||
entropyBit := false
|
||||
if i%3 == 0 || i%5 == 0 {
|
||||
entropyBit = true
|
||||
}
|
||||
|
||||
if i == 10 || i == 11 || i == 12 {
|
||||
continue
|
||||
}
|
||||
if i > 12 {
|
||||
expectedAfterStopWaiting.Add(protocol.PacketNumber(i), entropyBit)
|
||||
}
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(i), entropyBit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
err := handler.ReceivedStopWaiting(&frames.StopWaitingFrame{Entropy: 42, LeastUnacked: protocol.PacketNumber(12)})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, e := handler.getNackRanges()
|
||||
Expect(e).To(Equal(42 ^ expectedAfterStopWaiting))
|
||||
Expect(handler.highestInOrderObserved).To(Equal(protocol.PacketNumber(11)))
|
||||
Expect(handler.highestInOrderObservedEntropy).To(Equal(EntropyAccumulator(42)))
|
||||
})
|
||||
|
||||
It("does not emit NACK ranges after STOP_WAITING", func() {
|
||||
err := handler.ReceivedPacket(10, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ranges, _ := handler.getNackRanges()
|
||||
Expect(ranges).To(HaveLen(1))
|
||||
err = handler.ReceivedStopWaiting(&frames.StopWaitingFrame{Entropy: 0, LeastUnacked: protocol.PacketNumber(10)})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ranges, _ = handler.getNackRanges()
|
||||
Expect(ranges).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Context("ACK package generation", func() {
|
||||
It("generates a simple ACK frame", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(1, true)
|
||||
entropy.Add(2, true)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(2), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, err := handler.GetAckFrame(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack.LargestObserved).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(ack.Entropy).To(Equal(byte(entropy)))
|
||||
})
|
||||
|
||||
It("generates an ACK frame with a NACK range", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(1, true)
|
||||
entropy.Add(4, true)
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(4), true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, err := handler.GetAckFrame(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack.LargestObserved).To(Equal(protocol.PacketNumber(4)))
|
||||
Expect(ack.Entropy).To(Equal(byte(entropy)))
|
||||
Expect(ack.NackRanges).To(Equal([]frames.NackRange{{FirstPacketNumber: 2, LastPacketNumber: 3}}))
|
||||
})
|
||||
|
||||
It("does not generate an ACK if an ACK has already been sent for the largest Packet", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(2), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, err := handler.GetAckFrame(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).ToNot(BeNil())
|
||||
ack, err = handler.GetAckFrame(true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).To(BeNil())
|
||||
})
|
||||
|
||||
It("does not dequeue an ACK frame if told so", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(2), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, err := handler.GetAckFrame(false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).ToNot(BeNil())
|
||||
ack, err = handler.GetAckFrame(false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).ToNot(BeNil())
|
||||
ack, err = handler.GetAckFrame(false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("returns a cached ACK frame if the ACK was not dequeued", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(2), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, err := handler.GetAckFrame(false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack).ToNot(BeNil())
|
||||
ack2, err := handler.GetAckFrame(false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ack2).ToNot(BeNil())
|
||||
Expect(&ack).To(Equal(&ack2))
|
||||
})
|
||||
|
||||
It("generates a new ACK (and deletes the cached one) when a new packet arrives", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, _ := handler.GetAckFrame(true)
|
||||
Expect(ack).ToNot(BeNil())
|
||||
Expect(ack.LargestObserved).To(Equal(protocol.PacketNumber(1)))
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(3), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, _ = handler.GetAckFrame(true)
|
||||
Expect(ack).ToNot(BeNil())
|
||||
Expect(ack.LargestObserved).To(Equal(protocol.PacketNumber(3)))
|
||||
})
|
||||
|
||||
It("generates a new ACK when an out-of-order packet arrives", func() {
|
||||
err := handler.ReceivedPacket(protocol.PacketNumber(1), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(3), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, _ := handler.GetAckFrame(true)
|
||||
Expect(ack).ToNot(BeNil())
|
||||
Expect(ack.NackRanges).To(HaveLen(1))
|
||||
err = handler.ReceivedPacket(protocol.PacketNumber(2), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ack, _ = handler.GetAckFrame(true)
|
||||
Expect(ack).ToNot(BeNil())
|
||||
Expect(ack.NackRanges).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Garbage Collector", func() {
|
||||
It("only keeps packets with packet numbers higher than the highestInOrderObserved in packetHistory", func() {
|
||||
handler.ReceivedPacket(1, true)
|
||||
handler.ReceivedPacket(2, true)
|
||||
handler.ReceivedPacket(4, true)
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(4)))
|
||||
})
|
||||
|
||||
It("garbage collects packetHistory after receiving a StopWaiting", func() {
|
||||
handler.ReceivedPacket(1, true)
|
||||
handler.ReceivedPacket(2, true)
|
||||
handler.ReceivedPacket(4, true)
|
||||
swf := frames.StopWaitingFrame{LeastUnacked: 4}
|
||||
handler.ReceivedStopWaiting(&swf)
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(4)))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,339 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/congestion"
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrDuplicateOrOutOfOrderAck occurs when a duplicate or an out-of-order ACK is received
|
||||
ErrDuplicateOrOutOfOrderAck = errors.New("SentPacketHandler: Duplicate or out-of-order ACK")
|
||||
// ErrEntropy occurs when an ACK with incorrect entropy is received
|
||||
ErrEntropy = qerr.Error(qerr.InvalidAckData, "wrong entropy")
|
||||
// ErrMapAccess occurs when a NACK contains invalid NACK ranges
|
||||
ErrMapAccess = qerr.Error(qerr.InvalidAckData, "Packet does not exist in PacketHistory")
|
||||
// ErrTooManyTrackedSentPackets occurs when the sentPacketHandler has to keep track of too many packets
|
||||
ErrTooManyTrackedSentPackets = errors.New("Too many outstanding non-acked and non-retransmitted packets")
|
||||
errAckForUnsentPacket = qerr.Error(qerr.InvalidAckData, "Received ACK for an unsent package")
|
||||
)
|
||||
|
||||
var (
|
||||
errDuplicatePacketNumber = errors.New("Packet number already exists in Packet History")
|
||||
errWrongPacketNumberIncrement = errors.New("Packet number must be increased by exactly 1")
|
||||
)
|
||||
|
||||
type sentPacketHandler struct {
|
||||
lastSentPacketNumber protocol.PacketNumber
|
||||
lastSentPacketEntropy EntropyAccumulator
|
||||
lastSentPacketTime time.Time
|
||||
highestInOrderAckedPacketNumber protocol.PacketNumber
|
||||
LargestObserved protocol.PacketNumber
|
||||
LargestObservedEntropy EntropyAccumulator
|
||||
|
||||
// TODO: Move into separate class as in chromium
|
||||
packetHistory map[protocol.PacketNumber]*Packet
|
||||
|
||||
retransmissionQueue []*Packet
|
||||
stopWaitingManager StopWaitingManager
|
||||
|
||||
bytesInFlight protocol.ByteCount
|
||||
|
||||
rttStats *congestion.RTTStats
|
||||
congestion congestion.SendAlgorithm
|
||||
}
|
||||
|
||||
// NewSentPacketHandler creates a new sentPacketHandler
|
||||
func NewSentPacketHandler(stopWaitingManager StopWaitingManager) SentPacketHandler {
|
||||
rttStats := &congestion.RTTStats{}
|
||||
|
||||
congestion := congestion.NewCubicSender(
|
||||
congestion.DefaultClock{},
|
||||
rttStats,
|
||||
false, /* don't use reno since chromium doesn't (why?) */
|
||||
protocol.InitialCongestionWindow,
|
||||
protocol.DefaultMaxCongestionWindow,
|
||||
)
|
||||
|
||||
return &sentPacketHandler{
|
||||
packetHistory: make(map[protocol.PacketNumber]*Packet),
|
||||
stopWaitingManager: stopWaitingManager,
|
||||
rttStats: rttStats,
|
||||
congestion: congestion,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ackPacket(packetNumber protocol.PacketNumber) *Packet {
|
||||
packet, ok := h.packetHistory[packetNumber]
|
||||
if ok && !packet.Retransmitted {
|
||||
h.bytesInFlight -= packet.Length
|
||||
}
|
||||
delete(h.packetHistory, packetNumber)
|
||||
|
||||
h.stopWaitingManager.ReceivedAckForPacketNumber(packetNumber)
|
||||
|
||||
return packet
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) nackPacket(packetNumber protocol.PacketNumber) (*Packet, error) {
|
||||
packet, ok := h.packetHistory[packetNumber]
|
||||
if !ok {
|
||||
return nil, ErrMapAccess
|
||||
}
|
||||
|
||||
// If the packet has already been retransmitted, do nothing.
|
||||
// We're probably only receiving another NACK for this packet because the
|
||||
// retransmission has not yet arrived at the client.
|
||||
if packet.Retransmitted {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
packet.MissingReports++
|
||||
|
||||
if packet.MissingReports > protocol.RetransmissionThreshold {
|
||||
h.queuePacketForRetransmission(packet)
|
||||
return packet, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) queuePacketForRetransmission(packet *Packet) {
|
||||
h.bytesInFlight -= packet.Length
|
||||
h.retransmissionQueue = append(h.retransmissionQueue, packet)
|
||||
packet.Retransmitted = true
|
||||
|
||||
// TODO: delete from packetHistory once we drop support for version smaller than QUIC 33
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SentPacket(packet *Packet) error {
|
||||
_, ok := h.packetHistory[packet.PacketNumber]
|
||||
if ok {
|
||||
return errDuplicatePacketNumber
|
||||
}
|
||||
if h.lastSentPacketNumber+1 != packet.PacketNumber {
|
||||
return errWrongPacketNumberIncrement
|
||||
}
|
||||
now := time.Now()
|
||||
h.lastSentPacketTime = now
|
||||
packet.sendTime = now
|
||||
if packet.Length == 0 {
|
||||
return errors.New("SentPacketHandler: packet cannot be empty")
|
||||
}
|
||||
h.bytesInFlight += packet.Length
|
||||
|
||||
h.lastSentPacketEntropy.Add(packet.PacketNumber, packet.EntropyBit)
|
||||
packet.Entropy = h.lastSentPacketEntropy
|
||||
h.lastSentPacketNumber = packet.PacketNumber
|
||||
h.packetHistory[packet.PacketNumber] = packet
|
||||
|
||||
h.congestion.OnPacketSent(
|
||||
time.Now(),
|
||||
h.BytesInFlight(),
|
||||
packet.PacketNumber,
|
||||
packet.Length,
|
||||
true, /* TODO: is retransmittable */
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) calculateExpectedEntropy(ackFrame *frames.AckFrameLegacy) (EntropyAccumulator, error) {
|
||||
packet, ok := h.packetHistory[ackFrame.LargestObserved]
|
||||
if !ok {
|
||||
return 0, ErrMapAccess
|
||||
}
|
||||
expectedEntropy := packet.Entropy
|
||||
|
||||
if ackFrame.HasNACK() { // if the packet has NACKs, the entropy value has to be calculated
|
||||
nackRangeIndex := 0
|
||||
nackRange := ackFrame.NackRanges[nackRangeIndex]
|
||||
for i := ackFrame.LargestObserved; i > ackFrame.GetHighestInOrderPacketNumber(); i-- {
|
||||
if i < nackRange.FirstPacketNumber {
|
||||
nackRangeIndex++
|
||||
if nackRangeIndex < len(ackFrame.NackRanges) {
|
||||
nackRange = ackFrame.NackRanges[nackRangeIndex]
|
||||
}
|
||||
}
|
||||
if nackRange.ContainsPacketNumber(i) {
|
||||
packet, ok := h.packetHistory[i]
|
||||
if !ok {
|
||||
return 0, ErrMapAccess
|
||||
}
|
||||
expectedEntropy.Subtract(i, packet.EntropyBit)
|
||||
}
|
||||
}
|
||||
}
|
||||
return expectedEntropy, nil
|
||||
}
|
||||
|
||||
// TODO: Simplify return types
|
||||
func (h *sentPacketHandler) ReceivedAck(ackFrame *frames.AckFrameLegacy) error {
|
||||
if ackFrame.LargestObserved > h.lastSentPacketNumber {
|
||||
return errAckForUnsentPacket
|
||||
}
|
||||
|
||||
if ackFrame.LargestObserved <= h.LargestObserved { // duplicate or out-of-order AckFrame
|
||||
return ErrDuplicateOrOutOfOrderAck
|
||||
}
|
||||
|
||||
expectedEntropy, err := h.calculateExpectedEntropy(ackFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if byte(expectedEntropy) != ackFrame.Entropy {
|
||||
return ErrEntropy
|
||||
}
|
||||
|
||||
// Entropy ok. Now actually process the ACK packet
|
||||
h.LargestObserved = ackFrame.LargestObserved
|
||||
highestInOrderAckedPacketNumber := ackFrame.GetHighestInOrderPacketNumber()
|
||||
|
||||
// Update the RTT
|
||||
timeDelta := time.Now().Sub(h.packetHistory[h.LargestObserved].sendTime)
|
||||
// TODO: Don't always update RTT
|
||||
h.rttStats.UpdateRTT(timeDelta, ackFrame.DelayTime, time.Now())
|
||||
if utils.Debug() {
|
||||
utils.Debugf("\tEstimated RTT: %dms", h.rttStats.SmoothedRTT()/time.Millisecond)
|
||||
}
|
||||
|
||||
var ackedPackets congestion.PacketVector
|
||||
var lostPackets congestion.PacketVector
|
||||
|
||||
// ACK all packets below the highestInOrderAckedPacketNumber
|
||||
for i := h.highestInOrderAckedPacketNumber; i <= highestInOrderAckedPacketNumber; i++ {
|
||||
p := h.ackPacket(i)
|
||||
if p != nil {
|
||||
ackedPackets = append(ackedPackets, congestion.PacketInfo{Number: p.PacketNumber, Length: p.Length})
|
||||
}
|
||||
}
|
||||
|
||||
if ackFrame.HasNACK() {
|
||||
nackRangeIndex := 0
|
||||
nackRange := ackFrame.NackRanges[nackRangeIndex]
|
||||
for i := ackFrame.LargestObserved; i > ackFrame.GetHighestInOrderPacketNumber(); i-- {
|
||||
if i < nackRange.FirstPacketNumber {
|
||||
nackRangeIndex++
|
||||
if nackRangeIndex < len(ackFrame.NackRanges) {
|
||||
nackRange = ackFrame.NackRanges[nackRangeIndex]
|
||||
}
|
||||
}
|
||||
if nackRange.ContainsPacketNumber(i) {
|
||||
p, err := h.nackPacket(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if p != nil {
|
||||
lostPackets = append(lostPackets, congestion.PacketInfo{Number: p.PacketNumber, Length: p.Length})
|
||||
}
|
||||
} else {
|
||||
p := h.ackPacket(i)
|
||||
if p != nil {
|
||||
ackedPackets = append(ackedPackets, congestion.PacketInfo{Number: p.PacketNumber, Length: p.Length})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h.highestInOrderAckedPacketNumber = highestInOrderAckedPacketNumber
|
||||
|
||||
h.congestion.OnCongestionEvent(
|
||||
true, /* TODO: rtt updated */
|
||||
h.BytesInFlight(),
|
||||
ackedPackets,
|
||||
lostPackets,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProbablyHasPacketForRetransmission returns if there is a packet queued for retransmission
|
||||
// There is one case where it gets the answer wrong:
|
||||
// if a packet has already been queued for retransmission, but a belated ACK is received for this packet, this function will return true, although the packet will not be returend for retransmission by DequeuePacketForRetransmission()
|
||||
func (h *sentPacketHandler) ProbablyHasPacketForRetransmission() bool {
|
||||
h.maybeQueuePacketsRTO()
|
||||
|
||||
return len(h.retransmissionQueue) > 0
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) DequeuePacketForRetransmission() (packet *Packet) {
|
||||
if !h.ProbablyHasPacketForRetransmission() {
|
||||
return nil
|
||||
}
|
||||
|
||||
for len(h.retransmissionQueue) > 0 {
|
||||
queueLen := len(h.retransmissionQueue)
|
||||
// packets are usually NACKed in descending order. So use the slice as a stack
|
||||
packet = h.retransmissionQueue[queueLen-1]
|
||||
h.retransmissionQueue = h.retransmissionQueue[:queueLen-1]
|
||||
|
||||
// check if the packet was ACKed after it was already queued for retransmission
|
||||
// if so, it doesn't exist in the packetHistory anymore. Skip it then
|
||||
_, ok := h.packetHistory[packet.PacketNumber]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
return packet
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) BytesInFlight() protocol.ByteCount {
|
||||
return h.bytesInFlight
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) GetLargestObserved() protocol.PacketNumber {
|
||||
return h.LargestObserved
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) CongestionAllowsSending() bool {
|
||||
return h.BytesInFlight() <= h.congestion.GetCongestionWindow()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) CheckForError() error {
|
||||
length := len(h.retransmissionQueue) + len(h.packetHistory)
|
||||
if uint32(length) > protocol.MaxTrackedSentPackets {
|
||||
return ErrTooManyTrackedSentPackets
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) maybeQueuePacketsRTO() {
|
||||
if time.Now().Before(h.TimeOfFirstRTO()) {
|
||||
return
|
||||
}
|
||||
for p := h.highestInOrderAckedPacketNumber + 1; p <= h.lastSentPacketNumber; p++ {
|
||||
packet := h.packetHistory[p]
|
||||
if packet != nil && !packet.Retransmitted {
|
||||
packetsLost := congestion.PacketVector{congestion.PacketInfo{
|
||||
Number: packet.PacketNumber,
|
||||
Length: packet.Length,
|
||||
}}
|
||||
h.congestion.OnCongestionEvent(false, h.BytesInFlight(), nil, packetsLost)
|
||||
h.congestion.OnRetransmissionTimeout(true)
|
||||
h.queuePacketForRetransmission(packet)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) getRTO() time.Duration {
|
||||
rto := h.congestion.RetransmissionDelay()
|
||||
if rto == 0 {
|
||||
rto = protocol.DefaultRetransmissionTime
|
||||
}
|
||||
return utils.MaxDuration(rto, protocol.MinRetransmissionTime)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) TimeOfFirstRTO() time.Time {
|
||||
if h.lastSentPacketTime.IsZero() {
|
||||
return time.Time{}
|
||||
}
|
||||
return h.lastSentPacketTime.Add(h.getRTO())
|
||||
}
|
||||
@@ -1,735 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/congestion"
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
type mockCongestion struct {
|
||||
nCalls int
|
||||
argsOnPacketSent []interface{}
|
||||
argsOnCongestionEvent []interface{}
|
||||
onRetransmissionTimeout bool
|
||||
}
|
||||
|
||||
func (m *mockCongestion) TimeUntilSend(now time.Time, bytesInFlight protocol.ByteCount) time.Duration {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (m *mockCongestion) OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool) bool {
|
||||
m.nCalls++
|
||||
m.argsOnPacketSent = []interface{}{sentTime, bytesInFlight, packetNumber, bytes, isRetransmittable}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *mockCongestion) GetCongestionWindow() protocol.ByteCount {
|
||||
m.nCalls++
|
||||
return protocol.DefaultTCPMSS
|
||||
}
|
||||
|
||||
func (m *mockCongestion) OnCongestionEvent(rttUpdated bool, bytesInFlight protocol.ByteCount, ackedPackets congestion.PacketVector, lostPackets congestion.PacketVector) {
|
||||
m.nCalls++
|
||||
m.argsOnCongestionEvent = []interface{}{rttUpdated, bytesInFlight, ackedPackets, lostPackets}
|
||||
}
|
||||
|
||||
func (m *mockCongestion) OnRetransmissionTimeout(packetsRetransmitted bool) {
|
||||
m.nCalls++
|
||||
m.onRetransmissionTimeout = true
|
||||
}
|
||||
|
||||
func (m *mockCongestion) RetransmissionDelay() time.Duration {
|
||||
return protocol.DefaultRetransmissionTime
|
||||
}
|
||||
|
||||
func (m *mockCongestion) SetNumEmulatedConnections(n int) { panic("not implemented") }
|
||||
func (m *mockCongestion) OnConnectionMigration() { panic("not implemented") }
|
||||
func (m *mockCongestion) SetSlowStartLargeReduction(enabled bool) { panic("not implemented") }
|
||||
|
||||
type mockStopWaiting struct {
|
||||
receivedAckForPacketNumber protocol.PacketNumber
|
||||
}
|
||||
|
||||
func (m *mockStopWaiting) RegisterPacketForRetransmission(packet *Packet) { panic("not implemented") }
|
||||
func (m *mockStopWaiting) GetStopWaitingFrame() *frames.StopWaitingFrame { panic("not implemented") }
|
||||
func (m *mockStopWaiting) SentStopWaitingWithPacket(packetNumber protocol.PacketNumber) {
|
||||
panic("not implemented")
|
||||
}
|
||||
func (m *mockStopWaiting) ReceivedAckForPacketNumber(packetNumber protocol.PacketNumber) {
|
||||
m.receivedAckForPacketNumber = packetNumber
|
||||
}
|
||||
|
||||
var _ = Describe("SentPacketHandler", func() {
|
||||
var (
|
||||
handler *sentPacketHandler
|
||||
streamFrame frames.StreamFrame
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
stopWaitingManager := &mockStopWaiting{}
|
||||
handler = NewSentPacketHandler(stopWaitingManager).(*sentPacketHandler)
|
||||
streamFrame = frames.StreamFrame{
|
||||
StreamID: 5,
|
||||
Data: []byte{0x13, 0x37},
|
||||
}
|
||||
})
|
||||
|
||||
It("informs the StopWaitingManager about ACKs received", func() {
|
||||
handler.ackPacket(2)
|
||||
Expect(handler.stopWaitingManager.(*mockStopWaiting).receivedAckForPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
Context("SentPacket", func() {
|
||||
It("accepts two consecutive packets", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
packet2 := Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 2}
|
||||
err := handler.SentPacket(&packet1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.SentPacket(&packet2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(2)))
|
||||
entropy.Add(packet1.PacketNumber, packet1.EntropyBit)
|
||||
Expect(handler.packetHistory[1].PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory[1].Entropy).To(Equal(entropy))
|
||||
entropy.Add(packet2.PacketNumber, packet2.EntropyBit)
|
||||
Expect(handler.packetHistory[2].PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory[2].Entropy).To(Equal(entropy))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
})
|
||||
|
||||
It("rejects packets with the same packet number", func() {
|
||||
packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
packet2 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 2}
|
||||
err := handler.SentPacket(&packet1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.SentPacket(&packet2)
|
||||
Expect(err).To(MatchError(errDuplicatePacketNumber))
|
||||
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(1)))
|
||||
})
|
||||
|
||||
It("rejects non-consecutive packets", func() {
|
||||
packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
packet2 := Packet{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 2}
|
||||
err := handler.SentPacket(&packet1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.SentPacket(&packet2)
|
||||
Expect(err).To(MatchError(errWrongPacketNumberIncrement))
|
||||
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(1)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(1)))
|
||||
})
|
||||
|
||||
It("correctly calculates the entropy, even if the last packet has already been ACKed", func() {
|
||||
packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
packet2 := Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 2}
|
||||
err := handler.SentPacket(&packet1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(1)))
|
||||
entropy := EntropyAccumulator(0)
|
||||
entropy.Add(packet1.PacketNumber, packet1.EntropyBit)
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: 1,
|
||||
Entropy: byte(entropy),
|
||||
}
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(0)))
|
||||
err = handler.SentPacket(&packet2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(handler.lastSentPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
entropy.Add(packet2.PacketNumber, packet2.EntropyBit)
|
||||
Expect(handler.packetHistory[2].Entropy).To(Equal(entropy))
|
||||
})
|
||||
|
||||
It("stores the sent time", func() {
|
||||
packet := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
err := handler.SentPacket(&packet)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.packetHistory[1].sendTime.Unix()).To(BeNumerically("~", time.Now().Unix(), 1))
|
||||
})
|
||||
|
||||
It("updates the last sent time", func() {
|
||||
packet := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1}
|
||||
err := handler.SentPacket(&packet)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.lastSentPacketTime.Unix()).To(BeNumerically("~", time.Now().Unix(), 1))
|
||||
})
|
||||
})
|
||||
|
||||
Context("DOS mitigation", func() {
|
||||
It("checks the size of the packet history, for unacked packets", func() {
|
||||
for i := uint32(1); i < protocol.MaxTrackedSentPackets+10; i++ {
|
||||
packet := Packet{PacketNumber: protocol.PacketNumber(i), Frames: []frames.Frame{&streamFrame}, Length: 1}
|
||||
err := handler.SentPacket(&packet)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
err := handler.CheckForError()
|
||||
Expect(err).To(MatchError(ErrTooManyTrackedSentPackets))
|
||||
})
|
||||
|
||||
// TODO: add a test that the length of the retransmission queue is considered, even if packets have already been ACKed. Relevant once we drop support for QUIC 33 and earlier
|
||||
})
|
||||
|
||||
Context("ACK entropy calculations", func() {
|
||||
var packets []*Packet
|
||||
var entropy EntropyAccumulator
|
||||
|
||||
BeforeEach(func() {
|
||||
entropy = EntropyAccumulator(0)
|
||||
packets = []*Packet{
|
||||
{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: true, Length: 1},
|
||||
}
|
||||
for _, packet := range packets {
|
||||
handler.SentPacket(packet)
|
||||
}
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
|
||||
It("no NACK ranges", func() {
|
||||
largestObserved := 5
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
ack := frames.AckFrameLegacy{LargestObserved: protocol.PacketNumber(largestObserved)}
|
||||
calculatedEntropy, err := handler.calculateExpectedEntropy(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(calculatedEntropy).To(Equal(entropy))
|
||||
})
|
||||
|
||||
It("one NACK ranges", func() {
|
||||
largestObserved := 5
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
if i == 2 || i == 3 { // skip Packet 3 and 4
|
||||
continue
|
||||
}
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
NackRanges: []frames.NackRange{{FirstPacketNumber: 3, LastPacketNumber: 4}},
|
||||
}
|
||||
calculatedEntropy, err := handler.calculateExpectedEntropy(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(calculatedEntropy).To(Equal(entropy))
|
||||
})
|
||||
|
||||
It("one NACK ranges, when some packages have already been ACKed", func() {
|
||||
largestObserved := 6
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
if i == 2 || i == 3 { // skip Packet 3 and 4
|
||||
continue
|
||||
}
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
handler.ackPacket(1)
|
||||
handler.ackPacket(2)
|
||||
handler.ackPacket(5)
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
NackRanges: []frames.NackRange{{FirstPacketNumber: 3, LastPacketNumber: 4}},
|
||||
}
|
||||
calculatedEntropy, err := handler.calculateExpectedEntropy(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(calculatedEntropy).To(Equal(entropy))
|
||||
})
|
||||
|
||||
It("multiple NACK ranges", func() {
|
||||
largestObserved := 5
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
if i == 1 || i == 3 { // skip Packet 2 and 4
|
||||
continue
|
||||
}
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
NackRanges: []frames.NackRange{
|
||||
{FirstPacketNumber: 4, LastPacketNumber: 4},
|
||||
{FirstPacketNumber: 2, LastPacketNumber: 2},
|
||||
},
|
||||
}
|
||||
calculatedEntropy, err := handler.calculateExpectedEntropy(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(calculatedEntropy).To(Equal(entropy))
|
||||
})
|
||||
|
||||
It("actually rejects an ACK with the wrong entropy", func() {
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: 4,
|
||||
Entropy: 1,
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).To(MatchError(ErrEntropy))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
|
||||
It("completely processes an ACK without a NACK range", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
largestObserved := 4
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
Entropy: byte(entropy),
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved)))
|
||||
Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(largestObserved)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(largestObserved - 1)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(largestObserved + 1)))
|
||||
})
|
||||
|
||||
It("completely processes an ACK with a NACK range", func() {
|
||||
entropy := EntropyAccumulator(0)
|
||||
largestObserved := 6
|
||||
for i := 0; i < largestObserved; i++ {
|
||||
if i == 2 || i == 4 { // Packet Number 3 and 5 missing
|
||||
continue
|
||||
}
|
||||
entropy.Add(packets[i].PacketNumber, packets[i].EntropyBit)
|
||||
}
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
Entropy: byte(entropy),
|
||||
NackRanges: []frames.NackRange{
|
||||
{FirstPacketNumber: 5, LastPacketNumber: 5},
|
||||
{FirstPacketNumber: 3, LastPacketNumber: 3},
|
||||
},
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved)))
|
||||
Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(2)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(3)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(4)))
|
||||
Expect(handler.packetHistory).To(HaveKey(protocol.PacketNumber(5)))
|
||||
Expect(handler.packetHistory).ToNot(HaveKey(protocol.PacketNumber(6)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("ACK processing", func() { // in all these tests, the EntropyBit of each Packet is set to false, so that the resulting EntropyByte will always be 0
|
||||
var packets []*Packet
|
||||
|
||||
BeforeEach(func() {
|
||||
packets = []*Packet{
|
||||
{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
}
|
||||
for _, packet := range packets {
|
||||
handler.SentPacket(packet)
|
||||
}
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
|
||||
Context("ACK validation", func() {
|
||||
It("rejects duplicate ACKs", func() {
|
||||
largestObserved := 3
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).To(MatchError(ErrDuplicateOrOutOfOrderAck))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
})
|
||||
|
||||
It("rejects out of order ACKs", func() {
|
||||
largestObserved := 3
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: protocol.PacketNumber(largestObserved),
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
ack.LargestObserved--
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).To(MatchError(ErrDuplicateOrOutOfOrderAck))
|
||||
Expect(handler.LargestObserved).To(Equal(protocol.PacketNumber(largestObserved)))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
})
|
||||
|
||||
It("rejects ACKs with a too high LargestObserved packet number", func() {
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: packets[len(packets)-1].PacketNumber + 1337,
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).To(MatchError(errAckForUnsentPacket))
|
||||
Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(0)))
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("calculating RTT", func() {
|
||||
It("calculates the RTT", func() {
|
||||
now := time.Now()
|
||||
// First, fake the sent times of the first, second and last packet
|
||||
handler.packetHistory[1].sendTime = now.Add(-10 * time.Minute)
|
||||
handler.packetHistory[2].sendTime = now.Add(-5 * time.Minute)
|
||||
handler.packetHistory[6].sendTime = now.Add(-1 * time.Minute)
|
||||
// Now, check that the proper times are used when calculating the deltas
|
||||
err := handler.ReceivedAck(&frames.AckFrameLegacy{LargestObserved: 1})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 10*time.Minute, 1*time.Second))
|
||||
err = handler.ReceivedAck(&frames.AckFrameLegacy{LargestObserved: 2})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second))
|
||||
err = handler.ReceivedAck(&frames.AckFrameLegacy{LargestObserved: 6})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 1*time.Minute, 1*time.Second))
|
||||
})
|
||||
|
||||
It("uses the DelayTime in the ack frame", func() {
|
||||
now := time.Now()
|
||||
handler.packetHistory[1].sendTime = now.Add(-10 * time.Minute)
|
||||
err := handler.ReceivedAck(&frames.AckFrameLegacy{LargestObserved: 1, DelayTime: 5 * time.Minute})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.rttStats.LatestRTT()).To(BeNumerically("~", 5*time.Minute, 1*time.Second))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("Retransmission handler", func() {
|
||||
var packets []*Packet
|
||||
|
||||
BeforeEach(func() {
|
||||
packets = []*Packet{
|
||||
{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 3, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 4, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 5, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
{PacketNumber: 6, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1},
|
||||
}
|
||||
for _, packet := range packets {
|
||||
handler.SentPacket(packet)
|
||||
}
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(6)))
|
||||
})
|
||||
|
||||
It("does not dequeue a packet if no packet has been nacked", func() {
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold; i++ {
|
||||
_, err := handler.nackPacket(2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.ProbablyHasPacketForRetransmission()).To(BeFalse())
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
|
||||
It("queues a packet for retransmission", func() {
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.ProbablyHasPacketForRetransmission()).To(BeTrue())
|
||||
Expect(handler.retransmissionQueue).To(HaveLen(1))
|
||||
Expect(handler.retransmissionQueue[0].PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
It("dequeues a packet for retransmission", func() {
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(3)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
packet := handler.DequeuePacketForRetransmission()
|
||||
Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(3)))
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
|
||||
It("keeps the packets in the right order", func() {
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(4)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
packet := handler.DequeuePacketForRetransmission()
|
||||
Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
packet = handler.DequeuePacketForRetransmission()
|
||||
Expect(packet.PacketNumber).To(Equal(protocol.PacketNumber(4)))
|
||||
})
|
||||
|
||||
It("only queues each packet once, regardless of the number of NACKs", func() {
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(4)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(4)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
_ = handler.DequeuePacketForRetransmission()
|
||||
_ = handler.DequeuePacketForRetransmission()
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
|
||||
It("does not change the highestInOrderAckedPacketNumber after queueing a retransmission", func() {
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: 4,
|
||||
NackRanges: []frames.NackRange{{FirstPacketNumber: 3, LastPacketNumber: 3}},
|
||||
}
|
||||
err := handler.ReceivedAck(&ack)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
handler.nackPacket(3) // this is the second NACK for this packet
|
||||
Expect(handler.highestInOrderAckedPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
It("does not retransmit a packet if a belated was received", func() {
|
||||
// lose packet by NACKing it often enough
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold+1; i++ {
|
||||
_, err := handler.nackPacket(2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
// this is the belated ACK
|
||||
handler.ackPacket(2)
|
||||
// this is the edge case where ProbablyHasPacketForRetransmission() get's it wrong: it says there's probably a packet for retransmission, but actually there isn't
|
||||
Expect(handler.ProbablyHasPacketForRetransmission()).To(BeTrue())
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Context("calculating bytes in flight", func() {
|
||||
It("works in a typical retransmission scenarios", func() {
|
||||
packet1 := Packet{PacketNumber: 1, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 1}
|
||||
packet2 := Packet{PacketNumber: 2, Frames: []frames.Frame{&streamFrame}, EntropyBit: false, Length: 2}
|
||||
err := handler.SentPacket(&packet1)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = handler.SentPacket(&packet2)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(3)))
|
||||
|
||||
// ACK 2, NACK 1
|
||||
ack := frames.AckFrameLegacy{
|
||||
LargestObserved: 2,
|
||||
NackRanges: []frames.NackRange{{FirstPacketNumber: 1, LastPacketNumber: 1}},
|
||||
}
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(1)))
|
||||
|
||||
// Simulate protocol.RetransmissionThreshold more NACKs
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold; i++ {
|
||||
_, err = handler.nackPacket(1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(0)))
|
||||
|
||||
// Retransmission
|
||||
packet3 := Packet{PacketNumber: 3, EntropyBit: false, Length: 1}
|
||||
err = handler.SentPacket(&packet3)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(1)))
|
||||
|
||||
// ACK
|
||||
ack = frames.AckFrameLegacy{
|
||||
LargestObserved: 3,
|
||||
}
|
||||
err = handler.ReceivedAck(&ack)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.BytesInFlight()).To(Equal(protocol.ByteCount(0)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("congestion", func() {
|
||||
var (
|
||||
cong *mockCongestion
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
cong = &mockCongestion{}
|
||||
handler.congestion = cong
|
||||
})
|
||||
|
||||
It("should call OnSent", func() {
|
||||
p := &Packet{
|
||||
PacketNumber: 1,
|
||||
Frames: []frames.Frame{&frames.StreamFrame{StreamID: 5}},
|
||||
Length: 42,
|
||||
}
|
||||
err := handler.SentPacket(p)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cong.nCalls).To(Equal(1))
|
||||
Expect(cong.argsOnPacketSent[1]).To(Equal(protocol.ByteCount(42)))
|
||||
Expect(cong.argsOnPacketSent[2]).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(cong.argsOnPacketSent[3]).To(Equal(protocol.ByteCount(42)))
|
||||
Expect(cong.argsOnPacketSent[4]).To(BeTrue())
|
||||
})
|
||||
|
||||
It("should call OnCongestionEvent", func() {
|
||||
handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
||||
handler.SentPacket(&Packet{PacketNumber: 2, Frames: []frames.Frame{}, Length: 2})
|
||||
handler.SentPacket(&Packet{PacketNumber: 3, Frames: []frames.Frame{}, Length: 3})
|
||||
err := handler.ReceivedAck(&frames.AckFrameLegacy{
|
||||
LargestObserved: 3,
|
||||
NackRanges: []frames.NackRange{{2, 2}},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(cong.nCalls).To(Equal(4)) // 3 * SentPacket + 1 * ReceivedAck
|
||||
// rttUpdated, bytesInFlight, ackedPackets, lostPackets
|
||||
Expect(cong.argsOnCongestionEvent[0]).To(BeTrue())
|
||||
Expect(cong.argsOnCongestionEvent[1]).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(cong.argsOnCongestionEvent[2]).To(Equal(congestion.PacketVector{{1, 1}, {3, 3}}))
|
||||
Expect(cong.argsOnCongestionEvent[3]).To(BeEmpty())
|
||||
|
||||
// Loose the packet
|
||||
var packetNumber protocol.PacketNumber
|
||||
for i := uint8(0); i < protocol.RetransmissionThreshold; i++ {
|
||||
packetNumber = protocol.PacketNumber(4 + i)
|
||||
handler.SentPacket(&Packet{PacketNumber: packetNumber, Frames: []frames.Frame{}, Length: protocol.ByteCount(packetNumber)})
|
||||
err = handler.ReceivedAck(&frames.AckFrameLegacy{
|
||||
LargestObserved: packetNumber,
|
||||
NackRanges: []frames.NackRange{{2, 2}},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
Expect(cong.argsOnCongestionEvent[2]).To(Equal(congestion.PacketVector{{packetNumber, protocol.ByteCount(packetNumber)}}))
|
||||
Expect(cong.argsOnCongestionEvent[3]).To(Equal(congestion.PacketVector{{2, 2}}))
|
||||
})
|
||||
|
||||
It("allows or denies sending", func() {
|
||||
Expect(handler.CongestionAllowsSending()).To(BeTrue())
|
||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: protocol.DefaultTCPMSS + 1})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.CongestionAllowsSending()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("should call OnRetransmissionTimeout", func() {
|
||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.lastSentPacketTime = time.Now().Add(-time.Second)
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(cong.nCalls).To(Equal(3))
|
||||
// rttUpdated, bytesInFlight, ackedPackets, lostPackets
|
||||
Expect(cong.argsOnCongestionEvent[0]).To(BeFalse())
|
||||
Expect(cong.argsOnCongestionEvent[1]).To(Equal(protocol.ByteCount(1)))
|
||||
Expect(cong.argsOnCongestionEvent[2]).To(BeEmpty())
|
||||
Expect(cong.argsOnCongestionEvent[3]).To(Equal(congestion.PacketVector{{1, 1}}))
|
||||
|
||||
Expect(cong.onRetransmissionTimeout).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Context("calculating RTO", func() {
|
||||
It("uses default RTO", func() {
|
||||
Expect(handler.getRTO()).To(Equal(protocol.DefaultRetransmissionTime))
|
||||
})
|
||||
|
||||
It("uses RTO from rttStats", func() {
|
||||
rtt := time.Second
|
||||
expected := rtt + rtt/2*4
|
||||
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
|
||||
Expect(handler.getRTO()).To(Equal(expected))
|
||||
})
|
||||
|
||||
It("limits RTO min", func() {
|
||||
rtt := time.Millisecond
|
||||
handler.rttStats.UpdateRTT(rtt, 0, time.Now())
|
||||
Expect(handler.getRTO()).To(Equal(protocol.MinRetransmissionTime))
|
||||
})
|
||||
})
|
||||
|
||||
Context("RTO retransmission", func() {
|
||||
Context("calculating the time to first RTO", func() {
|
||||
It("defaults to zero", func() {
|
||||
Expect(handler.TimeOfFirstRTO().IsZero()).To(BeTrue())
|
||||
})
|
||||
|
||||
It("returns time to RTO", func() {
|
||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(handler.TimeOfFirstRTO().Sub(time.Now())).To(BeNumerically("~", protocol.DefaultRetransmissionTime, time.Millisecond))
|
||||
})
|
||||
|
||||
It("ignores nil packets", func() {
|
||||
handler.packetHistory[1] = nil
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(handler.TimeOfFirstRTO().IsZero()).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
Context("queuing packets due to RTO", func() {
|
||||
It("does nothing if not required", func() {
|
||||
err := handler.SentPacket(&Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("queues a packet if RTO expired", func() {
|
||||
p := &Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1}
|
||||
err := handler.SentPacket(p)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.lastSentPacketTime = time.Now().Add(-time.Second)
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(handler.retransmissionQueue).To(HaveLen(1))
|
||||
Expect(handler.retransmissionQueue[0]).To(Equal(p))
|
||||
})
|
||||
|
||||
It("does not queue retransmittedpackets", func() {
|
||||
p := &Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1, Retransmitted: true}
|
||||
err := handler.SentPacket(p)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.lastSentPacketTime = time.Now().Add(-time.Second)
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("ignores nil packets", func() {
|
||||
handler.packetHistory[1] = nil
|
||||
handler.maybeQueuePacketsRTO()
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
It("works with HasPacketForRetransmission", func() {
|
||||
p := &Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1}
|
||||
err := handler.SentPacket(p)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.lastSentPacketTime = time.Now().Add(-time.Second)
|
||||
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("works with DequeuePacketForRetransmission", func() {
|
||||
p := &Packet{PacketNumber: 1, Frames: []frames.Frame{}, Length: 1}
|
||||
err := handler.SentPacket(p)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
handler.lastSentPacketTime = time.Now().Add(-time.Second)
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(Equal(p))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,58 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"github.com/lucas-clemente/quic-go/frames"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
)
|
||||
|
||||
// StopWaitingManager manages StopWaitingFrames
|
||||
type stopWaitingManager struct {
|
||||
// sentStopWaitings map[protocol.PacketNumber]protocol.PacketNumber // map[LeastUnacked]stopWaitingSentWithPacketNumber
|
||||
lastNewStopWaitingFirstSentWithPacketNumber protocol.PacketNumber
|
||||
maxRetransmittedPacketNumber protocol.PacketNumber
|
||||
currentStopWaitingFrame *frames.StopWaitingFrame
|
||||
currentStopWaitingFrameSent bool
|
||||
}
|
||||
|
||||
// NewStopWaitingManager creates a new StopWaitingManager
|
||||
func NewStopWaitingManager() StopWaitingManager {
|
||||
return &stopWaitingManager{
|
||||
currentStopWaitingFrame: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterPacketForRetransmission prepares the StopWaitingFrame, if necessary
|
||||
func (h *stopWaitingManager) RegisterPacketForRetransmission(packet *Packet) {
|
||||
// out-of-order retransmission. A StopWaitingFrame with a higher LeastUnacked was already queued (or sent in the past), no need to send another one again
|
||||
if packet.PacketNumber < h.maxRetransmittedPacketNumber {
|
||||
return
|
||||
}
|
||||
if h.currentStopWaitingFrame == nil || h.currentStopWaitingFrame.LeastUnacked <= packet.PacketNumber { // <= because for StopWaitingFrames LeastUnacked = packet.PacketNumber + 1
|
||||
h.currentStopWaitingFrame = &frames.StopWaitingFrame{
|
||||
LeastUnacked: packet.PacketNumber + 1,
|
||||
Entropy: byte(packet.Entropy),
|
||||
}
|
||||
h.maxRetransmittedPacketNumber = packet.PacketNumber
|
||||
h.currentStopWaitingFrameSent = false
|
||||
}
|
||||
}
|
||||
|
||||
// GetStopWaitingFrame gets the StopWaitingFrame that needs to be sent. It returns nil if no StopWaitingFrame needs to be sent
|
||||
func (h *stopWaitingManager) GetStopWaitingFrame() *frames.StopWaitingFrame {
|
||||
return h.currentStopWaitingFrame
|
||||
}
|
||||
|
||||
// SentStopWaitingWithPacket must be called after sending out a StopWaitingFrame with a packet
|
||||
func (h *stopWaitingManager) SentStopWaitingWithPacket(packetNumber protocol.PacketNumber) {
|
||||
if !h.currentStopWaitingFrameSent {
|
||||
h.lastNewStopWaitingFirstSentWithPacketNumber = packetNumber
|
||||
}
|
||||
h.currentStopWaitingFrameSent = true
|
||||
}
|
||||
|
||||
// ReceivedAckForPacketNumber should be called after receiving an ACK
|
||||
func (h *stopWaitingManager) ReceivedAckForPacketNumber(packetNumber protocol.PacketNumber) {
|
||||
if packetNumber >= h.lastNewStopWaitingFirstSentWithPacketNumber {
|
||||
h.currentStopWaitingFrame = nil
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("StopWaitingManager", func() {
|
||||
var manager *stopWaitingManager
|
||||
BeforeEach(func() {
|
||||
manager = NewStopWaitingManager().(*stopWaitingManager)
|
||||
})
|
||||
|
||||
It("returns nil in the beginning", func() {
|
||||
Expect(manager.GetStopWaitingFrame()).To(BeNil())
|
||||
})
|
||||
|
||||
It("gets a StopWaitingFrame after a packet has been registered for retransmission", func() {
|
||||
leastUnacked := protocol.PacketNumber(10)
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked, Entropy: 10})
|
||||
swf := manager.GetStopWaitingFrame()
|
||||
Expect(swf).ToNot(BeNil())
|
||||
Expect(swf.LeastUnacked).To(Equal(leastUnacked + 1))
|
||||
Expect(swf.Entropy).To(Equal(byte(10)))
|
||||
})
|
||||
|
||||
It("always gets the StopWaitingFrame for the highest retransmitted packet number", func() {
|
||||
leastUnacked := protocol.PacketNumber(10)
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked, Entropy: 10})
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked - 1, Entropy: 8})
|
||||
swf := manager.GetStopWaitingFrame()
|
||||
Expect(swf).ToNot(BeNil())
|
||||
Expect(swf.LeastUnacked).To(Equal(leastUnacked + 1))
|
||||
Expect(swf.Entropy).To(Equal(byte(10)))
|
||||
})
|
||||
|
||||
It("updates the StopWaitingFrame when a packet with a higher packet number is retransmitted", func() {
|
||||
leastUnacked := protocol.PacketNumber(10)
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked - 1, Entropy: 10})
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked, Entropy: 8})
|
||||
swf := manager.GetStopWaitingFrame()
|
||||
Expect(swf).ToNot(BeNil())
|
||||
Expect(swf.LeastUnacked).To(Equal(leastUnacked + 1))
|
||||
Expect(swf.Entropy).To(Equal(byte(8)))
|
||||
})
|
||||
|
||||
It("does not create a new StopWaitingFrame for an out-of-order retransmission", func() {
|
||||
leastUnacked := protocol.PacketNumber(10)
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked, Entropy: 8})
|
||||
manager.SentStopWaitingWithPacket(12)
|
||||
manager.ReceivedAckForPacketNumber(12)
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: leastUnacked - 1, Entropy: 10})
|
||||
swf := manager.GetStopWaitingFrame()
|
||||
Expect(swf).To(BeNil())
|
||||
})
|
||||
|
||||
Context("ACK handling", func() {
|
||||
It("removes the current StopWaitingFrame when the first packet it was sent with is ACKed", func() {
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: 10})
|
||||
manager.SentStopWaitingWithPacket(13)
|
||||
manager.SentStopWaitingWithPacket(14)
|
||||
manager.SentStopWaitingWithPacket(15)
|
||||
Expect(manager.GetStopWaitingFrame()).ToNot(BeNil())
|
||||
manager.ReceivedAckForPacketNumber(13)
|
||||
Expect(manager.GetStopWaitingFrame()).To(BeNil())
|
||||
})
|
||||
|
||||
It("removes the current StopWaitingFrame when any packet it was sent with is ACKed", func() {
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: 10})
|
||||
manager.SentStopWaitingWithPacket(13)
|
||||
manager.SentStopWaitingWithPacket(14)
|
||||
manager.SentStopWaitingWithPacket(15)
|
||||
Expect(manager.GetStopWaitingFrame()).ToNot(BeNil())
|
||||
manager.ReceivedAckForPacketNumber(14)
|
||||
Expect(manager.GetStopWaitingFrame()).To(BeNil())
|
||||
})
|
||||
|
||||
It("does not remove the current StopWaitingFrame when a packet before the one containing the StopWaitingFrame is ACKed", func() {
|
||||
manager.RegisterPacketForRetransmission(&Packet{PacketNumber: 10})
|
||||
manager.SentStopWaitingWithPacket(13)
|
||||
Expect(manager.GetStopWaitingFrame()).ToNot(BeNil())
|
||||
manager.ReceivedAckForPacketNumber(12)
|
||||
Expect(manager.GetStopWaitingFrame()).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user