implement a function to pack probe packets

This commit is contained in:
Marten Seemann 2019-11-11 15:12:58 +07:00
parent 5f14b03135
commit fbbe225719
3 changed files with 135 additions and 45 deletions

View file

@ -9,6 +9,7 @@ import (
gomock "github.com/golang/mock/gomock"
handshake "github.com/lucas-clemente/quic-go/internal/handshake"
protocol "github.com/lucas-clemente/quic-go/internal/protocol"
wire "github.com/lucas-clemente/quic-go/internal/wire"
)
@ -62,6 +63,21 @@ func (mr *MockPackerMockRecorder) MaybePackAckPacket() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybePackAckPacket", reflect.TypeOf((*MockPacker)(nil).MaybePackAckPacket))
}
// MaybePackProbePacket mocks base method
func (m *MockPacker) MaybePackProbePacket(arg0 protocol.EncryptionLevel) (*packedPacket, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MaybePackProbePacket", arg0)
ret0, _ := ret[0].(*packedPacket)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// MaybePackProbePacket indicates an expected call of MaybePackProbePacket
func (mr *MockPackerMockRecorder) MaybePackProbePacket(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MaybePackProbePacket", reflect.TypeOf((*MockPacker)(nil).MaybePackProbePacket), arg0)
}
// PackConnectionClose mocks base method
func (m *MockPacker) PackConnectionClose(arg0 *wire.ConnectionCloseFrame) (*packedPacket, error) {
m.ctrl.T.Helper()

View file

@ -16,6 +16,7 @@ import (
type packer interface {
PackPacket() (*packedPacket, error)
MaybePackProbePacket(protocol.EncryptionLevel) (*packedPacket, error)
MaybePackAckPacket() (*packedPacket, error)
PackConnectionClose(*wire.ConnectionCloseFrame) (*packedPacket, error)
@ -270,54 +271,32 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
}
}
sealer, err := p.cryptoSetup.Get1RTTSealer()
if err != nil {
// sealer not yet available
return nil, nil
}
header := p.getShortHeader(sealer.KeyPhase())
headerLen := header.GetLength(p.version)
maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen
payload := p.composeNextPacket(maxSize)
// check if we have anything to send
if len(payload.frames) == 0 && payload.ack == nil {
return nil, nil
}
if len(payload.frames) == 0 { // the packet only contains an ACK
if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
ping := &wire.PingFrame{}
payload.frames = append(payload.frames, ackhandler.Frame{Frame: ping})
payload.length += ping.Length(p.version)
p.numNonAckElicitingAcks = 0
} else {
p.numNonAckElicitingAcks++
}
} else {
p.numNonAckElicitingAcks = 0
}
return p.writeAndSealPacket(header, payload, protocol.Encryption1RTT, sealer)
return p.maybePackAppDataPacket()
}
func (p *packetPacker) maybePackCryptoPacket() (*packedPacket, error) {
// Try packing an Initial packet.
packet, err := p.maybePackInitialPacket()
if err != nil {
return nil, err
if err == handshake.ErrKeysDropped {
p.droppedInitial = true
} else if err != nil || packet != nil {
return packet, err
}
if packet != nil {
return packet, nil
// No Initial was packed. Try packing a Handshake packet.
packet, err = p.maybePackHandshakePacket()
if err == handshake.ErrKeysDropped {
p.droppedHandshake = true
return nil, nil
}
return p.maybePackHandshakePacket()
if err == handshake.ErrKeysNotYetAvailable {
return nil, nil
}
return packet, err
}
func (p *packetPacker) maybePackInitialPacket() (*packedPacket, error) {
sealer, err := p.cryptoSetup.GetInitialSealer()
if err == handshake.ErrKeysDropped {
p.droppedInitial = true
return nil, nil
}
if err != nil {
return nil, err
}
@ -333,13 +312,7 @@ func (p *packetPacker) maybePackInitialPacket() (*packedPacket, error) {
func (p *packetPacker) maybePackHandshakePacket() (*packedPacket, error) {
sealer, err := p.cryptoSetup.GetHandshakeSealer()
if err == handshake.ErrKeysDropped {
p.droppedHandshake = true
return nil, nil
}
if err == handshake.ErrKeysNotYetAvailable {
return nil, nil
}
if err != nil {
return nil, err
}
@ -396,6 +369,38 @@ func (p *packetPacker) packCryptoPacket(
return p.writeAndSealPacket(hdr, payload, encLevel, sealer)
}
func (p *packetPacker) maybePackAppDataPacket() (*packedPacket, error) {
sealer, err := p.cryptoSetup.Get1RTTSealer()
if err != nil {
// sealer not yet available
return nil, nil
}
header := p.getShortHeader(sealer.KeyPhase())
headerLen := header.GetLength(p.version)
maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen
payload := p.composeNextPacket(maxSize)
// check if we have anything to send
if len(payload.frames) == 0 && payload.ack == nil {
return nil, nil
}
if len(payload.frames) == 0 { // the packet only contains an ACK
if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
ping := &wire.PingFrame{}
payload.frames = append(payload.frames, ackhandler.Frame{Frame: ping})
payload.length += ping.Length(p.version)
p.numNonAckElicitingAcks = 0
} else {
p.numNonAckElicitingAcks++
}
} else {
p.numNonAckElicitingAcks = 0
}
return p.writeAndSealPacket(header, payload, protocol.Encryption1RTT, sealer)
}
func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount) payload {
var payload payload
@ -426,6 +431,19 @@ func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount) payloa
return payload
}
func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel) (*packedPacket, error) {
switch encLevel {
case protocol.EncryptionInitial:
return p.maybePackInitialPacket()
case protocol.EncryptionHandshake:
return p.maybePackHandshakePacket()
case protocol.Encryption1RTT:
return p.maybePackAppDataPacket()
default:
panic("unknown encryption level")
}
}
func (p *packetPacker) getSealerAndHeader(encLevel protocol.EncryptionLevel) (sealer, *wire.ExtendedHeader, error) {
switch encLevel {
case protocol.EncryptionInitial:

View file

@ -730,6 +730,62 @@ var _ = Describe("Packet packer", func() {
Expect(packet).ToNot(BeNil())
})
})
Context("packing probe packets", func() {
It("packs an Initial probe packet", func() {
f := &wire.CryptoFrame{Data: []byte("Initial")}
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().GetInitialSealer().Return(sealer, nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial)
initialStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
packet, err := packer.MaybePackProbePacket(protocol.EncryptionInitial)
Expect(err).ToNot(HaveOccurred())
Expect(packet).ToNot(BeNil())
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
checkLength(packet.raw)
})
It("packs a Handshake probe packet", func() {
f := &wire.CryptoFrame{Data: []byte("Handshake")}
retransmissionQueue.AddHandshake(f)
sealingManager.EXPECT().GetHandshakeSealer().Return(sealer, nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake)
handshakeStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
packet, err := packer.MaybePackProbePacket(protocol.EncryptionHandshake)
Expect(err).ToNot(HaveOccurred())
Expect(packet).ToNot(BeNil())
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
checkLength(packet.raw)
})
It("packs a 1-RTT probe packet", func() {
f := &wire.StreamFrame{Data: []byte("1-RTT")}
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().Get1RTTSealer().Return(sealer, nil)
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT)
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42))
expectAppendControlFrames()
expectAppendStreamFrames(ackhandler.Frame{Frame: f})
packet, err := packer.MaybePackProbePacket(protocol.Encryption1RTT)
Expect(err).ToNot(HaveOccurred())
Expect(packet).ToNot(BeNil())
Expect(packet.EncryptionLevel()).To(Equal(protocol.Encryption1RTT))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
})
})
})
})