uquic/packet_packer_test.go

1611 lines
85 KiB
Go

package quic
import (
"bytes"
"fmt"
"math/rand"
"net"
"time"
"github.com/lucas-clemente/quic-go/internal/ackhandler"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/mocks"
mockackhandler "github.com/lucas-clemente/quic-go/internal/mocks/ackhandler"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/qerr"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Packet packer", func() {
const maxPacketSize protocol.ByteCount = 1357
const version = protocol.VersionTLS
var (
packer *packetPacker
retransmissionQueue *retransmissionQueue
datagramQueue *datagramQueue
framer *MockFrameSource
ackFramer *MockAckFrameSource
initialStream *MockCryptoStream
handshakeStream *MockCryptoStream
sealingManager *MockSealingManager
pnManager *mockackhandler.MockSentPacketHandler
)
connID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8})
parsePacket := func(data []byte) []*wire.ExtendedHeader {
var hdrs []*wire.ExtendedHeader
for len(data) > 0 {
hdr, payload, rest, err := wire.ParsePacket(data, connID.Len())
Expect(err).ToNot(HaveOccurred())
r := bytes.NewReader(data)
extHdr, err := hdr.ParseExtended(r, version)
Expect(err).ToNot(HaveOccurred())
if extHdr.IsLongHeader {
ExpectWithOffset(1, extHdr.Length).To(BeEquivalentTo(r.Len() - len(rest) + int(extHdr.PacketNumberLen)))
ExpectWithOffset(1, extHdr.Length+protocol.ByteCount(extHdr.PacketNumberLen)).To(BeNumerically(">=", 4))
} else {
ExpectWithOffset(1, len(payload)+int(extHdr.PacketNumberLen)).To(BeNumerically(">=", 4))
}
data = rest
hdrs = append(hdrs, extHdr)
}
return hdrs
}
appendFrames := func(fs, frames []ackhandler.Frame) ([]ackhandler.Frame, protocol.ByteCount) {
var length protocol.ByteCount
for _, f := range frames {
length += f.Frame.Length(packer.version)
}
return append(fs, frames...), length
}
expectAppendStreamFrames := func(frames ...ackhandler.Frame) {
framer.EXPECT().AppendStreamFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(fs []ackhandler.Frame, _ protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
return appendFrames(fs, frames)
})
}
expectAppendControlFrames := func(frames ...ackhandler.Frame) {
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(fs []ackhandler.Frame, _ protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
return appendFrames(fs, frames)
})
}
BeforeEach(func() {
rand.Seed(GinkgoRandomSeed())
retransmissionQueue = newRetransmissionQueue(version)
mockSender := NewMockStreamSender(mockCtrl)
mockSender.EXPECT().onHasStreamData(gomock.Any()).AnyTimes()
initialStream = NewMockCryptoStream(mockCtrl)
handshakeStream = NewMockCryptoStream(mockCtrl)
framer = NewMockFrameSource(mockCtrl)
ackFramer = NewMockAckFrameSource(mockCtrl)
sealingManager = NewMockSealingManager(mockCtrl)
pnManager = mockackhandler.NewMockSentPacketHandler(mockCtrl)
datagramQueue = newDatagramQueue(func() {}, utils.DefaultLogger)
packer = newPacketPacker(
protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8}),
func() protocol.ConnectionID { return connID },
initialStream,
handshakeStream,
pnManager,
retransmissionQueue,
&net.TCPAddr{},
sealingManager,
framer,
ackFramer,
datagramQueue,
protocol.PerspectiveServer,
version,
)
packer.version = version
packer.maxPacketSize = maxPacketSize
})
Context("determining the maximum packet size", func() {
It("uses the minimum initial size, if it can't determine if the remote address is IPv4 or IPv6", func() {
Expect(getMaxPacketSize(&net.TCPAddr{})).To(BeEquivalentTo(protocol.MinInitialPacketSize))
})
It("uses the maximum IPv4 packet size, if the remote address is IPv4", func() {
addr := &net.UDPAddr{IP: net.IPv4(11, 12, 13, 14), Port: 1337}
Expect(getMaxPacketSize(addr)).To(BeEquivalentTo(protocol.InitialPacketSizeIPv4))
})
It("uses the maximum IPv6 packet size, if the remote address is IPv6", func() {
ip := net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
addr := &net.UDPAddr{IP: ip, Port: 1337}
Expect(getMaxPacketSize(addr)).To(BeEquivalentTo(protocol.InitialPacketSizeIPv6))
})
})
Context("generating a packet header", func() {
It("uses the Long Header format", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen3)
h := packer.getLongHeader(protocol.EncryptionHandshake)
Expect(h.IsLongHeader).To(BeTrue())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x42)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen3))
Expect(h.Version).To(Equal(packer.version))
})
It("sets source and destination connection ID", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
srcConnID := protocol.ParseConnectionID([]byte{1, 2, 3, 4, 5, 6, 7, 8})
destConnID := protocol.ParseConnectionID([]byte{8, 7, 6, 5, 4, 3, 2, 1})
packer.srcConnID = srcConnID
packer.getDestConnID = func() protocol.ConnectionID { return destConnID }
h := packer.getLongHeader(protocol.EncryptionHandshake)
Expect(h.SrcConnectionID).To(Equal(srcConnID))
Expect(h.DestConnectionID).To(Equal(destConnID))
})
It("gets a short header", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x1337), protocol.PacketNumberLen4)
h := packer.getShortHeader(protocol.KeyPhaseOne)
Expect(h.IsLongHeader).To(BeFalse())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(h.KeyPhase).To(Equal(protocol.KeyPhaseOne))
})
})
Context("encrypting packets", func() {
It("encrypts a packet", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x1337), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x1337))
sealer := mocks.NewMockShortHeaderSealer(mockCtrl)
sealer.EXPECT().Overhead().Return(4).AnyTimes()
var hdrRaw []byte
gomock.InOrder(
sealer.EXPECT().KeyPhase().Return(protocol.KeyPhaseOne),
sealer.EXPECT().Seal(gomock.Any(), gomock.Any(), protocol.PacketNumber(0x1337), gomock.Any()).DoAndReturn(func(_, src []byte, _ protocol.PacketNumber, aad []byte) []byte {
hdrRaw = append([]byte{}, aad...)
return append(src, []byte{0xde, 0xca, 0xfb, 0xad}...)
}),
sealer.EXPECT().EncryptHeader(gomock.Any(), gomock.Any(), gomock.Any()).Do(func(sample []byte, firstByte *byte, pnBytes []byte) {
Expect(firstByte).To(Equal(&hdrRaw[0]))
Expect(pnBytes).To(Equal(hdrRaw[len(hdrRaw)-2:]))
*firstByte ^= 0xff // invert the first byte
// invert the packet number bytes
for i := range pnBytes {
pnBytes[i] ^= 0xff
}
}),
)
framer.EXPECT().HasData().Return(true)
sealingManager.EXPECT().GetInitialSealer().Return(nil, nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, nil)
sealingManager.EXPECT().Get1RTTSealer().Return(sealer, nil)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
expectAppendControlFrames()
f := &wire.StreamFrame{Data: []byte{0xde, 0xca, 0xfb, 0xad}}
expectAppendStreamFrames(ackhandler.Frame{Frame: f})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame).To(Equal(f))
hdrRawEncrypted := append([]byte{}, hdrRaw...)
hdrRawEncrypted[0] ^= 0xff
hdrRawEncrypted[len(hdrRaw)-2] ^= 0xff
hdrRawEncrypted[len(hdrRaw)-1] ^= 0xff
Expect(p.buffer.Data[0:len(hdrRaw)]).To(Equal(hdrRawEncrypted))
Expect(p.buffer.Data[p.buffer.Len()-4:]).To(Equal([]byte{0xde, 0xca, 0xfb, 0xad}))
})
})
Context("packing packets", func() {
// getSealer gets a sealer that's expected to seal exactly one packet
getSealer := func() *mocks.MockShortHeaderSealer {
sealer := mocks.NewMockShortHeaderSealer(mockCtrl)
sealer.EXPECT().KeyPhase().Return(protocol.KeyPhaseOne).AnyTimes()
sealer.EXPECT().Overhead().Return(7).AnyTimes()
sealer.EXPECT().EncryptHeader(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
sealer.EXPECT().Seal(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(dst, src []byte, pn protocol.PacketNumber, associatedData []byte) []byte {
return append(src, bytes.Repeat([]byte{'s'}, sealer.Overhead())...)
}).AnyTimes()
return sealer
}
Context("packing ACK packets", func() {
It("doesn't pack a packet if there's no ACK to send", func() {
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
p, err := packer.PackCoalescedPacket(true)
Expect(err).ToNot(HaveOccurred())
Expect(p).To(BeNil())
})
It("packs Initial ACK-only packets, and pads them (for the client)", func() {
packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).Return(ack)
p, err := packer.PackCoalescedPacket(true)
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].ack).To(Equal(ack))
Expect(p.longHdrPackets[0].frames).To(BeEmpty())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
parsePacket(p.buffer.Data)
})
It("packs Initial ACK-only packets, and doesn't pads them (for the server)", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).Return(ack)
p, err := packer.PackCoalescedPacket(true)
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].ack).To(Equal(ack))
Expect(p.longHdrPackets[0].frames).To(BeEmpty())
Expect(p.buffer.Len()).To(BeNumerically("<", 100))
parsePacket(p.buffer.Data)
})
It("packs 1-RTT ACK-only packets, before handshake confirmation", func() {
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true).Return(ack)
p, err := packer.PackCoalescedPacket(true)
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.Ack).To(Equal(ack))
Expect(p.shortHdrPacket.Frames).To(BeEmpty())
parsePacket(p.buffer.Data)
})
It("packs 1-RTT ACK-only packets, after handshake confirmation", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true).Return(ack)
p, buffer, err := packer.PackPacket(true, time.Now())
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.Ack).To(Equal(ack))
Expect(p.Frames).To(BeEmpty())
parsePacket(buffer.Data)
})
})
Context("packing 0-RTT packets", func() {
BeforeEach(func() {
packer.perspective = protocol.PerspectiveClient
sealingManager.EXPECT().GetInitialSealer().Return(nil, nil).AnyTimes()
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, nil).AnyTimes()
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable).AnyTimes()
initialStream.EXPECT().HasData().AnyTimes()
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).AnyTimes()
handshakeStream.EXPECT().HasData().AnyTimes()
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, true).AnyTimes()
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true).AnyTimes()
})
It("packs a 0-RTT packet", func() {
sealingManager.EXPECT().Get0RTTSealer().Return(getSealer(), nil).AnyTimes()
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(0x42))
cf := ackhandler.Frame{Frame: &wire.MaxDataFrame{MaximumData: 0x1337}}
framer.EXPECT().HasData().Return(true)
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(frames []ackhandler.Frame, _ protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
Expect(frames).To(BeEmpty())
return append(frames, cf), cf.Length(packer.version)
})
// TODO: check sizes
framer.EXPECT().AppendStreamFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(frames []ackhandler.Frame, _ protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
return frames, 0
})
p, err := packer.PackCoalescedPacket(false)
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].header.Type).To(Equal(protocol.PacketType0RTT))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.Encryption0RTT))
Expect(p.longHdrPackets[0].frames).To(Equal([]ackhandler.Frame{cf}))
})
})
Context("packing CONNECTION_CLOSE", func() {
It("clears the reason phrase for crypto errors", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
quicErr := qerr.NewLocalCryptoError(0x42, "crypto error")
quicErr.FrameType = 0x1234
p, err := packer.PackConnectionClose(quicErr)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].header.Type).To(Equal(protocol.PacketTypeHandshake))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf := p.longHdrPackets[0].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(0x100 + 0x42))
Expect(ccf.FrameType).To(BeEquivalentTo(0x1234))
Expect(ccf.ReasonPhrase).To(BeEmpty())
})
It("packs a CONNECTION_CLOSE in 1-RTT", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
// expect no framer.PopStreamFrames
p, err := packer.PackConnectionClose(&qerr.TransportError{
ErrorCode: qerr.CryptoBufferExceeded,
ErrorMessage: "test error",
})
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(BeEmpty())
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf := p.shortHdrPacket.Frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(qerr.CryptoBufferExceeded))
Expect(ccf.ReasonPhrase).To(Equal("test error"))
})
It("packs a CONNECTION_CLOSE in all available encryption levels, and replaces application errors in Initial and Handshake", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(1), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(1))
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(2), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(2))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(3), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(3))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
p, err := packer.PackApplicationClose(&qerr.ApplicationError{
ErrorCode: 0x1337,
ErrorMessage: "test error",
})
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.longHdrPackets[0].header.Type).To(Equal(protocol.PacketTypeInitial))
Expect(p.longHdrPackets[0].header.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf := p.longHdrPackets[0].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(qerr.ApplicationErrorErrorCode))
Expect(ccf.ReasonPhrase).To(BeEmpty())
Expect(p.longHdrPackets[1].header.Type).To(Equal(protocol.PacketTypeHandshake))
Expect(p.longHdrPackets[1].header.PacketNumber).To(Equal(protocol.PacketNumber(2)))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf = p.longHdrPackets[1].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(qerr.ApplicationErrorErrorCode))
Expect(ccf.ReasonPhrase).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.PacketNumber).To(Equal(protocol.PacketNumber(3)))
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf = p.shortHdrPacket.Frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeTrue())
Expect(ccf.ErrorCode).To(BeEquivalentTo(0x1337))
Expect(ccf.ReasonPhrase).To(Equal("test error"))
})
It("packs a CONNECTION_CLOSE in all available encryption levels, as a client", func() {
packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(1), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(1))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(2), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(2))
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
p, err := packer.PackApplicationClose(&qerr.ApplicationError{
ErrorCode: 0x1337,
ErrorMessage: "test error",
})
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.buffer.Len()).To(BeNumerically("<", protocol.MinInitialPacketSize))
Expect(p.longHdrPackets[0].header.Type).To(Equal(protocol.PacketTypeHandshake))
Expect(p.longHdrPackets[0].header.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf := p.longHdrPackets[0].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(qerr.ApplicationErrorErrorCode))
Expect(ccf.ReasonPhrase).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.PacketNumber).To(Equal(protocol.PacketNumber(2)))
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf = p.shortHdrPacket.Frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeTrue())
Expect(ccf.ErrorCode).To(BeEquivalentTo(0x1337))
Expect(ccf.ReasonPhrase).To(Equal("test error"))
})
It("packs a CONNECTION_CLOSE in all available encryption levels and pads, as a client", func() {
packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(1), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(1))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(2), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(2))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get0RTTSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
p, err := packer.PackApplicationClose(&qerr.ApplicationError{
ErrorCode: 0x1337,
ErrorMessage: "test error",
})
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(p.longHdrPackets[0].header.Type).To(Equal(protocol.PacketTypeInitial))
Expect(p.longHdrPackets[0].header.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf := p.longHdrPackets[0].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeFalse())
Expect(ccf.ErrorCode).To(BeEquivalentTo(qerr.ApplicationErrorErrorCode))
Expect(ccf.ReasonPhrase).To(BeEmpty())
Expect(p.longHdrPackets[1].header.Type).To(Equal(protocol.PacketType0RTT))
Expect(p.longHdrPackets[1].header.PacketNumber).To(Equal(protocol.PacketNumber(2)))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame).To(BeAssignableToTypeOf(&wire.ConnectionCloseFrame{}))
ccf = p.longHdrPackets[1].frames[0].Frame.(*wire.ConnectionCloseFrame)
Expect(ccf.IsApplicationError).To(BeTrue())
Expect(ccf.ErrorCode).To(BeEquivalentTo(0x1337))
Expect(ccf.ReasonPhrase).To(Equal("test error"))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].Type).To(Equal(protocol.PacketType0RTT))
})
})
Context("packing normal packets", func() {
It("returns nil when no packet is queued", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
// don't expect any calls to PopPacketNumber
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
framer.EXPECT().HasData()
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
})
It("packs single packets", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
expectAppendControlFrames()
f := &wire.StreamFrame{
StreamID: 5,
Data: []byte{0xde, 0xca, 0xfb, 0xad},
}
expectAppendStreamFrames(ackhandler.Frame{Frame: f})
p, buffer, err := packer.PackPacket(false, time.Now())
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
b, err := f.Append(nil, packer.version)
Expect(err).ToNot(HaveOccurred())
Expect(p.Frames).To(HaveLen(1))
Expect(p.Frames[0].Frame.(*wire.StreamFrame).StreamID).To(Equal(f.StreamID))
Expect(buffer.Data).To(ContainSubstring(string(b)))
})
It("packs a single ACK", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 42, Smallest: 1}}}
framer.EXPECT().HasData()
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true).Return(ack)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
p, _, err := packer.PackPacket(false, time.Now())
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.Ack).To(Equal(ack))
})
It("packs control frames", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
frames := []ackhandler.Frame{
{Frame: &wire.ResetStreamFrame{}},
{Frame: &wire.MaxDataFrame{}},
}
expectAppendControlFrames(frames...)
expectAppendStreamFrames()
p, buffer, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Frames).To(HaveLen(2))
for i, f := range p.Frames {
Expect(f).To(BeAssignableToTypeOf(frames[i]))
}
Expect(buffer.Len()).ToNot(BeZero())
})
It("packs DATAGRAM frames", func() {
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
f := &wire.DatagramFrame{
DataLenPresent: true,
Data: []byte("foobar"),
}
done := make(chan struct{})
go func() {
defer GinkgoRecover()
defer close(done)
datagramQueue.AddAndWait(f)
}()
// make sure the DATAGRAM has actually been queued
time.Sleep(scaleDuration(20 * time.Millisecond))
framer.EXPECT().HasData()
p, buffer, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Frames).To(HaveLen(1))
Expect(p.Frames[0].Frame).To(Equal(f))
Expect(buffer.Data).ToNot(BeEmpty())
Eventually(done).Should(BeClosed())
})
It("doesn't pack a DATAGRAM frame if the ACK frame is too large", func() {
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true).Return(&wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 100}}})
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
f := &wire.DatagramFrame{
DataLenPresent: true,
Data: make([]byte, maxPacketSize-10),
}
done := make(chan struct{})
go func() {
defer GinkgoRecover()
defer close(done)
datagramQueue.AddAndWait(f)
}()
// make sure the DATAGRAM has actually been queued
time.Sleep(scaleDuration(20 * time.Millisecond))
framer.EXPECT().HasData()
p, buffer, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Ack).ToNot(BeNil())
Expect(p.Frames).To(BeEmpty())
Expect(buffer.Data).ToNot(BeEmpty())
datagramQueue.CloseWithError(nil)
Eventually(done).Should(BeClosed())
})
It("accounts for the space consumed by control frames", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
var maxSize protocol.ByteCount
gomock.InOrder(
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(fs []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
maxSize = maxLen
return fs, 444
}),
framer.EXPECT().AppendStreamFrames(gomock.Any(), gomock.Any()).Do(func(fs []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
Expect(maxLen).To(Equal(maxSize - 444))
return fs, 0
}),
)
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
})
It("pads if payload length + packet number length is smaller than 4, for Long Header packets", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealer := getSealer()
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(sealer, nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
packer.retransmissionQueue.AddHandshake(&wire.PingFrame{})
handshakeStream.EXPECT().HasData()
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
packet, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(packet).ToNot(BeNil())
Expect(packet.longHdrPackets).To(HaveLen(1))
// cut off the tag that the mock sealer added
// packet.buffer.Data = packet.buffer.Data[:packet.buffer.Len()-protocol.ByteCount(sealer.Overhead())]
hdr, _, _, err := wire.ParsePacket(packet.buffer.Data, packer.getDestConnID().Len())
Expect(err).ToNot(HaveOccurred())
data := packet.buffer.Data
r := bytes.NewReader(data)
extHdr, err := hdr.ParseExtended(r, packer.version)
Expect(err).ToNot(HaveOccurred())
Expect(extHdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1))
Expect(r.Len()).To(Equal(4 - 1 /* packet number length */ + sealer.Overhead()))
// the first bytes of the payload should be a 2 PADDING frames...
firstPayloadByte, err := r.ReadByte()
Expect(err).ToNot(HaveOccurred())
Expect(firstPayloadByte).To(Equal(byte(0)))
secondPayloadByte, err := r.ReadByte()
Expect(err).ToNot(HaveOccurred())
Expect(secondPayloadByte).To(Equal(byte(0)))
// ... followed by the PING
frameParser := wire.NewFrameParser(false, packer.version)
l, frame, err := frameParser.ParseNext(data[len(data)-r.Len():], protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
Expect(r.Len() - l).To(Equal(sealer.Overhead()))
})
It("pads if payload length + packet number length is smaller than 4", func() {
f := &wire.StreamFrame{
StreamID: 0x10, // small stream ID, such that only a single byte is consumed
Fin: true,
}
Expect(f.Length(packer.version)).To(BeEquivalentTo(2))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealer := getSealer()
sealingManager.EXPECT().Get1RTTSealer().Return(sealer, nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: f})
_, buffer, err := packer.PackPacket(false, time.Now())
Expect(err).ToNot(HaveOccurred())
// cut off the tag that the mock sealer added
buffer.Data = buffer.Data[:buffer.Len()-protocol.ByteCount(sealer.Overhead())]
hdr, _, _, err := wire.ParsePacket(buffer.Data, packer.getDestConnID().Len())
Expect(err).ToNot(HaveOccurred())
data := buffer.Data
r := bytes.NewReader(data)
extHdr, err := hdr.ParseExtended(r, packer.version)
Expect(err).ToNot(HaveOccurred())
Expect(extHdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1))
Expect(r.Len()).To(Equal(4 - 1 /* packet number length */))
// the first byte of the payload should be a PADDING frame...
firstPayloadByte, err := r.ReadByte()
Expect(err).ToNot(HaveOccurred())
Expect(firstPayloadByte).To(Equal(byte(0)))
// ... followed by the STREAM frame
frameParser := wire.NewFrameParser(true, packer.version)
l, frame, err := frameParser.ParseNext(buffer.Data[len(data)-r.Len():], protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(BeAssignableToTypeOf(&wire.StreamFrame{}))
sf := frame.(*wire.StreamFrame)
Expect(sf.StreamID).To(Equal(f.StreamID))
Expect(sf.Fin).To(Equal(f.Fin))
Expect(sf.Data).To(BeEmpty())
Expect(r.Len() - l).To(BeZero())
})
It("packs multiple small STREAM frames into single packet", func() {
f1 := &wire.StreamFrame{
StreamID: 5,
Data: []byte("frame 1"),
DataLenPresent: true,
}
f2 := &wire.StreamFrame{
StreamID: 5,
Data: []byte("frame 2"),
DataLenPresent: true,
}
f3 := &wire.StreamFrame{
StreamID: 3,
Data: []byte("frame 3"),
DataLenPresent: true,
}
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: f1}, ackhandler.Frame{Frame: f2}, ackhandler.Frame{Frame: f3})
p, _, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Frames).To(HaveLen(3))
Expect(p.Frames[0].Frame.(*wire.StreamFrame).Data).To(Equal([]byte("frame 1")))
Expect(p.Frames[1].Frame.(*wire.StreamFrame).Data).To(Equal([]byte("frame 2")))
Expect(p.Frames[2].Frame.(*wire.StreamFrame).Data).To(Equal([]byte("frame 3")))
})
Context("making ACK packets ack-eliciting", func() {
sendMaxNumNonAckElicitingAcks := func() {
for i := 0; i < protocol.MaxNonAckElicitingAcks; i++ {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Return(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}})
expectAppendControlFrames()
expectAppendStreamFrames()
p, _, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Ack).ToNot(BeNil())
Expect(p.Frames).To(BeEmpty())
}
}
It("adds a PING frame when it's supposed to send a ack-eliciting packet", func() {
sendMaxNumNonAckElicitingAcks()
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Return(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}})
expectAppendControlFrames()
expectAppendStreamFrames()
p, _, err := packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
var hasPing bool
for _, f := range p.Frames {
if _, ok := f.Frame.(*wire.PingFrame); ok {
hasPing = true
Expect(f.OnLost).ToNot(BeNil()) // make sure the PING is not retransmitted if lost
}
}
Expect(hasPing).To(BeTrue())
// make sure the next packet doesn't contain another PING
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Return(&wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}})
expectAppendControlFrames()
expectAppendStreamFrames()
p, _, err = packer.PackPacket(false, time.Now())
Expect(p).ToNot(BeNil())
Expect(err).ToNot(HaveOccurred())
Expect(p.Ack).ToNot(BeNil())
Expect(p.Frames).To(BeEmpty())
})
It("waits until there's something to send before adding a PING frame", func() {
sendMaxNumNonAckElicitingAcks()
// nothing to send
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
expectAppendControlFrames()
expectAppendStreamFrames()
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
// now add some frame to send
expectAppendControlFrames()
expectAppendStreamFrames()
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 1}}}
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Return(ack)
p, _, err := packer.PackPacket(false, time.Now())
Expect(err).ToNot(HaveOccurred())
Expect(p.Ack).To(Equal(ack))
var hasPing bool
for _, f := range p.Frames {
if _, ok := f.Frame.(*wire.PingFrame); ok {
hasPing = true
Expect(f.OnLost).ToNot(BeNil()) // make sure the PING is not retransmitted if lost
}
}
Expect(hasPing).To(BeTrue())
})
It("doesn't send a PING if it already sent another ack-eliciting frame", func() {
sendMaxNumNonAckElicitingAcks()
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
expectAppendStreamFrames()
expectAppendControlFrames(ackhandler.Frame{Frame: &wire.MaxDataFrame{}})
p, _, err := packer.PackPacket(false, time.Now())
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.Frames).ToNot(ContainElement(&wire.PingFrame{}))
})
})
Context("handling transport parameters", func() {
It("lowers the maximum packet size", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2).Times(2)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil).Times(2)
framer.EXPECT().HasData().Return(true).Times(2)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Times(2)
var initialMaxPacketSize protocol.ByteCount
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
initialMaxPacketSize = maxLen
return nil, 0
})
expectAppendStreamFrames()
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
// now reduce the maxPacketSize
packer.HandleTransportParameters(&wire.TransportParameters{
MaxUDPPayloadSize: maxPacketSize - 10,
})
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
Expect(maxLen).To(Equal(initialMaxPacketSize - 10))
return nil, 0
})
expectAppendStreamFrames()
_, _, err = packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
})
It("doesn't increase the max packet size", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2).Times(2)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil).Times(2)
framer.EXPECT().HasData().Return(true).Times(2)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Times(2)
var initialMaxPacketSize protocol.ByteCount
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
initialMaxPacketSize = maxLen
return nil, 0
})
expectAppendStreamFrames()
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
// now try to increase the maxPacketSize
packer.HandleTransportParameters(&wire.TransportParameters{
MaxUDPPayloadSize: maxPacketSize + 10,
})
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
Expect(maxLen).To(Equal(initialMaxPacketSize))
return nil, 0
})
expectAppendStreamFrames()
_, _, err = packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
})
})
Context("max packet size", func() {
It("increases the max packet size", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2).Times(2)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil).Times(2)
framer.EXPECT().HasData().Return(true).Times(2)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false).Times(2)
var initialMaxPacketSize protocol.ByteCount
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
initialMaxPacketSize = maxLen
return nil, 0
})
expectAppendStreamFrames()
_, _, err := packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
// now reduce the maxPacketSize
const packetSizeIncrease = 50
packer.SetMaxPacketSize(maxPacketSize + packetSizeIncrease)
framer.EXPECT().AppendControlFrames(gomock.Any(), gomock.Any()).Do(func(_ []ackhandler.Frame, maxLen protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
Expect(maxLen).To(Equal(initialMaxPacketSize + packetSizeIncrease))
return nil, 0
})
expectAppendStreamFrames()
_, _, err = packer.PackPacket(false, time.Now())
Expect(err).To(MatchError(errNothingToPack))
})
})
})
Context("packing crypto packets", func() {
It("sets the length", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
f := &wire.CryptoFrame{
Offset: 0x1337,
Data: []byte("foobar"),
}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
handshakeStream.EXPECT().HasData().Return(true).AnyTimes()
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f)
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
parsePacket(p.buffer.Data)
})
It("packs an Initial packet and pads it", func() {
packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x42, Data: []byte("initial")}
})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("initial")))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(1))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
})
It("packs a maximum size Handshake packet", func() {
var f *wire.CryptoFrame
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
initialStream.EXPECT().HasData()
handshakeStream.EXPECT().HasData().Return(true).Times(2)
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
f = &wire.CryptoFrame{Offset: 0x1337}
f.Data = bytes.Repeat([]byte{'f'}, int(size-f.Length(packer.version)-1))
Expect(f.Length(packer.version)).To(Equal(size))
return f
})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].header.IsLongHeader).To(BeTrue())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
parsePacket(p.buffer.Data)
})
It("packs a coalesced packet with Initial / Handshake, and pads it", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
// don't EXPECT any calls for a Handshake ACK frame
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x42, Data: []byte("initial")}
})
handshakeStream.EXPECT().HasData().Return(true).Times(2)
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x1337, Data: []byte("handshake")}
})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.shortHdrPacket).To(BeNil())
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("initial")))
Expect(p.longHdrPackets[1].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("handshake")))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].Type).To(Equal(protocol.PacketTypeHandshake))
})
It("packs a coalesced packet with Initial / super short Handshake, and pads it", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
// don't EXPECT any calls for a Handshake ACK frame
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x42, Data: []byte("initial")}
})
handshakeStream.EXPECT().HasData()
packer.retransmissionQueue.AddHandshake(&wire.PingFrame{})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.shortHdrPacket).To(BeNil())
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("initial")))
Expect(p.longHdrPackets[1].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].Type).To(Equal(protocol.PacketTypeHandshake))
})
It("packs a coalesced packet with super short Initial / super short Handshake, and pads it", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, gomock.Any())
initialStream.EXPECT().HasData()
handshakeStream.EXPECT().HasData()
packer.retransmissionQueue.AddInitial(&wire.PingFrame{})
packer.retransmissionQueue.AddHandshake(&wire.PingFrame{})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
Expect(p.longHdrPackets[1].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].Type).To(Equal(protocol.PacketTypeHandshake))
})
It("packs a coalesced packet with Initial / super short 1-RTT, and pads it", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x42, Data: []byte("initial")}
})
expectAppendControlFrames()
expectAppendStreamFrames()
framer.EXPECT().HasData().Return(true)
packer.retransmissionQueue.AddAppData(&wire.PingFrame{})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("initial")))
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].IsLongHeader).To(BeFalse())
})
It("packs a coalesced packet with Initial / 0-RTT, and pads it", func() {
packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption0RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get0RTTSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
// don't EXPECT any calls for a Handshake ACK frame
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x42, Data: []byte("initial")}
})
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: &wire.StreamFrame{Data: []byte("foobar")}})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(2))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("initial")))
Expect(p.longHdrPackets[1].EncryptionLevel()).To(Equal(protocol.Encryption0RTT))
Expect(p.longHdrPackets[1].frames).To(HaveLen(1))
Expect(p.longHdrPackets[1].frames[0].Frame.(*wire.StreamFrame).Data).To(Equal([]byte("foobar")))
hdrs := parsePacket(p.buffer.Data)
Expect(hdrs).To(HaveLen(2))
Expect(hdrs[0].Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdrs[1].Type).To(Equal(protocol.PacketType0RTT))
})
It("packs a coalesced packet with Handshake / 1-RTT", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24))
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
framer.EXPECT().HasData().Return(true)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
// don't EXPECT any calls for a 1-RTT ACK frame
handshakeStream.EXPECT().HasData().Return(true).Times(2)
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
return &wire.CryptoFrame{Offset: 0x1337, Data: []byte("handshake")}
})
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: &wire.StreamFrame{Data: []byte("foobar")}})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeNumerically("<", 100))
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame).Data).To(Equal([]byte("handshake")))
Expect(p.shortHdrPacket).ToNot(BeNil())
Expect(p.shortHdrPacket.Frames).To(HaveLen(1))
Expect(p.shortHdrPacket.Frames[0].Frame.(*wire.StreamFrame).Data).To(Equal([]byte("foobar")))
hdr, _, rest, err := wire.ParsePacket(p.buffer.Data, 0)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.Type).To(Equal(protocol.PacketTypeHandshake))
hdr, _, rest, err = wire.ParsePacket(rest, 0)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsLongHeader).To(BeFalse())
Expect(rest).To(BeEmpty())
})
It("doesn't add a coalesced packet if the remaining size is smaller than MaxCoalescedPacketSize", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24))
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
// don't EXPECT any calls to GetHandshakeSealer and Get1RTTSealer
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
handshakeStream.EXPECT().HasData().Return(true).Times(2)
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
s := size - protocol.MinCoalescedPacketSize
f := &wire.CryptoFrame{Offset: 0x1337}
f.Data = bytes.Repeat([]byte{'f'}, int(s-f.Length(packer.version)-1))
Expect(f.Length(packer.version)).To(Equal(s))
return f
})
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.shortHdrPacket).To(BeNil())
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(len(p.buffer.Data)).To(BeEquivalentTo(maxPacketSize - protocol.MinCoalescedPacketSize))
parsePacket(p.buffer.Data)
})
It("pads if payload length + packet number length is smaller than 4, for Long Header packets", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
sealer := getSealer()
sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(sealer, nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
packer.retransmissionQueue.AddHandshake(&wire.PingFrame{})
handshakeStream.EXPECT().HasData()
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
packet, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(packet).ToNot(BeNil())
Expect(packet.longHdrPackets).To(HaveLen(1))
Expect(packet.shortHdrPacket).To(BeNil())
// cut off the tag that the mock sealer added
// packet.buffer.Data = packet.buffer.Data[:packet.buffer.Len()-protocol.ByteCount(sealer.Overhead())]
hdr, _, _, err := wire.ParsePacket(packet.buffer.Data, packer.getDestConnID().Len())
Expect(err).ToNot(HaveOccurred())
data := packet.buffer.Data
r := bytes.NewReader(data)
extHdr, err := hdr.ParseExtended(r, packer.version)
Expect(err).ToNot(HaveOccurred())
Expect(extHdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1))
Expect(r.Len()).To(Equal(4 - 1 /* packet number length */ + sealer.Overhead()))
// the first bytes of the payload should be a 2 PADDING frames...
firstPayloadByte, err := r.ReadByte()
Expect(err).ToNot(HaveOccurred())
Expect(firstPayloadByte).To(Equal(byte(0)))
secondPayloadByte, err := r.ReadByte()
Expect(err).ToNot(HaveOccurred())
Expect(secondPayloadByte).To(Equal(byte(0)))
// ... followed by the PING
frameParser := wire.NewFrameParser(false, packer.version)
l, frame, err := frameParser.ParseNext(data[len(data)-r.Len():], protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
Expect(r.Len() - l).To(Equal(sealer.Overhead()))
})
It("adds retransmissions", func() {
f := &wire.CryptoFrame{Data: []byte("Initial")}
retransmissionQueue.AddInitial(f)
retransmissionQueue.AddHandshake(&wire.CryptoFrame{Data: []byte("Handshake")})
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData()
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.longHdrPackets[0].frames).To(Equal([]ackhandler.Frame{{Frame: f}}))
Expect(p.longHdrPackets[0].header.IsLongHeader).To(BeTrue())
})
It("sends an Initial packet containing only an ACK", func() {
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 10, Largest: 20}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).Return(ack)
initialStream.EXPECT().HasData().Times(2)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].ack).To(Equal(ack))
})
It("doesn't pack anything if there's nothing to send at Initial and Handshake keys are not yet available", func() {
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
initialStream.EXPECT().HasData()
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true)
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p).To(BeNil())
})
It("sends a Handshake packet containing only an ACK", func() {
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 10, Largest: 20}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, true).Return(ack)
initialStream.EXPECT().HasData()
handshakeStream.EXPECT().HasData().Times(2)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].ack).To(Equal(ack))
})
for _, pers := range []protocol.Perspective{protocol.PerspectiveServer, protocol.PerspectiveClient} {
perspective := pers
It(fmt.Sprintf("pads Initial packets to the required minimum packet size, for the %s", perspective), func() {
token := []byte("initial token")
packer.SetToken(token)
f := &wire.CryptoFrame{Data: []byte("foobar")}
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f)
packer.perspective = protocol.PerspectiveClient
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].header.Token).To(Equal(token))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
cf := p.longHdrPackets[0].frames[0].Frame.(*wire.CryptoFrame)
Expect(cf.Data).To(Equal([]byte("foobar")))
})
}
It("adds an ACK frame", func() {
f := &wire.CryptoFrame{Data: []byte("foobar")}
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 42, Largest: 1337}}}
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false).Return(ack)
initialStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f)
packer.version = protocol.VersionTLS
packer.perspective = protocol.PerspectiveClient
p, err := packer.PackCoalescedPacket(false)
Expect(err).ToNot(HaveOccurred())
Expect(p.longHdrPackets).To(HaveLen(1))
Expect(p.longHdrPackets[0].ack).To(Equal(ack))
Expect(p.longHdrPackets[0].frames).To(HaveLen(1))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
})
})
Context("packing probe packets", func() {
for _, pers := range []protocol.Perspective{protocol.PerspectiveServer, protocol.PerspectiveClient} {
perspective := pers
It(fmt.Sprintf("packs an Initial probe packet and pads it, for the %s", perspective), func() {
packer.perspective = perspective
f := &wire.CryptoFrame{Data: []byte("Initial")}
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
p, err := packer.MaybePackProbePacket(protocol.EncryptionInitial)
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
packet := p.longHdrPackets[0]
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
parsePacket(p.buffer.Data)
})
It(fmt.Sprintf("packs an Initial probe packet with 1 byte payload, for the %s", perspective), func() {
packer.perspective = perspective
retransmissionQueue.AddInitial(&wire.PingFrame{})
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen1)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
p, err := packer.MaybePackProbePacket(protocol.EncryptionInitial)
Expect(err).ToNot(HaveOccurred())
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
packet := p.longHdrPackets[0]
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(BeAssignableToTypeOf(&wire.PingFrame{}))
parsePacket(p.buffer.Data)
})
}
It("packs a Handshake probe packet", func() {
f := &wire.CryptoFrame{Data: []byte("Handshake")}
retransmissionQueue.AddHandshake(f)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
handshakeStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
p, err := packer.MaybePackProbePacket(protocol.EncryptionHandshake)
Expect(err).ToNot(HaveOccurred())
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
packet := p.longHdrPackets[0]
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
parsePacket(p.buffer.Data)
})
It("packs a full size Handshake probe packet", func() {
f := &wire.CryptoFrame{Data: make([]byte, 2000)}
retransmissionQueue.AddHandshake(f)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
handshakeStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
p, err := packer.MaybePackProbePacket(protocol.EncryptionHandshake)
Expect(err).ToNot(HaveOccurred())
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(HaveLen(1))
packet := p.longHdrPackets[0]
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
Expect(packet.length).To(Equal(maxPacketSize))
parsePacket(p.buffer.Data)
})
It("packs a 1-RTT probe packet", func() {
f := &wire.StreamFrame{Data: []byte("1-RTT")}
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
framer.EXPECT().HasData().Return(true)
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: f})
p, err := packer.MaybePackProbePacket(protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
packet := p.shortHdrPacket
Expect(packet.Frames).To(HaveLen(1))
Expect(packet.Frames[0].Frame).To(Equal(f))
})
It("packs a full size 1-RTT probe packet", func() {
f := &wire.StreamFrame{Data: make([]byte, 2000)}
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, false)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
framer.EXPECT().HasData().Return(true)
expectAppendControlFrames()
framer.EXPECT().AppendStreamFrames(gomock.Any(), gomock.Any()).DoAndReturn(func(fs []ackhandler.Frame, maxSize protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount) {
sf, split := f.MaybeSplitOffFrame(maxSize, packer.version)
Expect(split).To(BeTrue())
return append(fs, ackhandler.Frame{Frame: sf}), sf.Length(packer.version)
})
p, err := packer.MaybePackProbePacket(protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.longHdrPackets).To(BeEmpty())
Expect(p.shortHdrPacket).ToNot(BeNil())
packet := p.shortHdrPacket
Expect(packet.Frames).To(HaveLen(1))
Expect(packet.Frames[0].Frame).To(BeAssignableToTypeOf(&wire.StreamFrame{}))
Expect(packet.Length).To(Equal(maxPacketSize))
})
It("returns nil if there's no probe data to send", func() {
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
framer.EXPECT().HasData()
packet, err := packer.MaybePackProbePacket(protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(packet).To(BeNil())
})
It("packs an MTU probe packet", func() {
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x43), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x43))
ping := ackhandler.Frame{Frame: &wire.PingFrame{}}
const probePacketSize = maxPacketSize + 42
p, buffer, err := packer.PackMTUProbePacket(ping, probePacketSize, time.Now())
Expect(err).ToNot(HaveOccurred())
Expect(p.Length).To(BeEquivalentTo(probePacketSize))
Expect(p.PacketNumber).To(Equal(protocol.PacketNumber(0x43)))
Expect(buffer.Data).To(HaveLen(int(probePacketSize)))
Expect(p.IsPathMTUProbePacket).To(BeTrue())
})
})
})
})
var _ = Describe("Converting to ackhandler.Packet", func() {
It("convert a packet", func() {
packet := &longHeaderPacket{
header: &wire.ExtendedHeader{Header: wire.Header{IsLongHeader: true, Type: protocol.PacketTypeInitial}},
frames: []ackhandler.Frame{{Frame: &wire.MaxDataFrame{}}, {Frame: &wire.PingFrame{}}},
ack: &wire.AckFrame{AckRanges: []wire.AckRange{{Largest: 100, Smallest: 80}}},
length: 42,
}
t := time.Now()
p := packet.ToAckHandlerPacket(t, nil)
Expect(p.Length).To(Equal(protocol.ByteCount(42)))
Expect(p.Frames).To(Equal(packet.frames))
Expect(p.LargestAcked).To(Equal(protocol.PacketNumber(100)))
Expect(p.SendTime).To(Equal(t))
})
It("sets the LargestAcked to invalid, if the packet doesn't have an ACK frame", func() {
packet := &longHeaderPacket{
header: &wire.ExtendedHeader{Header: wire.Header{IsLongHeader: true, Type: protocol.PacketTypeHandshake}},
frames: []ackhandler.Frame{{Frame: &wire.MaxDataFrame{}}, {Frame: &wire.PingFrame{}}},
}
p := packet.ToAckHandlerPacket(time.Now(), nil)
Expect(p.LargestAcked).To(Equal(protocol.InvalidPacketNumber))
})
DescribeTable(
"doesn't overwrite the OnLost callback, if it is set",
func(hdr wire.Header) {
var pingLost bool
packet := &longHeaderPacket{
header: &wire.ExtendedHeader{Header: hdr},
frames: []ackhandler.Frame{
{Frame: &wire.MaxDataFrame{}},
{Frame: &wire.PingFrame{}, OnLost: func(wire.Frame) { pingLost = true }},
},
}
p := packet.ToAckHandlerPacket(time.Now(), newRetransmissionQueue(protocol.VersionTLS))
Expect(p.Frames).To(HaveLen(2))
Expect(p.Frames[0].OnLost).ToNot(BeNil())
p.Frames[1].OnLost(nil)
Expect(pingLost).To(BeTrue())
},
Entry(protocol.EncryptionInitial.String(), wire.Header{IsLongHeader: true, Type: protocol.PacketTypeInitial}),
Entry(protocol.EncryptionHandshake.String(), wire.Header{IsLongHeader: true, Type: protocol.PacketTypeHandshake}),
Entry(protocol.Encryption0RTT.String(), wire.Header{IsLongHeader: true, Type: protocol.PacketType0RTT}),
)
})