diff --git a/frames/ack_frame.go b/frames/ack_frame.go index 2e91babb6..87c8cb5c2 100644 --- a/frames/ack_frame.go +++ b/frames/ack_frame.go @@ -21,8 +21,10 @@ var ( errInconsistentAckLowestAcked = errors.New("internal inconsistency: LowestAcked does not match ACK ranges") ) -// An AckFrame is a ACK frame in QUIC c34 +// An AckFrame is an ACK frame in QUIC type AckFrame struct { + AckFrameLegacy *AckFrameLegacy + LargestAcked protocol.PacketNumber LowestAcked protocol.PacketNumber AckRanges []AckRange // has to be ordered. The ACK range with the highest FirstPacketNumber goes first, the ACK range with the lowest FirstPacketNumber goes last @@ -35,6 +37,15 @@ type AckFrame struct { func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { frame := &AckFrame{} + if version != protocol.VersionWhatever && version <= protocol.Version33 { + var err error + frame.AckFrameLegacy, err = ParseAckFrameLegacy(r, version) + if err != nil { + return nil, err + } + return frame, nil + } + typeByte, err := r.ReadByte() if err != nil { return nil, err @@ -187,6 +198,10 @@ func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, // Write writes an ACK frame. func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { + if f.AckFrameLegacy != nil { + return f.AckFrameLegacy.Write(b, version) + } + largestAckedLen := protocol.GetPacketNumberLength(f.LargestAcked) typeByte := uint8(0x40) @@ -327,6 +342,10 @@ func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error // MinLength of a written frame func (f *AckFrame) MinLength(version protocol.VersionNumber) (protocol.ByteCount, error) { + if f.AckFrameLegacy != nil { + return f.AckFrameLegacy.MinLength(version) + } + var length protocol.ByteCount length = 1 + 2 + 1 // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked)) @@ -346,6 +365,10 @@ func (f *AckFrame) MinLength(version protocol.VersionNumber) (protocol.ByteCount // HasMissingRanges returns if this frame reports any missing packets func (f *AckFrame) HasMissingRanges() bool { + if f.AckFrameLegacy != nil { + panic("HasMissingRanges() should not be called on an AckFrameLegacy") + } + if len(f.AckRanges) > 0 { return true } diff --git a/frames/ack_frame_test.go b/frames/ack_frame_test.go index 94a1c1352..e618d492e 100644 --- a/frames/ack_frame_test.go +++ b/frames/ack_frame_test.go @@ -832,4 +832,46 @@ var _ = Describe("AckFrame", func() { Expect(ack.validateAckRanges()).To(BeTrue()) }) }) + + Context("Legacy AckFrame wrapping", func() { + It("parses a ACK frame", func() { + b := bytes.NewReader([]byte{0x40, 0xA4, 0x03, 0x23, 0x45, 0x01, 0x02, 0xFF, 0xEE, 0xDD, 0xCC}) + frame, err := ParseAckFrame(b, protocol.Version32) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.AckFrameLegacy).ToNot(BeNil()) + Expect(frame.AckFrameLegacy.Entropy).To(Equal(byte(0xA4))) + Expect(frame.AckFrameLegacy.LargestObserved).To(Equal(protocol.PacketNumber(0x03))) + Expect(frame.LargestAcked).To(BeZero()) + Expect(frame.LowestAcked).To(BeZero()) + Expect(b.Len()).To(Equal(0)) + }) + + It("writes an ACK frame", func() { + b1 := &bytes.Buffer{} + b2 := &bytes.Buffer{} + ackLegacy := &AckFrameLegacy{ + Entropy: 2, + LargestObserved: 1, + } + frame := AckFrame{ + AckFrameLegacy: ackLegacy, + } + err := frame.Write(b1, protocol.Version32) + Expect(err).ToNot(HaveOccurred()) + err = ackLegacy.Write(b2, protocol.Version32) + Expect(err).ToNot(HaveOccurred()) + Expect(b1.Bytes()).To(Equal(b2.Bytes())) + }) + + It("determines the minLength", func() { + ackLegacy := &AckFrameLegacy{ + Entropy: 2, + LargestObserved: 1, + } + ack := AckFrame{AckFrameLegacy: ackLegacy} + minLengthLegacy, _ := ackLegacy.MinLength(0) + minLength, _ := ack.MinLength(0) + Expect(minLength).To(Equal(minLengthLegacy)) + }) + }) })