forked from quic-go/quic-go
implement NACK range parsing in ACK frames
This commit is contained in:
9
ackhandler/nack_range.go
Normal file
9
ackhandler/nack_range.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package ackhandler
|
||||
|
||||
import "github.com/lucas-clemente/quic-go/protocol"
|
||||
|
||||
// NackRange is a NACK range
|
||||
type NackRange struct {
|
||||
FirstPacketNumber protocol.PacketNumber
|
||||
Length uint8
|
||||
}
|
||||
@@ -2,8 +2,9 @@ package frames
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/ackhandler"
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
@@ -13,6 +14,8 @@ type AckFrame struct {
|
||||
Entropy byte
|
||||
LargestObserved protocol.PacketNumber
|
||||
DelayTime uint16 // Todo: properly interpret this value as described in the specification
|
||||
HasNACK bool
|
||||
NackRanges []*ackhandler.NackRange
|
||||
}
|
||||
|
||||
// Write writes an ACK frame.
|
||||
@@ -37,9 +40,9 @@ func ParseAckFrame(r *bytes.Reader) (*AckFrame, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasNACK := false
|
||||
frame.HasNACK = false
|
||||
if typeByte&0x20 == 0x20 {
|
||||
hasNACK = true
|
||||
frame.HasNACK = true
|
||||
}
|
||||
if typeByte&0x10 == 0x10 {
|
||||
panic("truncated ACKs not yet implemented.")
|
||||
@@ -102,19 +105,38 @@ func ParseAckFrame(r *bytes.Reader) (*AckFrame, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if hasNACK {
|
||||
fmt.Println("NACK not implemented yet!")
|
||||
if frame.HasNACK {
|
||||
var numRanges uint8
|
||||
numRanges, err = r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := make([]byte, largestObservedLen+1)
|
||||
|
||||
for i := uint8(0); i < numRanges; i++ {
|
||||
_, err := r.Read(p)
|
||||
missingPacketSequenceNumberDeltaByte, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
missingPacketSequenceNumberDelta := uint64(missingPacketSequenceNumberDeltaByte)
|
||||
|
||||
rangeLength, err := utils.ReadUintN(r, largestObservedLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nackRange := ackhandler.NackRange{
|
||||
Length: uint8(rangeLength + 1),
|
||||
}
|
||||
if i == 0 {
|
||||
nackRange.FirstPacketNumber = frame.LargestObserved - protocol.PacketNumber(missingPacketSequenceNumberDelta+rangeLength)
|
||||
} else {
|
||||
if missingPacketSequenceNumberDelta == 0 {
|
||||
return nil, errors.New("ACK frame: Continues NACK ranges not yet implemented.")
|
||||
}
|
||||
lastNackRange := frame.NackRanges[len(frame.NackRanges)-1]
|
||||
nackRange.FirstPacketNumber = lastNackRange.FirstPacketNumber - protocol.PacketNumber(missingPacketSequenceNumberDelta+rangeLength) - 1
|
||||
}
|
||||
frame.NackRanges = append(frame.NackRanges, &nackRange)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ var _ = Describe("AckFrame", func() {
|
||||
Expect(frame.Entropy).To(Equal(byte(0xA4)))
|
||||
Expect(frame.LargestObserved).To(Equal(protocol.PacketNumber(0x03)))
|
||||
Expect(frame.DelayTime).To(Equal(uint16(0x4523)))
|
||||
Expect(frame.HasNACK).To(Equal(false))
|
||||
Expect(b.Len()).To(Equal(0))
|
||||
})
|
||||
|
||||
@@ -34,6 +35,30 @@ var _ = Describe("AckFrame", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(b.Len()).To(Equal(0))
|
||||
})
|
||||
|
||||
It("parses a frame containing one NACK range", func() {
|
||||
b := bytes.NewReader([]byte{0x60, 0x8, 0x3, 0x72, 0x1, 0x1, 0x0, 0xc0, 0x15, 0x0, 0x0, 0x1, 0x1, 0x1})
|
||||
frame, err := ParseAckFrame(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.HasNACK).To(Equal(true))
|
||||
Expect(len(frame.NackRanges)).To(Equal(1))
|
||||
Expect(frame.NackRanges[0].FirstPacketNumber).To(Equal(protocol.PacketNumber(1)))
|
||||
Expect(frame.NackRanges[0].Length).To(Equal(uint8(2)))
|
||||
})
|
||||
|
||||
It("parses a frame containing multiple NACK ranges", func() {
|
||||
b := bytes.NewReader([]byte{0x60, 0x2, 0xf, 0xb8, 0x1, 0x1, 0x0, 0xe5, 0x58, 0x4, 0x0, 0x3, 0x1, 0x6, 0x1, 0x2, 0x1, 0x0})
|
||||
frame, err := ParseAckFrame(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.HasNACK).To(Equal(true))
|
||||
Expect(len(frame.NackRanges)).To(Equal(3))
|
||||
Expect(frame.NackRanges[0].FirstPacketNumber).To(Equal(protocol.PacketNumber(8)))
|
||||
Expect(frame.NackRanges[0].Length).To(Equal(uint8(7)))
|
||||
Expect(frame.NackRanges[1].FirstPacketNumber).To(Equal(protocol.PacketNumber(4)))
|
||||
Expect(frame.NackRanges[1].Length).To(Equal(uint8(3)))
|
||||
Expect(frame.NackRanges[2].FirstPacketNumber).To(Equal(protocol.PacketNumber(2)))
|
||||
Expect(frame.NackRanges[2].Length).To(Equal(uint8(1)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("when writing", func() {
|
||||
@@ -46,4 +71,18 @@ var _ = Describe("AckFrame", func() {
|
||||
Expect(b.Bytes()).To(Equal([]byte{0x48, 0x02, 0x01, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0}))
|
||||
})
|
||||
})
|
||||
|
||||
It("is self-consistent", func() {
|
||||
b := &bytes.Buffer{}
|
||||
frame := &AckFrame{
|
||||
Entropy: 0xDE,
|
||||
LargestObserved: 6789,
|
||||
}
|
||||
err := frame.Write(b)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
readframe, err := ParseAckFrame(bytes.NewReader(b.Bytes()))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(readframe.Entropy).To(Equal(frame.Entropy))
|
||||
Expect(readframe.LargestObserved).To(Equal(frame.LargestObserved))
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user