implement NACK range parsing in ACK frames

This commit is contained in:
Marten Seemann
2016-04-19 20:39:40 +07:00
parent 83416ab861
commit 5381bfe220
3 changed files with 77 additions and 7 deletions

9
ackhandler/nack_range.go Normal file
View 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
}

View File

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

View File

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