diff --git a/frames/ack_frame_new.go b/frames/ack_frame_new.go index a86de0aa..a49d4a0b 100644 --- a/frames/ack_frame_new.go +++ b/frames/ack_frame_new.go @@ -32,9 +32,9 @@ func ParseAckFrameNew(r *bytes.Reader, version protocol.VersionNumber) (*AckFram return nil, err } - hasNACK := false + hasMissingRanges := false if typeByte&0x20 == 0x20 { - hasNACK = true + hasMissingRanges = true } largestObservedLen := 2 * ((typeByte & 0x0C) >> 2) @@ -60,7 +60,7 @@ func ParseAckFrameNew(r *bytes.Reader, version protocol.VersionNumber) (*AckFram frame.DelayTime = time.Duration(delay) * time.Microsecond var numAckBlocks uint8 - if hasNACK { + if hasMissingRanges { numAckBlocks, err = r.ReadByte() if err != nil { return nil, err @@ -76,7 +76,7 @@ func ParseAckFrameNew(r *bytes.Reader, version protocol.VersionNumber) (*AckFram return nil, errInvalidAckRanges } - if hasNACK { + if hasMissingRanges { ackRange := AckRange{ FirstPacketNumber: protocol.PacketNumber(largestObserved-ackBlockLength) + 1, LastPacketNumber: frame.LargestObserved, @@ -193,8 +193,10 @@ func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) err f.DelayTime = time.Now().Sub(f.PacketReceivedTime) utils.WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond)) + var numRanges uint64 + var numRangesWritten uint64 // to check for internal consistency if f.HasMissingRanges() { - numRanges := len(f.AckRanges) + numRanges = f.numWrittenNackRanges() if numRanges >= 0xFF { panic("AckFrame: Too many ACK ranges") } @@ -209,6 +211,7 @@ func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) err } length := f.LargestObserved - f.AckRanges[0].FirstPacketNumber + 1 utils.WriteUint48(b, uint64(length)) + numRangesWritten++ } for i, ackRange := range f.AckRanges { @@ -217,11 +220,39 @@ func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) err } 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)) + num := gap/0xFF + 1 + if gap%0xFF == 0 { + num-- + } + + if num == 1 { + b.WriteByte(uint8(gap)) + utils.WriteUint48(b, uint64(length)) + numRangesWritten++ + } else { + for i := 0; i < int(num); i++ { + var lengthWritten uint64 + var gapWritten uint8 + + if i == int(num)-1 { // last block + lengthWritten = uint64(length) + gapWritten = uint8(gap % 0xFF) + } else { + lengthWritten = 0 + gapWritten = 0xFF + } + + b.WriteByte(uint8(gapWritten)) + utils.WriteUint48(b, lengthWritten) + numRangesWritten++ + } + } + } + + if numRanges != numRangesWritten { + return errors.New("BUG: Inconsistent number of ACK ranges written") } b.WriteByte(0x01) // Just one timestamp @@ -266,3 +297,27 @@ func (f *AckFrameNew) GetHighestInOrderPacketNumber() protocol.PacketNumber { } return f.LargestObserved } + +// numWrittenNackRanges calculates the number of ACK blocks that are about to be written +// this number is different from len(f.AckRanges) for the case of long gaps (> 255 packets) +func (f *AckFrameNew) numWrittenNackRanges() uint64 { + if len(f.AckRanges) == 0 { + return 0 + } + + var numRanges uint64 + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + lastAckRange := f.AckRanges[i-1] + gap := lastAckRange.FirstPacketNumber - ackRange.LastPacketNumber + numRanges += 1 + uint64(gap)/0xFF + if uint64(gap)%(0xFF+1) == 0 { + numRanges-- + } + } + + return numRanges + 1 +} diff --git a/frames/ack_frame_new_test.go b/frames/ack_frame_new_test.go index f84a6df5..419607d0 100644 --- a/frames/ack_frame_new_test.go +++ b/frames/ack_frame_new_test.go @@ -242,6 +242,81 @@ var _ = Describe("AckFrame", func() { Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) Expect(r.Len()).To(BeZero()) }) + + Context("longer ACK blocks", func() { + It("only writes one block for 255 lost packets", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 300, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 275, LastPacketNumber: 300}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 19}, + }, + } + Expect(frameOrig.numWrittenNackRanges()).To(Equal(uint64(2))) + 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)) + }) + + It("writes two blocks for 256 lost packets", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 300, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 276, LastPacketNumber: 300}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 19}, + }, + } + Expect(frameOrig.numWrittenNackRanges()).To(Equal(uint64(3))) + err := frameOrig.Write(b, 0) + Expect(err).ToNot(HaveOccurred()) + // Expect(b.Bytes()[13+0*(1+6) : 13+1*(1+6)]).To(Equal([]byte{0xFF, 0, 0, 0, 0, 0, 0})) + // Expect(b.Bytes()[13+1*(1+6) : 13+2*(1+6)]).To(Equal([]byte{0x1, 0, 0, 0, 0, 0, 19})) + 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)) + }) + + It("writes multiple blocks for a lot of lost packets", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 3000, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 2900, LastPacketNumber: 3000}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 19}, + }, + } + 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)) + }) + + It("writes multiple longer blocks for 256 lost packets", func() { + frameOrig := &AckFrameNew{ + LargestObserved: 3600, + AckRanges: []AckRange{ + AckRange{FirstPacketNumber: 2900, LastPacketNumber: 3600}, + AckRange{FirstPacketNumber: 1000, LastPacketNumber: 2500}, + AckRange{FirstPacketNumber: 1, LastPacketNumber: 19}, + }, + } + 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)) + }) + }) }) Context("min length", func() {