From cc5fe06db9e36968c85ce3e8eee62e80c93a318d Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 21 Jun 2016 00:24:44 +0700 Subject: [PATCH] implement basic writing of ACK blocks for QUIC 34 ACK frames ref #182 --- frames/ack_frame_new.go | 50 +++++++++++----- frames/ack_frame_new_test.go | 107 ++++++++++++++++++++++++++++------- 2 files changed, 120 insertions(+), 37 deletions(-) diff --git a/frames/ack_frame_new.go b/frames/ack_frame_new.go index 4c59efd3..1194108c 100644 --- a/frames/ack_frame_new.go +++ b/frames/ack_frame_new.go @@ -167,12 +167,15 @@ func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) err typeByte ^= (uint8(largestObservedLen / 2)) << 2 } - missingSequenceNumberDeltaLen := largestObservedLen + // TODO: send shorter values, if possible + missingSequenceNumberDeltaLen := protocol.PacketNumberLen6 if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 { typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2)) } - f.DelayTime = time.Now().Sub(f.PacketReceivedTime) + if f.HasMissingRanges() { + typeByte |= (0x20 | 0x03) + } b.WriteByte(typeByte) @@ -187,22 +190,39 @@ func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) err utils.WriteUint48(b, uint64(f.LargestObserved)) } + f.DelayTime = time.Now().Sub(f.PacketReceivedTime) utils.WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond)) - // TODO: write number of ACK blocks, if present - - switch missingSequenceNumberDeltaLen { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(f.LargestObserved)) - case protocol.PacketNumberLen2: - utils.WriteUint16(b, uint16(f.LargestObserved)) - case protocol.PacketNumberLen4: - utils.WriteUint32(b, uint32(f.LargestObserved)) - case protocol.PacketNumberLen6: - utils.WriteUint48(b, uint64(f.LargestObserved)) + if f.HasMissingRanges() { + numRanges := len(f.AckRanges) + if numRanges >= 0xFF { + panic("AckFrame: Too many ACK ranges") + } + b.WriteByte(uint8(numRanges - 1)) } - // TODO: write ACK blocks + if !f.HasMissingRanges() { + utils.WriteUint48(b, uint64(f.LargestObserved-f.LowestAcked)) + } else { + if f.LargestObserved != f.AckRanges[0].LastPacketNumber { + return errors.New("internal inconsistency") + } + length := f.LargestObserved - f.AckRanges[0].FirstPacketNumber + 1 + utils.WriteUint48(b, uint64(length)) + } + + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + length := ackRange.LastPacketNumber - ackRange.FirstPacketNumber + 1 + // TODO: implement large gaps + gap := f.AckRanges[i-1].FirstPacketNumber - ackRange.LastPacketNumber - 1 + + b.WriteByte(uint8(gap)) + utils.WriteUint48(b, uint64(length)) + } b.WriteByte(0x01) // Just one timestamp b.WriteByte(0x00) // Delta Largest observed @@ -217,7 +237,7 @@ func (f *AckFrameNew) MinLength(version protocol.VersionNumber) (protocol.ByteCo length = 1 + 2 + 1 + 1 + 4 // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp, 1 Delta Largest Observed, 4 FirstTimestamp length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestObserved)) // for the first ACK block length - length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestObserved)) + length += protocol.ByteCount(protocol.PacketNumberLen6) length += (1 + 2) * 0 /* TODO: num_timestamps */ if f.HasMissingRanges() { diff --git a/frames/ack_frame_new_test.go b/frames/ack_frame_new_test.go index 245cf1b7..280c2437 100644 --- a/frames/ack_frame_new_test.go +++ b/frames/ack_frame_new_test.go @@ -155,10 +155,95 @@ var _ = Describe("AckFrame", func() { Context("when writing", func() { var b *bytes.Buffer + BeforeEach(func() { b = &bytes.Buffer{} }) + Context("self-consistency", func() { + It("writes a simple ACK frame", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 1, + } + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrameNew(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes the correct block length in a simple ACK frame", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 20, + LowestAcked: 10, + } + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrameNew(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a simple ACK frame with a high packet number", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 0xDEADBEEFCAFE, + } + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrameNew(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with one packet missing", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 40, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 25, LastPacketNumber: 40}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 23}, + }, + } + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrameNew(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with multiple missing packets", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 25, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 22, LastPacketNumber: 25}, + AckRange{FirstPacketNumber: 15, LastPacketNumber: 18}, + AckRange{FirstPacketNumber: 13, LastPacketNumber: 13}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 10}, + }, + } + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrameNew(r, 0) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + }) + Context("min length", func() { It("has proper min length", func() { f := &AckFrameNew{ @@ -185,27 +270,5 @@ var _ = Describe("AckFrame", func() { } Expect(frame.GetHighestInOrderPacketNumber()).To(Equal(protocol.PacketNumber(0x1337))) }) - - }) - - Context("self-consistency checks", func() { - var b *bytes.Buffer - BeforeEach(func() { - b = &bytes.Buffer{} - }) - - It("is self-consistent for ACK frames without NACK ranges", func() { - frameOrig := &AckFrameNew{ - LargestObserved: 1, - } - err := frameOrig.Write(b, protocol.Version34) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrameNew(r, protocol.Version34) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved)) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(r.Len()).To(BeZero()) - }) }) })