mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-06 21:57:36 +03:00
Merge pull request #2095 from lucas-clemente/frame-retransmisions
retransmit frames, not packets
This commit is contained in:
commit
dd6e8a7424
19 changed files with 755 additions and 1214 deletions
8
internal/ackhandler/frame.go
Normal file
8
internal/ackhandler/frame.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package ackhandler
|
||||
|
||||
import "github.com/lucas-clemente/quic-go/internal/wire"
|
||||
|
||||
type Frame struct {
|
||||
wire.Frame // nil if the frame has already been acknowledged in another packet
|
||||
OnLost func(wire.Frame)
|
||||
}
|
|
@ -8,11 +8,22 @@ import (
|
|||
"github.com/lucas-clemente/quic-go/quictrace"
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
includedInBytesInFlight bool
|
||||
}
|
||||
|
||||
// SentPacketHandler handles ACKs received for outgoing packets
|
||||
type SentPacketHandler interface {
|
||||
// SentPacket may modify the packet
|
||||
SentPacket(packet *Packet)
|
||||
SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber)
|
||||
ReceivedAck(ackFrame *wire.AckFrame, withPacketNumber protocol.PacketNumber, encLevel protocol.EncryptionLevel, recvTime time.Time) error
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
ResetForRetry() error
|
||||
|
@ -31,8 +42,7 @@ type SentPacketHandler interface {
|
|||
|
||||
// only to be called once the handshake is complete
|
||||
GetLowestPacketNotConfirmedAcked() protocol.PacketNumber
|
||||
DequeuePacketForRetransmission() *Packet
|
||||
DequeueProbePacket() (*Packet, error)
|
||||
QueueProbePacket() bool /* was a packet queued */
|
||||
|
||||
PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
|
||||
PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package ackhandler
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []wire.Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
// There are two reasons why a packet cannot be retransmitted:
|
||||
// * it was already retransmitted
|
||||
// * this packet is a retransmission, and we already received an ACK for the original packet
|
||||
canBeRetransmitted bool
|
||||
includedInBytesInFlight bool
|
||||
retransmittedAs []protocol.PacketNumber
|
||||
isRetransmission bool // we need a separate bool here because 0 is a valid packet number
|
||||
retransmissionOf protocol.PacketNumber
|
||||
}
|
|
@ -10,8 +10,6 @@ const (
|
|||
SendNone SendMode = iota
|
||||
// SendAck means an ACK-only packet should be sent
|
||||
SendAck
|
||||
// SendRetransmission means that retransmissions should be sent
|
||||
SendRetransmission
|
||||
// SendPTO means that a probe packet should be sent
|
||||
SendPTO
|
||||
// SendAny means that any packet should be sent
|
||||
|
@ -24,8 +22,6 @@ func (s SendMode) String() string {
|
|||
return "none"
|
||||
case SendAck:
|
||||
return "ack"
|
||||
case SendRetransmission:
|
||||
return "retransmission"
|
||||
case SendPTO:
|
||||
return "pto"
|
||||
case SendAny:
|
||||
|
|
|
@ -11,7 +11,6 @@ var _ = Describe("Send Mode", func() {
|
|||
Expect(SendAny.String()).To(Equal("any"))
|
||||
Expect(SendAck.String()).To(Equal("ack"))
|
||||
Expect(SendPTO.String()).To(Equal("pto"))
|
||||
Expect(SendRetransmission.String()).To(Equal("retransmission"))
|
||||
Expect(SendMode(123).String()).To(Equal("invalid send mode: 123"))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ackhandler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
@ -56,8 +55,6 @@ type sentPacketHandler struct {
|
|||
// Only applies to the application-data packet number space.
|
||||
lowestNotConfirmedAcked protocol.PacketNumber
|
||||
|
||||
retransmissionQueue []*Packet
|
||||
|
||||
bytesInFlight protocol.ByteCount
|
||||
|
||||
congestion congestion.SendAlgorithmWithDebugInfos
|
||||
|
@ -112,14 +109,6 @@ func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
|||
}
|
||||
return true, nil
|
||||
})
|
||||
// remove packets from the retransmission queue
|
||||
var queue []*Packet
|
||||
for _, packet := range h.retransmissionQueue {
|
||||
if packet.EncryptionLevel != encLevel {
|
||||
queue = append(queue, packet)
|
||||
}
|
||||
}
|
||||
h.retransmissionQueue = queue
|
||||
// drop the packet history
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
|
@ -138,17 +127,6 @@ func (h *sentPacketHandler) SentPacket(packet *Packet) {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) {
|
||||
var p []*Packet
|
||||
for _, packet := range packets {
|
||||
if isAckEliciting := h.sentPacketImpl(packet); isAckEliciting {
|
||||
p = append(p, packet)
|
||||
}
|
||||
}
|
||||
h.getPacketNumberSpace(p[0].EncryptionLevel).history.SentPacketsAsRetransmission(p, retransmissionOf)
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLevel) *packetNumberSpace {
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
|
@ -181,7 +159,6 @@ func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* is ack-elicit
|
|||
h.lastSentAckElicitingPacketTime = packet.SendTime
|
||||
packet.includedInBytesInFlight = true
|
||||
h.bytesInFlight += packet.Length
|
||||
packet.canBeRetransmitted = true
|
||||
if h.numProbesToSend > 0 {
|
||||
h.numProbesToSend--
|
||||
}
|
||||
|
@ -346,12 +323,14 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
|||
|
||||
// Cancel the alarm if no packets are outstanding
|
||||
if !h.hasOutstandingPackets() {
|
||||
h.logger.Debugf("setLossDetectionTimer: canceling. Bytes in flight: %d", h.bytesInFlight)
|
||||
h.alarm = time.Time{}
|
||||
return
|
||||
}
|
||||
|
||||
// PTO alarm
|
||||
h.alarm = h.lastSentAckElicitingPacketTime.Add(h.rttStats.PTO() << h.ptoCount)
|
||||
h.logger.Debugf("setLossDetectionTimer: setting to", h.alarm)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) detectLostPackets(
|
||||
|
@ -399,27 +378,23 @@ func (h *sentPacketHandler) detectLostPackets(
|
|||
}
|
||||
|
||||
for _, p := range lostPackets {
|
||||
h.queueFramesForRetransmission(p)
|
||||
// the bytes in flight need to be reduced no matter if this packet will be retransmitted
|
||||
if p.includedInBytesInFlight {
|
||||
h.bytesInFlight -= p.Length
|
||||
h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
|
||||
}
|
||||
if p.canBeRetransmitted {
|
||||
// queue the packet for retransmission, and report the loss to the congestion controller
|
||||
if err := h.queuePacketForRetransmission(p, pnSpace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
pnSpace.history.Remove(p.PacketNumber)
|
||||
if h.traceCallback != nil {
|
||||
// TODO: trace frames
|
||||
h.traceCallback(quictrace.Event{
|
||||
Time: now,
|
||||
EventType: quictrace.PacketLost,
|
||||
EncryptionLevel: p.EncryptionLevel,
|
||||
PacketNumber: p.PacketNumber,
|
||||
PacketSize: p.Length,
|
||||
Frames: p.Frames,
|
||||
TransportState: h.GetStats(),
|
||||
//Frames: p.Frames,
|
||||
TransportState: h.GetStats(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -465,97 +440,16 @@ func (h *sentPacketHandler) GetLossDetectionTimeout() time.Time {
|
|||
|
||||
func (h *sentPacketHandler) onPacketAcked(p *Packet, rcvTime time.Time) error {
|
||||
pnSpace := h.getPacketNumberSpace(p.EncryptionLevel)
|
||||
// This happens if a packet and its retransmissions is acked in the same ACK.
|
||||
// As soon as we process the first one, this will remove all the retransmissions,
|
||||
// so we won't find the retransmitted packet number later.
|
||||
if packet := pnSpace.history.GetPacket(p.PacketNumber); packet == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// only report the acking of this packet to the congestion controller if:
|
||||
// * it is an ack-eliciting packet
|
||||
// * this packet wasn't retransmitted yet
|
||||
if p.isRetransmission {
|
||||
// that the parent doesn't exist is expected to happen every time the original packet was already acked
|
||||
if parent := pnSpace.history.GetPacket(p.retransmissionOf); parent != nil {
|
||||
if len(parent.retransmittedAs) == 1 {
|
||||
parent.retransmittedAs = nil
|
||||
} else {
|
||||
// remove this packet from the slice of retransmission
|
||||
retransmittedAs := make([]protocol.PacketNumber, 0, len(parent.retransmittedAs)-1)
|
||||
for _, pn := range parent.retransmittedAs {
|
||||
if pn != p.PacketNumber {
|
||||
retransmittedAs = append(retransmittedAs, pn)
|
||||
}
|
||||
}
|
||||
parent.retransmittedAs = retransmittedAs
|
||||
}
|
||||
}
|
||||
}
|
||||
// this also applies to packets that have been retransmitted as probe packets
|
||||
if p.includedInBytesInFlight {
|
||||
h.bytesInFlight -= p.Length
|
||||
}
|
||||
if err := h.stopRetransmissionsFor(p, pnSpace); err != nil {
|
||||
return err
|
||||
}
|
||||
return pnSpace.history.Remove(p.PacketNumber)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) stopRetransmissionsFor(p *Packet, pnSpace *packetNumberSpace) error {
|
||||
if err := pnSpace.history.MarkCannotBeRetransmitted(p.PacketNumber); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range p.retransmittedAs {
|
||||
packet := pnSpace.history.GetPacket(r)
|
||||
if packet == nil {
|
||||
return fmt.Errorf("sent packet handler BUG: marking packet as not retransmittable %d (retransmission of %d) not found in history", r, p.PacketNumber)
|
||||
}
|
||||
h.stopRetransmissionsFor(packet, pnSpace)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) DequeuePacketForRetransmission() *Packet {
|
||||
if len(h.retransmissionQueue) == 0 {
|
||||
return nil
|
||||
}
|
||||
packet := h.retransmissionQueue[0]
|
||||
// Shift the slice and don't retain anything that isn't needed.
|
||||
copy(h.retransmissionQueue, h.retransmissionQueue[1:])
|
||||
h.retransmissionQueue[len(h.retransmissionQueue)-1] = nil
|
||||
h.retransmissionQueue = h.retransmissionQueue[:len(h.retransmissionQueue)-1]
|
||||
return packet
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) DequeueProbePacket() (*Packet, error) {
|
||||
if len(h.retransmissionQueue) > 0 {
|
||||
return h.DequeuePacketForRetransmission(), nil
|
||||
}
|
||||
|
||||
var pnSpace *packetNumberSpace
|
||||
var p *Packet
|
||||
if h.initialPackets != nil {
|
||||
pnSpace = h.initialPackets
|
||||
p = h.initialPackets.history.FirstOutstanding()
|
||||
}
|
||||
if p == nil && h.handshakePackets != nil {
|
||||
pnSpace = h.handshakePackets
|
||||
p = h.handshakePackets.history.FirstOutstanding()
|
||||
}
|
||||
if p == nil {
|
||||
pnSpace = h.oneRTTPackets
|
||||
p = h.oneRTTPackets.history.FirstOutstanding()
|
||||
}
|
||||
if p == nil {
|
||||
return nil, errors.New("cannot dequeue a probe packet. No outstanding packets")
|
||||
}
|
||||
if err := h.queuePacketForRetransmission(p, pnSpace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.DequeuePacketForRetransmission(), nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) PeekPacketNumber(encLevel protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
|
||||
|
@ -575,7 +469,7 @@ func (h *sentPacketHandler) PopPacketNumber(encLevel protocol.EncryptionLevel) p
|
|||
}
|
||||
|
||||
func (h *sentPacketHandler) SendMode() SendMode {
|
||||
numTrackedPackets := len(h.retransmissionQueue) + h.oneRTTPackets.history.Len()
|
||||
numTrackedPackets := h.oneRTTPackets.history.Len()
|
||||
if h.initialPackets != nil {
|
||||
numTrackedPackets += h.initialPackets.history.Len()
|
||||
}
|
||||
|
@ -603,10 +497,6 @@ func (h *sentPacketHandler) SendMode() SendMode {
|
|||
}
|
||||
return SendAck
|
||||
}
|
||||
// Send retransmissions first, if there are any.
|
||||
if len(h.retransmissionQueue) > 0 {
|
||||
return SendRetransmission
|
||||
}
|
||||
if numTrackedPackets >= protocol.MaxOutstandingSentPackets {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Max outstanding limited: tracking %d packets, maximum: %d", numTrackedPackets, protocol.MaxOutstandingSentPackets)
|
||||
|
@ -632,30 +522,45 @@ func (h *sentPacketHandler) ShouldSendNumPackets() int {
|
|||
return int(math.Ceil(float64(protocol.MinPacingDelay) / float64(delay)))
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) queuePacketForRetransmission(p *Packet, pnSpace *packetNumberSpace) error {
|
||||
if !p.canBeRetransmitted {
|
||||
return fmt.Errorf("sent packet handler BUG: packet %d already queued for retransmission", p.PacketNumber)
|
||||
func (h *sentPacketHandler) QueueProbePacket() bool {
|
||||
var p *Packet
|
||||
if h.initialPackets != nil {
|
||||
p = h.initialPackets.history.FirstOutstanding()
|
||||
}
|
||||
if err := pnSpace.history.MarkCannotBeRetransmitted(p.PacketNumber); err != nil {
|
||||
return err
|
||||
if p == nil && h.handshakePackets != nil {
|
||||
p = h.handshakePackets.history.FirstOutstanding()
|
||||
}
|
||||
if p == nil {
|
||||
p = h.oneRTTPackets.history.FirstOutstanding()
|
||||
}
|
||||
if p == nil {
|
||||
return false
|
||||
}
|
||||
h.queueFramesForRetransmission(p)
|
||||
// TODO: don't remove the packet here
|
||||
// Keep track of acknowledged frames instead.
|
||||
if p.includedInBytesInFlight {
|
||||
h.bytesInFlight -= p.Length
|
||||
}
|
||||
if err := h.getPacketNumberSpace(p.EncryptionLevel).history.Remove(p.PacketNumber); err != nil {
|
||||
// should never happen. We just got this packet from the history a lines above.
|
||||
panic(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) queueFramesForRetransmission(p *Packet) {
|
||||
for _, f := range p.Frames {
|
||||
f.OnLost(f.Frame)
|
||||
}
|
||||
h.retransmissionQueue = append(h.retransmissionQueue, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ResetForRetry() error {
|
||||
h.bytesInFlight = 0
|
||||
var packets []*Packet
|
||||
h.initialPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
if p.canBeRetransmitted {
|
||||
packets = append(packets, p)
|
||||
}
|
||||
h.queueFramesForRetransmission(p)
|
||||
return true, nil
|
||||
})
|
||||
for _, p := range packets {
|
||||
h.logger.Debugf("Queueing packet %#x for retransmission.", p.PacketNumber)
|
||||
h.retransmissionQueue = append(h.retransmissionQueue, p)
|
||||
}
|
||||
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Pop())
|
||||
h.setLossDetectionTimer()
|
||||
return nil
|
||||
|
|
|
@ -14,40 +14,15 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func ackElicitingPacket(p *Packet) *Packet {
|
||||
if p.EncryptionLevel == protocol.EncryptionUnspecified {
|
||||
p.EncryptionLevel = protocol.Encryption1RTT
|
||||
}
|
||||
if p.Length == 0 {
|
||||
p.Length = 1
|
||||
}
|
||||
if p.SendTime.IsZero() {
|
||||
p.SendTime = time.Now()
|
||||
}
|
||||
p.Frames = []wire.Frame{&wire.PingFrame{}}
|
||||
return p
|
||||
}
|
||||
|
||||
func nonAckElicitingPacket(p *Packet) *Packet {
|
||||
p = ackElicitingPacket(p)
|
||||
p.Frames = nil
|
||||
p.LargestAcked = 1
|
||||
return p
|
||||
}
|
||||
|
||||
func cryptoPacket(p *Packet) *Packet {
|
||||
p = ackElicitingPacket(p)
|
||||
p.EncryptionLevel = protocol.EncryptionInitial
|
||||
return p
|
||||
}
|
||||
|
||||
var _ = Describe("SentPacketHandler", func() {
|
||||
var (
|
||||
handler *sentPacketHandler
|
||||
streamFrame wire.StreamFrame
|
||||
lostPackets []protocol.PacketNumber
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
lostPackets = nil
|
||||
rttStats := &congestion.RTTStats{}
|
||||
handler = NewSentPacketHandler(42, rttStats, nil, utils.DefaultLogger).(*sentPacketHandler)
|
||||
streamFrame = wire.StreamFrame{
|
||||
|
@ -63,17 +38,33 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
return nil
|
||||
}
|
||||
|
||||
losePacket := func(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) {
|
||||
p := getPacket(pn, encLevel)
|
||||
ExpectWithOffset(1, p).ToNot(BeNil())
|
||||
handler.queuePacketForRetransmission(p, handler.getPacketNumberSpace(encLevel))
|
||||
if p.includedInBytesInFlight {
|
||||
p.includedInBytesInFlight = false
|
||||
handler.bytesInFlight -= p.Length
|
||||
ackElicitingPacket := func(p *Packet) *Packet {
|
||||
if p.EncryptionLevel == protocol.EncryptionUnspecified {
|
||||
p.EncryptionLevel = protocol.Encryption1RTT
|
||||
}
|
||||
r := handler.DequeuePacketForRetransmission()
|
||||
ExpectWithOffset(1, r).ToNot(BeNil())
|
||||
ExpectWithOffset(1, r.PacketNumber).To(Equal(pn))
|
||||
if p.Length == 0 {
|
||||
p.Length = 1
|
||||
}
|
||||
if p.SendTime.IsZero() {
|
||||
p.SendTime = time.Now()
|
||||
}
|
||||
p.Frames = []Frame{
|
||||
{Frame: &wire.PingFrame{}, OnLost: func(wire.Frame) { lostPackets = append(lostPackets, p.PacketNumber) }},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
nonAckElicitingPacket := func(p *Packet) *Packet {
|
||||
p = ackElicitingPacket(p)
|
||||
p.Frames = nil
|
||||
p.LargestAcked = 1
|
||||
return p
|
||||
}
|
||||
|
||||
cryptoPacket := func(p *Packet) *Packet {
|
||||
p = ackElicitingPacket(p)
|
||||
p.EncryptionLevel = protocol.EncryptionInitial
|
||||
return p
|
||||
}
|
||||
|
||||
expectInPacketHistory := func(expected []protocol.PacketNumber, encLevel protocol.EncryptionLevel) {
|
||||
|
@ -174,21 +165,21 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("acks and nacks the right packets", func() {
|
||||
Context("acks the right packets", func() {
|
||||
expectInPacketHistoryOrLost := func(expected []protocol.PacketNumber, encLevel protocol.EncryptionLevel) {
|
||||
pnSpace := handler.getPacketNumberSpace(encLevel)
|
||||
ExpectWithOffset(1, pnSpace.history.Len()+len(handler.retransmissionQueue)).To(Equal(len(expected)))
|
||||
ExpectWithOffset(1, pnSpace.history.Len()+len(lostPackets)).To(Equal(len(expected)))
|
||||
expectedLoop:
|
||||
for _, p := range expected {
|
||||
if _, ok := pnSpace.history.packetMap[p]; ok {
|
||||
continue
|
||||
}
|
||||
for _, lost := range handler.retransmissionQueue {
|
||||
if lost.PacketNumber == p {
|
||||
for _, lostP := range lostPackets {
|
||||
if lostP == p {
|
||||
continue expectedLoop
|
||||
}
|
||||
}
|
||||
Fail(fmt.Sprintf("Packet %d neither in packet history nor declared lost.", p))
|
||||
Fail(fmt.Sprintf("Packet %d not in packet history.", p))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,9 +324,26 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
Context("determining which ACKs we have received an ACK for", func() {
|
||||
BeforeEach(func() {
|
||||
morePackets := []*Packet{
|
||||
{PacketNumber: 13, LargestAcked: 100, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.Encryption1RTT},
|
||||
{PacketNumber: 14, LargestAcked: 200, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.Encryption1RTT},
|
||||
{PacketNumber: 15, Frames: []wire.Frame{&streamFrame}, Length: 1, EncryptionLevel: protocol.Encryption1RTT},
|
||||
{
|
||||
PacketNumber: 13,
|
||||
LargestAcked: 100,
|
||||
Frames: []Frame{{Frame: &streamFrame, OnLost: func(wire.Frame) {}}},
|
||||
Length: 1,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
},
|
||||
{
|
||||
PacketNumber: 14,
|
||||
LargestAcked: 200,
|
||||
Frames: []Frame{{Frame: &streamFrame, OnLost: func(wire.Frame) {}}},
|
||||
Length: 1,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
},
|
||||
{
|
||||
PacketNumber: 15,
|
||||
Frames: []Frame{{Frame: &streamFrame, OnLost: func(wire.Frame) {}}},
|
||||
Length: 1,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
},
|
||||
}
|
||||
for _, packet := range morePackets {
|
||||
handler.SentPacket(packet)
|
||||
|
@ -368,55 +376,6 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("ACK processing, for retransmitted packets", func() {
|
||||
It("sends a packet as retransmission", func() {
|
||||
// packet 5 was retransmitted as packet 6
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, Length: 10, EncryptionLevel: protocol.Encryption1RTT}))
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
||||
losePacket(5, protocol.Encryption1RTT)
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
handler.SentPacketsAsRetransmission([]*Packet{ackElicitingPacket(&Packet{PacketNumber: 6, Length: 11})}, 5)
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
||||
})
|
||||
|
||||
It("removes a packet when it is acked", func() {
|
||||
// packet 5 was retransmitted as packet 6
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, Length: 10}))
|
||||
losePacket(5, protocol.Encryption1RTT)
|
||||
handler.SentPacketsAsRetransmission([]*Packet{ackElicitingPacket(&Packet{PacketNumber: 6, Length: 11})}, 5)
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
||||
// ack 5
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}}
|
||||
err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectInPacketHistory([]protocol.PacketNumber{6}, protocol.Encryption1RTT)
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(11)))
|
||||
})
|
||||
|
||||
It("handles ACKs that ack the original packet as well as the retransmission", func() {
|
||||
// packet 5 was retransmitted as packet 7
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, Length: 10}))
|
||||
losePacket(5, protocol.Encryption1RTT)
|
||||
handler.SentPacketsAsRetransmission([]*Packet{ackElicitingPacket(&Packet{PacketNumber: 7, Length: 11})}, 5)
|
||||
// ack 5 and 7
|
||||
ack := &wire.AckFrame{
|
||||
AckRanges: []wire.AckRange{
|
||||
{Smallest: 7, Largest: 7},
|
||||
{Smallest: 5, Largest: 5},
|
||||
},
|
||||
}
|
||||
err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.oneRTTPackets.history.Len()).To(BeZero())
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
||||
It("does not dequeue a packet if no ACK has been received", func() {
|
||||
handler.SentPacket(&Packet{PacketNumber: 1, EncryptionLevel: protocol.Encryption1RTT, SendTime: time.Now().Add(-time.Hour)})
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
|
||||
Context("congestion", func() {
|
||||
var cong *mocks.MockSendAlgorithmWithDebugInfos
|
||||
|
||||
|
@ -437,7 +396,7 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
handler.SentPacket(&Packet{
|
||||
PacketNumber: 1,
|
||||
Length: 42,
|
||||
Frames: []wire.Frame{&wire.PingFrame{}},
|
||||
Frames: []Frame{{Frame: &wire.PingFrame{}, OnLost: func(wire.Frame) {}}},
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
})
|
||||
})
|
||||
|
@ -531,32 +490,10 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
Expect(handler.SendMode()).To(Equal(SendAck))
|
||||
})
|
||||
|
||||
It("doesn't allow retransmissions if congestion limited", func() {
|
||||
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
||||
cong.EXPECT().CanSend(gomock.Any()).Return(false)
|
||||
Expect(handler.SendMode()).To(Equal(SendAck))
|
||||
})
|
||||
|
||||
It("allows sending retransmissions", func() {
|
||||
cong.EXPECT().CanSend(gomock.Any()).Return(true)
|
||||
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
||||
Expect(handler.SendMode()).To(Equal(SendRetransmission))
|
||||
})
|
||||
|
||||
It("allows retransmissions, if we're keeping track of between MaxOutstandingSentPackets and MaxTrackedSentPackets packets", func() {
|
||||
cong.EXPECT().CanSend(gomock.Any()).Return(true)
|
||||
Expect(protocol.MaxOutstandingSentPackets).To(BeNumerically("<", protocol.MaxTrackedSentPackets))
|
||||
handler.retransmissionQueue = make([]*Packet, protocol.MaxOutstandingSentPackets+10)
|
||||
Expect(handler.SendMode()).To(Equal(SendRetransmission))
|
||||
handler.retransmissionQueue = make([]*Packet, protocol.MaxTrackedSentPackets)
|
||||
Expect(handler.SendMode()).To(Equal(SendNone))
|
||||
})
|
||||
|
||||
It("allows RTOs, even when congestion limited", func() {
|
||||
// note that we don't EXPECT a call to GetCongestionWindow
|
||||
// that means retransmissions are sent without considering the congestion window
|
||||
handler.numProbesToSend = 1
|
||||
handler.retransmissionQueue = []*Packet{{PacketNumber: 3}}
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
})
|
||||
|
||||
|
@ -607,6 +544,19 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
})
|
||||
|
||||
Context("probe packets", func() {
|
||||
It("queues a probe packet", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 10}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 11}))
|
||||
queued := handler.QueueProbePacket()
|
||||
Expect(queued).To(BeTrue())
|
||||
Expect(lostPackets).To(Equal([]protocol.PacketNumber{10}))
|
||||
})
|
||||
|
||||
It("says when it can't queue a probe packet", func() {
|
||||
queued := handler.QueueProbePacket()
|
||||
Expect(queued).To(BeFalse())
|
||||
})
|
||||
|
||||
It("implements exponential backoff", func() {
|
||||
sendTime := time.Now().Add(-time.Hour)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: sendTime}))
|
||||
|
@ -620,9 +570,16 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
Expect(handler.GetLossDetectionTimeout().Sub(sendTime)).To(Equal(4 * timeout))
|
||||
})
|
||||
|
||||
It("sets the TPO send mode until two packets is sent", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.OnLossDetectionTimeout()
|
||||
It("sets the PTO send mode until two packets is sent", func() {
|
||||
var lostPackets []protocol.PacketNumber
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: 1,
|
||||
SendTime: time.Now().Add(-time.Hour),
|
||||
Frames: []Frame{
|
||||
{Frame: &wire.PingFrame{}, OnLost: func(wire.Frame) { lostPackets = append(lostPackets, 1) }},
|
||||
},
|
||||
}))
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
Expect(handler.ShouldSendNumPackets()).To(Equal(2))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2}))
|
||||
|
@ -633,7 +590,7 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
|
||||
It("only counts ack-eliciting packets as probe packets", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.OnLossDetectionTimeout()
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
Expect(handler.ShouldSendNumPackets()).To(Equal(2))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2}))
|
||||
|
@ -653,118 +610,49 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
updateRTT(time.Hour)
|
||||
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
|
||||
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // RTO
|
||||
p, err := handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p).ToNot(BeNil())
|
||||
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
p, err = handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p).ToNot(BeNil())
|
||||
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed()) // TLP
|
||||
Expect(handler.ptoCount).To(BeEquivalentTo(1))
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 3}))
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 4}))
|
||||
|
||||
Expect(handler.ptoCount).To(BeEquivalentTo(3))
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed()) // PTO
|
||||
Expect(handler.ptoCount).To(BeEquivalentTo(2))
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5}))
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 6}))
|
||||
|
||||
Expect(handler.SendMode()).To(Equal(SendAny))
|
||||
})
|
||||
|
||||
It("gets two probe packets if RTO expires, for crypto packets", func() {
|
||||
It("gets two probe packets if PTO expires, for crypto packets", func() {
|
||||
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 1}))
|
||||
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 2}))
|
||||
|
||||
updateRTT(time.Hour)
|
||||
Expect(handler.initialPackets.lossTime.IsZero()).To(BeTrue())
|
||||
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // RTO
|
||||
p, err := handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p).ToNot(BeNil())
|
||||
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
p, err = handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(p).ToNot(BeNil())
|
||||
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 3}))
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
handler.SentPacket(cryptoPacket(&Packet{PacketNumber: 3}))
|
||||
|
||||
Expect(handler.ptoCount).To(BeEquivalentTo(3))
|
||||
})
|
||||
|
||||
It("doesn't delete packets transmitted as PTO from the history", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // RTO
|
||||
_, err := handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectInPacketHistory([]protocol.PacketNumber{1, 2}, protocol.Encryption1RTT)
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(2)))
|
||||
// Send a probe packet and receive an ACK for it.
|
||||
// This verifies the RTO.
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 3}))
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 3, Largest: 3}}}
|
||||
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())).To(Succeed())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.oneRTTPackets.history.Len()).To(BeZero())
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
Expect(handler.retransmissionQueue).To(BeEmpty()) // 1 and 2 were already sent as probe packets
|
||||
Expect(handler.SendMode()).To(Equal(SendAny))
|
||||
})
|
||||
|
||||
It("resets the send mode when it receives an acknowledgement after queueing probe packets", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
||||
handler.OnLossDetectionTimeout()
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.SendMode()).To(Equal(SendPTO))
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}
|
||||
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())).To(Succeed())
|
||||
Expect(handler.SendMode()).To(Equal(SendAny))
|
||||
})
|
||||
|
||||
It("gets packets sent before the probe packet for retransmission", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 1, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 2, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 3, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 4, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // RTO
|
||||
_, err := handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, err = handler.DequeueProbePacket()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
expectInPacketHistory([]protocol.PacketNumber{1, 2, 3, 4, 5}, protocol.Encryption1RTT)
|
||||
// Send a probe packet and receive an ACK for it.
|
||||
// This verifies the RTO.
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 6}))
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 6, Largest: 6}}}
|
||||
err = handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(handler.oneRTTPackets.history.Len()).To(BeZero())
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
Expect(handler.retransmissionQueue).To(HaveLen(3)) // packets 3, 4, 5
|
||||
})
|
||||
|
||||
It("handles ACKs for the original packet", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // TLP
|
||||
handler.OnLossDetectionTimeout() // RTO
|
||||
handler.SentPacketsAsRetransmission([]*Packet{ackElicitingPacket(&Packet{PacketNumber: 6})}, 5)
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 5, Largest: 5}}}
|
||||
err := handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = handler.OnLossDetectionTimeout()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("handles ACKs for the original packet", func() {
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 5, SendTime: time.Now().Add(-time.Hour)}))
|
||||
handler.rttStats.UpdateRTT(time.Second, 0, time.Now())
|
||||
|
@ -783,11 +671,7 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 6, Largest: 6}}}
|
||||
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, time.Now())).To(Succeed())
|
||||
expectInPacketHistory([]protocol.PacketNumber{4, 5}, protocol.Encryption1RTT)
|
||||
for _, p := range []protocol.PacketNumber{1, 2, 3} {
|
||||
lost := handler.DequeuePacketForRetransmission()
|
||||
Expect(lost).ToNot(BeNil())
|
||||
Expect(lost.PacketNumber).To(Equal(p))
|
||||
}
|
||||
Expect(lostPackets).To(Equal([]protocol.PacketNumber{1, 2, 3}))
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -800,8 +684,6 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 2, Largest: 2}}}
|
||||
Expect(handler.ReceivedAck(ack, 1, protocol.Encryption1RTT, now)).To(Succeed())
|
||||
Expect(handler.DequeuePacketForRetransmission()).ToNot(BeNil())
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
// no need to set an alarm, since packet 1 was already declared lost
|
||||
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeTrue())
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
|
@ -821,11 +703,6 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
// Packet 1 should be considered lost (1+1/8) RTTs after it was sent.
|
||||
Expect(handler.oneRTTPackets.lossTime.IsZero()).To(BeFalse())
|
||||
Expect(handler.oneRTTPackets.lossTime.Sub(getPacket(1, protocol.Encryption1RTT).SendTime)).To(Equal(time.Second * 9 / 8))
|
||||
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil())
|
||||
// make sure this is not an RTO: only packet 1 is retransmissted
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
|
||||
It("sets the early retransmit alarm for crypto packets", func() {
|
||||
|
@ -842,22 +719,15 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
// Packet 1 should be considered lost (1+1/8) RTTs after it was sent.
|
||||
Expect(handler.initialPackets.lossTime.IsZero()).To(BeFalse())
|
||||
Expect(handler.initialPackets.lossTime.Sub(getPacket(1, protocol.EncryptionInitial).SendTime)).To(Equal(time.Second * 9 / 8))
|
||||
|
||||
Expect(handler.OnLossDetectionTimeout()).To(Succeed())
|
||||
Expect(handler.DequeuePacketForRetransmission()).NotTo(BeNil())
|
||||
// make sure this is not an RTO: only packet 1 is retransmissted
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Context("crypto packets", func() {
|
||||
It("rejects an ACK that acks packets with a higher encryption level", func() {
|
||||
handler.SentPacket(&Packet{
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: 13,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
Frames: []wire.Frame{&streamFrame},
|
||||
Length: 1,
|
||||
})
|
||||
}))
|
||||
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 13, Largest: 13}}}
|
||||
err := handler.ReceivedAck(ack, 1, protocol.EncryptionHandshake, time.Now())
|
||||
Expect(err).To(MatchError("PROTOCOL_VIOLATION: Received ACK for an unsent packet"))
|
||||
|
@ -865,43 +735,43 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
|
||||
It("deletes Initial packets", func() {
|
||||
for i := protocol.PacketNumber(0); i < 6; i++ {
|
||||
p := ackElicitingPacket(&Packet{PacketNumber: i, EncryptionLevel: protocol.EncryptionInitial})
|
||||
handler.SentPacket(p)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: i,
|
||||
EncryptionLevel: protocol.EncryptionInitial,
|
||||
}))
|
||||
}
|
||||
for i := protocol.PacketNumber(0); i < 10; i++ {
|
||||
p := ackElicitingPacket(&Packet{PacketNumber: i, EncryptionLevel: protocol.EncryptionHandshake})
|
||||
handler.SentPacket(p)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: i,
|
||||
EncryptionLevel: protocol.EncryptionHandshake,
|
||||
}))
|
||||
}
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(16)))
|
||||
handler.queuePacketForRetransmission(getPacket(1, protocol.EncryptionInitial), handler.getPacketNumberSpace(protocol.EncryptionInitial))
|
||||
lostPacket := getPacket(3, protocol.EncryptionHandshake)
|
||||
handler.queuePacketForRetransmission(lostPacket, handler.getPacketNumberSpace(protocol.EncryptionHandshake))
|
||||
handler.DropPackets(protocol.EncryptionInitial)
|
||||
Expect(lostPackets).To(BeEmpty()) // frames must not be queued for retransmission
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
||||
Expect(handler.initialPackets).To(BeNil())
|
||||
Expect(handler.handshakePackets.history.Len()).ToNot(BeZero())
|
||||
packet := handler.DequeuePacketForRetransmission()
|
||||
Expect(packet).To(Equal(lostPacket))
|
||||
})
|
||||
|
||||
It("deletes Handshake packets", func() {
|
||||
for i := protocol.PacketNumber(0); i < 6; i++ {
|
||||
p := ackElicitingPacket(&Packet{PacketNumber: i, EncryptionLevel: protocol.EncryptionHandshake})
|
||||
handler.SentPacket(p)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: i,
|
||||
EncryptionLevel: protocol.EncryptionHandshake,
|
||||
}))
|
||||
}
|
||||
for i := protocol.PacketNumber(0); i < 10; i++ {
|
||||
p := ackElicitingPacket(&Packet{PacketNumber: i, EncryptionLevel: protocol.Encryption1RTT})
|
||||
handler.SentPacket(p)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{
|
||||
PacketNumber: i,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
}))
|
||||
}
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(16)))
|
||||
handler.queuePacketForRetransmission(getPacket(1, protocol.EncryptionHandshake), handler.getPacketNumberSpace(protocol.EncryptionInitial))
|
||||
lostPacket := getPacket(3, protocol.Encryption1RTT)
|
||||
handler.queuePacketForRetransmission(lostPacket, handler.getPacketNumberSpace(protocol.EncryptionHandshake))
|
||||
handler.DropPackets(protocol.EncryptionHandshake)
|
||||
Expect(lostPackets).To(BeEmpty()) // frames must not be queued for retransmission
|
||||
Expect(handler.bytesInFlight).To(Equal(protocol.ByteCount(10)))
|
||||
Expect(handler.handshakePackets).To(BeNil())
|
||||
packet := handler.DequeuePacketForRetransmission()
|
||||
Expect(packet).To(Equal(lostPacket))
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -929,25 +799,16 @@ var _ = Describe("SentPacketHandler", func() {
|
|||
|
||||
Context("resetting for retry", func() {
|
||||
It("queues outstanding packets for retransmission and cancels alarms", func() {
|
||||
packet := &Packet{
|
||||
PacketNumber: 42,
|
||||
EncryptionLevel: protocol.EncryptionInitial,
|
||||
Frames: []wire.Frame{&wire.CryptoFrame{Data: []byte("foobar")}},
|
||||
Length: 100,
|
||||
}
|
||||
handler.SentPacket(packet)
|
||||
handler.SentPacket(ackElicitingPacket(&Packet{PacketNumber: 42, EncryptionLevel: protocol.EncryptionInitial}))
|
||||
Expect(handler.GetLossDetectionTimeout()).ToNot(BeZero())
|
||||
Expect(handler.bytesInFlight).ToNot(BeZero())
|
||||
Expect(handler.DequeuePacketForRetransmission()).To(BeNil())
|
||||
Expect(handler.SendMode()).To(Equal(SendAny))
|
||||
// now receive a Retry
|
||||
Expect(handler.ResetForRetry()).To(Succeed())
|
||||
Expect(lostPackets).To(Equal([]protocol.PacketNumber{42}))
|
||||
Expect(handler.bytesInFlight).To(BeZero())
|
||||
Expect(handler.GetLossDetectionTimeout()).To(BeZero())
|
||||
Expect(handler.SendMode()).To(Equal(SendRetransmission))
|
||||
p := handler.DequeuePacketForRetransmission()
|
||||
Expect(p.PacketNumber).To(Equal(packet.PacketNumber))
|
||||
Expect(p.Frames).To(Equal(packet.Frames))
|
||||
Expect(handler.SendMode()).To(Equal(SendAny))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -9,10 +9,6 @@ import (
|
|||
type sentPacketHistory struct {
|
||||
packetList *PacketList
|
||||
packetMap map[protocol.PacketNumber]*PacketElement
|
||||
|
||||
numOutstandingPackets int
|
||||
|
||||
firstOutstanding *PacketElement
|
||||
}
|
||||
|
||||
func newSentPacketHistory() *sentPacketHistory {
|
||||
|
@ -23,40 +19,8 @@ func newSentPacketHistory() *sentPacketHistory {
|
|||
}
|
||||
|
||||
func (h *sentPacketHistory) SentPacket(p *Packet) {
|
||||
h.sentPacketImpl(p)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) sentPacketImpl(p *Packet) *PacketElement {
|
||||
el := h.packetList.PushBack(*p)
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
if h.firstOutstanding == nil {
|
||||
h.firstOutstanding = el
|
||||
}
|
||||
if p.canBeRetransmitted {
|
||||
h.numOutstandingPackets++
|
||||
}
|
||||
return el
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentPacketsAsRetransmission(packets []*Packet, retransmissionOf protocol.PacketNumber) {
|
||||
retransmission, ok := h.packetMap[retransmissionOf]
|
||||
// The retransmitted packet is not present anymore.
|
||||
// This can happen if it was acked in between dequeueing of the retransmission and sending.
|
||||
// Just treat the retransmissions as normal packets.
|
||||
// TODO: This won't happen if we clear packets queued for retransmission on new ACKs.
|
||||
if !ok {
|
||||
for _, packet := range packets {
|
||||
h.sentPacketImpl(packet)
|
||||
}
|
||||
return
|
||||
}
|
||||
retransmission.Value.retransmittedAs = make([]protocol.PacketNumber, len(packets))
|
||||
for i, packet := range packets {
|
||||
retransmission.Value.retransmittedAs[i] = packet.PacketNumber
|
||||
el := h.sentPacketImpl(packet)
|
||||
el.Value.isRetransmission = true
|
||||
el.Value.retransmissionOf = retransmissionOf
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) GetPacket(p protocol.PacketNumber) *Packet {
|
||||
|
@ -84,40 +48,10 @@ func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) err
|
|||
// It must not be modified (e.g. retransmitted).
|
||||
// Use DequeueFirstPacketForRetransmission() to retransmit it.
|
||||
func (h *sentPacketHistory) FirstOutstanding() *Packet {
|
||||
if h.firstOutstanding == nil {
|
||||
if !h.HasOutstandingPackets() {
|
||||
return nil
|
||||
}
|
||||
return &h.firstOutstanding.Value
|
||||
}
|
||||
|
||||
// QueuePacketForRetransmission marks a packet for retransmission.
|
||||
// A packet can only be queued once.
|
||||
func (h *sentPacketHistory) MarkCannotBeRetransmitted(pn protocol.PacketNumber) error {
|
||||
el, ok := h.packetMap[pn]
|
||||
if !ok {
|
||||
return fmt.Errorf("sent packet history: packet %d not found", pn)
|
||||
}
|
||||
if el.Value.canBeRetransmitted {
|
||||
h.numOutstandingPackets--
|
||||
if h.numOutstandingPackets < 0 {
|
||||
panic("numOutstandingHandshakePackets negative")
|
||||
}
|
||||
}
|
||||
el.Value.canBeRetransmitted = false
|
||||
if el == h.firstOutstanding {
|
||||
h.readjustFirstOutstanding()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readjustFirstOutstanding readjusts the pointer to the first outstanding packet.
|
||||
// This is necessary every time the first outstanding packet is deleted or retransmitted.
|
||||
func (h *sentPacketHistory) readjustFirstOutstanding() {
|
||||
el := h.firstOutstanding.Next()
|
||||
for el != nil && !el.Value.canBeRetransmitted {
|
||||
el = el.Next()
|
||||
}
|
||||
h.firstOutstanding = el
|
||||
return &h.packetList.Front().Value
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
|
@ -129,20 +63,11 @@ func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error {
|
|||
if !ok {
|
||||
return fmt.Errorf("packet %d not found in sent packet history", p)
|
||||
}
|
||||
if el == h.firstOutstanding {
|
||||
h.readjustFirstOutstanding()
|
||||
}
|
||||
if el.Value.canBeRetransmitted {
|
||||
h.numOutstandingPackets--
|
||||
if h.numOutstandingPackets < 0 {
|
||||
panic("numOutstandingHandshakePackets negative")
|
||||
}
|
||||
}
|
||||
h.packetList.Remove(el)
|
||||
delete(h.packetMap, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
return h.numOutstandingPackets > 0
|
||||
return h.packetList.Len() > 0
|
||||
}
|
||||
|
|
|
@ -15,13 +15,14 @@ var _ = Describe("SentPacketHistory", func() {
|
|||
ExpectWithOffset(1, hist.packetMap).To(HaveLen(len(packetNumbers)))
|
||||
ExpectWithOffset(1, hist.packetList.Len()).To(Equal(len(packetNumbers)))
|
||||
i := 0
|
||||
hist.Iterate(func(p *Packet) (bool, error) {
|
||||
err := hist.Iterate(func(p *Packet) (bool, error) {
|
||||
pn := packetNumbers[i]
|
||||
ExpectWithOffset(1, p.PacketNumber).To(Equal(pn))
|
||||
ExpectWithOffset(1, hist.packetMap[pn].Value.PacketNumber).To(Equal(pn))
|
||||
i++
|
||||
return true, nil
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
BeforeEach(func() {
|
||||
|
@ -53,45 +54,6 @@ var _ = Describe("SentPacketHistory", func() {
|
|||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
})
|
||||
|
||||
It("gets the second packet if the first one is retransmitted", func() {
|
||||
hist.SentPacket(&Packet{PacketNumber: 1, canBeRetransmitted: true})
|
||||
hist.SentPacket(&Packet{PacketNumber: 3, canBeRetransmitted: true})
|
||||
hist.SentPacket(&Packet{PacketNumber: 4, canBeRetransmitted: true})
|
||||
front := hist.FirstOutstanding()
|
||||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
// Queue the first packet for retransmission.
|
||||
// The first outstanding packet should now be 3.
|
||||
err := hist.MarkCannotBeRetransmitted(1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
front = hist.FirstOutstanding()
|
||||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(3)))
|
||||
})
|
||||
|
||||
It("gets the third packet if the first two are retransmitted", func() {
|
||||
hist.SentPacket(&Packet{PacketNumber: 1, canBeRetransmitted: true})
|
||||
hist.SentPacket(&Packet{PacketNumber: 3, canBeRetransmitted: true})
|
||||
hist.SentPacket(&Packet{PacketNumber: 4, canBeRetransmitted: true})
|
||||
front := hist.FirstOutstanding()
|
||||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
// Queue the second packet for retransmission.
|
||||
// The first outstanding packet should still be 3.
|
||||
err := hist.MarkCannotBeRetransmitted(3)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
front = hist.FirstOutstanding()
|
||||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
// Queue the first packet for retransmission.
|
||||
// The first outstanding packet should still be 4.
|
||||
err = hist.MarkCannotBeRetransmitted(1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
front = hist.FirstOutstanding()
|
||||
Expect(front).ToNot(BeNil())
|
||||
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(4)))
|
||||
})
|
||||
})
|
||||
|
||||
It("gets a packet by packet number", func() {
|
||||
|
@ -161,100 +123,35 @@ var _ = Describe("SentPacketHistory", func() {
|
|||
})
|
||||
})
|
||||
|
||||
Context("retransmissions", func() {
|
||||
BeforeEach(func() {
|
||||
for i := protocol.PacketNumber(1); i <= 5; i++ {
|
||||
hist.SentPacket(&Packet{PacketNumber: i})
|
||||
}
|
||||
})
|
||||
|
||||
It("errors if the packet doesn't exist", func() {
|
||||
err := hist.MarkCannotBeRetransmitted(100)
|
||||
Expect(err).To(MatchError("sent packet history: packet 100 not found"))
|
||||
})
|
||||
|
||||
It("adds a sent packets as a retransmission", func() {
|
||||
hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}}, 2)
|
||||
expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13})
|
||||
Expect(hist.GetPacket(13).isRetransmission).To(BeTrue())
|
||||
Expect(hist.GetPacket(13).retransmissionOf).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(hist.GetPacket(2).retransmittedAs).To(Equal([]protocol.PacketNumber{13}))
|
||||
})
|
||||
|
||||
It("adds multiple packets sent as a retransmission", func() {
|
||||
hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}, {PacketNumber: 15}}, 2)
|
||||
expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13, 15})
|
||||
Expect(hist.GetPacket(13).isRetransmission).To(BeTrue())
|
||||
Expect(hist.GetPacket(13).retransmissionOf).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(hist.GetPacket(15).retransmissionOf).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(hist.GetPacket(2).retransmittedAs).To(Equal([]protocol.PacketNumber{13, 15}))
|
||||
})
|
||||
|
||||
It("adds a packet as a normal packet if the retransmitted packet doesn't exist", func() {
|
||||
hist.SentPacketsAsRetransmission([]*Packet{{PacketNumber: 13}}, 7)
|
||||
expectInHistory([]protocol.PacketNumber{1, 2, 3, 4, 5, 13})
|
||||
Expect(hist.GetPacket(13).isRetransmission).To(BeFalse())
|
||||
Expect(hist.GetPacket(13).retransmissionOf).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
||||
Context("outstanding packets", func() {
|
||||
It("says if it has outstanding packets", func() {
|
||||
Expect(hist.HasOutstandingPackets()).To(BeFalse())
|
||||
hist.SentPacket(&Packet{
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
canBeRetransmitted: true,
|
||||
})
|
||||
hist.SentPacket(&Packet{EncryptionLevel: protocol.Encryption1RTT})
|
||||
Expect(hist.HasOutstandingPackets()).To(BeTrue())
|
||||
})
|
||||
|
||||
It("doesn't consider non-ack-eliciting packets as outstanding", func() {
|
||||
hist.SentPacket(&Packet{
|
||||
EncryptionLevel: protocol.EncryptionInitial,
|
||||
})
|
||||
Expect(hist.HasOutstandingPackets()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("accounts for deleted packets", func() {
|
||||
hist.SentPacket(&Packet{
|
||||
PacketNumber: 10,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
canBeRetransmitted: true,
|
||||
PacketNumber: 10,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
})
|
||||
Expect(hist.HasOutstandingPackets()).To(BeTrue())
|
||||
err := hist.Remove(10)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hist.HasOutstandingPackets()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("doesn't count packets marked as non-ack-eliciting", func() {
|
||||
hist.SentPacket(&Packet{
|
||||
PacketNumber: 10,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
canBeRetransmitted: true,
|
||||
})
|
||||
Expect(hist.HasOutstandingPackets()).To(BeTrue())
|
||||
err := hist.MarkCannotBeRetransmitted(10)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hist.Remove(10)).To(Succeed())
|
||||
Expect(hist.HasOutstandingPackets()).To(BeFalse())
|
||||
})
|
||||
|
||||
It("counts the number of packets", func() {
|
||||
hist.SentPacket(&Packet{
|
||||
PacketNumber: 10,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
canBeRetransmitted: true,
|
||||
PacketNumber: 10,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
})
|
||||
hist.SentPacket(&Packet{
|
||||
PacketNumber: 11,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
canBeRetransmitted: true,
|
||||
PacketNumber: 11,
|
||||
EncryptionLevel: protocol.Encryption1RTT,
|
||||
})
|
||||
err := hist.Remove(11)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hist.Remove(11)).To(Succeed())
|
||||
Expect(hist.HasOutstandingPackets()).To(BeTrue())
|
||||
err = hist.Remove(10)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(hist.Remove(10)).To(Succeed())
|
||||
Expect(hist.HasOutstandingPackets()).To(BeFalse())
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue