diff --git a/ackhandler/nack_range.go b/ackhandler/nack_range.go new file mode 100644 index 000000000..9c3be8e2b --- /dev/null +++ b/ackhandler/nack_range.go @@ -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 +} diff --git a/frames/ack_frame.go b/frames/ack_frame.go index 90b67b78d..e78cb7cd1 100644 --- a/frames/ack_frame.go +++ b/frames/ack_frame.go @@ -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) } } diff --git a/frames/ack_frame_test.go b/frames/ack_frame_test.go index 2f15f0755..23e260310 100644 --- a/frames/ack_frame_test.go +++ b/frames/ack_frame_test.go @@ -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)) + }) })