rename AckHandler package to AckHandlerLegacy

This commit is contained in:
Marten Seemann
2016-06-18 22:32:51 +07:00
parent 288cb9e143
commit eb03ed5334
16 changed files with 42 additions and 42 deletions

View File

@@ -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")
}

View File

@@ -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)
}

View File

@@ -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))
})
})
})

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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())
})
})
})

View File

@@ -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
}

View File

@@ -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)))
})
})
})

View File

@@ -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())
}

View File

@@ -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))
})
})
})

View File

@@ -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
}
}

View File

@@ -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())
})
})
})