diff --git a/packet_packer.go b/packet_packer.go index 7be70388..04668438 100644 --- a/packet_packer.go +++ b/packet_packer.go @@ -157,10 +157,22 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP frames = append(frames, frame) controlFrames = controlFrames[1:] } + + // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field + // this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set + // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size + // for gQUIC STREAM frames, DataLen is always 2 bytes + // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes + if p.version.UsesIETFFrameFormat() { + maxSize++ + } else { + maxSize += 2 + } for len(streamFrames) > 0 && payloadLength+protocol.MinStreamFrameSize < maxSize { // TODO: optimize by setting DataLenPresent = false on all but the last STREAM frame frame := streamFrames[0] frameToAdd := frame + sf, err := frame.MaybeSplitOffFrame(maxSize-payloadLength, p.version) if err != nil { return nil, err @@ -173,6 +185,9 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP payloadLength += frameToAdd.Length(p.version) frames = append(frames, frameToAdd) } + if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok { + sf.DataLenPresent = false + } raw, err := p.writeAndSealPacket(header, frames, sealer) if err != nil { return nil, err @@ -351,7 +366,7 @@ func (p *packetPacker) composeNextPacket( // temporarily increase the maxFrameSize by the (minimum) length of the DataLen field // this leads to a properly sized packet in all cases, since we do all the packet length calculations with StreamFrames that have the DataLen set - // however, for the last StreamFrame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size + // however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size // for gQUIC STREAM frames, DataLen is always 2 bytes // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes if p.version.UsesIETFFrameFormat() { diff --git a/packet_packer_test.go b/packet_packer_test.go index a85adeed..57ab1b26 100644 --- a/packet_packer_test.go +++ b/packet_packer_test.go @@ -809,8 +809,10 @@ var _ = Describe("Packet packer", func() { sf2 := packets[1].frames[1].(*wire.StreamFrame) Expect(sf1.StreamID).To(Equal(protocol.StreamID(42))) Expect(sf1.Offset).To(Equal(protocol.ByteCount(1337))) + Expect(sf1.DataLenPresent).To(BeFalse()) Expect(sf2.StreamID).To(Equal(protocol.StreamID(42))) Expect(sf2.Offset).To(Equal(protocol.ByteCount(1337) + sf1.DataLen())) + Expect(sf2.DataLenPresent).To(BeFalse()) Expect(sf1.DataLen() + sf2.DataLen()).To(Equal(protocol.MaxPacketSize * 3 / 2)) Expect(packets[0].raw).To(HaveLen(int(protocol.MaxPacketSize))) }) @@ -844,6 +846,29 @@ var _ = Describe("Packet packer", func() { Expect(len(packets[0].raw) + int(packets[1].frames[1].Length(packer.version))).To(BeNumerically(">", protocol.MaxPacketSize-protocol.MinStreamFrameSize)) }) + It("correctly sets the DataLenPresent on STREAM frames", func() { + frames := []wire.Frame{ + &wire.StreamFrame{StreamID: 4, Data: []byte("foobar"), DataLenPresent: true}, + &wire.StreamFrame{StreamID: 5, Data: []byte("barfoo")}, + } + packets, err := packer.PackRetransmission(&ackhandler.Packet{ + EncryptionLevel: protocol.EncryptionForwardSecure, + Frames: frames, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(packets).To(HaveLen(1)) + p := packets[0] + Expect(p.frames).To(HaveLen(3)) + Expect(p.frames[1]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + Expect(p.frames[2]).To(BeAssignableToTypeOf(&wire.StreamFrame{})) + sf1 := p.frames[1].(*wire.StreamFrame) + sf2 := p.frames[2].(*wire.StreamFrame) + Expect(sf1.StreamID).To(Equal(protocol.StreamID(4))) + Expect(sf1.DataLenPresent).To(BeTrue()) + Expect(sf2.StreamID).To(Equal(protocol.StreamID(5))) + Expect(sf2.DataLenPresent).To(BeFalse()) + }) + }) Context("packing ACK packets", func() {