mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 21:27:35 +03:00
Merge pull request #2882 from lucas-clemente/fix-1rtt-probe-packet-packing
fix packing of 1-RTT probe packets
This commit is contained in:
commit
287a324acf
3 changed files with 72 additions and 27 deletions
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
mrand "math/rand"
|
mrand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
@ -31,6 +32,7 @@ var _ = Describe("Handshake drop tests", func() {
|
||||||
ln quic.Listener
|
ln quic.Listener
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data := GeneratePRData(5000)
|
||||||
const timeout = 2 * time.Minute
|
const timeout = 2 * time.Minute
|
||||||
|
|
||||||
startListenerAndProxy := func(dropCallback quicproxy.DropCallback, doRetry bool, longCertChain bool, version protocol.VersionNumber) {
|
startListenerAndProxy := func(dropCallback quicproxy.DropCallback, doRetry bool, longCertChain bool, version protocol.VersionNumber) {
|
||||||
|
@ -77,10 +79,9 @@ var _ = Describe("Handshake drop tests", func() {
|
||||||
defer sess.CloseWithError(0, "")
|
defer sess.CloseWithError(0, "")
|
||||||
str, err := sess.AcceptStream(context.Background())
|
str, err := sess.AcceptStream(context.Background())
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
b := make([]byte, 6)
|
b, err := ioutil.ReadAll(gbytes.TimeoutReader(str, timeout))
|
||||||
_, err = gbytes.TimeoutReader(str, 10*time.Second).Read(b)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(string(b)).To(Equal("foobar"))
|
Expect(b).To(Equal(data))
|
||||||
serverSessionChan <- sess
|
serverSessionChan <- sess
|
||||||
}()
|
}()
|
||||||
sess, err := quic.DialAddr(
|
sess, err := quic.DialAddr(
|
||||||
|
@ -95,8 +96,9 @@ var _ = Describe("Handshake drop tests", func() {
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
str, err := sess.OpenStream()
|
str, err := sess.OpenStream()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = str.Write([]byte("foobar"))
|
_, err = str.Write(data)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(str.Close()).To(Succeed())
|
||||||
|
|
||||||
var serverSession quic.Session
|
var serverSession quic.Session
|
||||||
Eventually(serverSessionChan, timeout).Should(Receive(&serverSession))
|
Eventually(serverSessionChan, timeout).Should(Receive(&serverSession))
|
||||||
|
@ -115,8 +117,9 @@ var _ = Describe("Handshake drop tests", func() {
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
str, err := sess.OpenStream()
|
str, err := sess.OpenStream()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = str.Write([]byte("foobar"))
|
_, err = str.Write(data)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(str.Close()).To(Succeed())
|
||||||
serverSessionChan <- sess
|
serverSessionChan <- sess
|
||||||
}()
|
}()
|
||||||
sess, err := quic.DialAddr(
|
sess, err := quic.DialAddr(
|
||||||
|
@ -131,10 +134,9 @@ var _ = Describe("Handshake drop tests", func() {
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
str, err := sess.AcceptStream(context.Background())
|
str, err := sess.AcceptStream(context.Background())
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
b := make([]byte, 6)
|
b, err := ioutil.ReadAll(gbytes.TimeoutReader(str, timeout))
|
||||||
_, err = gbytes.TimeoutReader(str, 10*time.Second).Read(b)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(string(b)).To(Equal("foobar"))
|
Expect(b).To(Equal(data))
|
||||||
|
|
||||||
var serverSession quic.Session
|
var serverSession quic.Session
|
||||||
Eventually(serverSessionChan, timeout).Should(Receive(&serverSession))
|
Eventually(serverSessionChan, timeout).Should(Receive(&serverSession))
|
||||||
|
|
|
@ -467,7 +467,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *packetPacker) maybeGetCryptoPacket(maxSize, currentSize protocol.ByteCount, encLevel protocol.EncryptionLevel) (*wire.ExtendedHeader, *payload) {
|
func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize, currentSize protocol.ByteCount, encLevel protocol.EncryptionLevel) (*wire.ExtendedHeader, *payload) {
|
||||||
var s cryptoStream
|
var s cryptoStream
|
||||||
var hasRetransmission bool
|
var hasRetransmission bool
|
||||||
//nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
|
//nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
|
||||||
|
@ -494,19 +494,19 @@ func (p *packetPacker) maybeGetCryptoPacket(maxSize, currentSize protocol.ByteCo
|
||||||
if ack != nil {
|
if ack != nil {
|
||||||
payload.ack = ack
|
payload.ack = ack
|
||||||
payload.length = ack.Length(p.version)
|
payload.length = ack.Length(p.version)
|
||||||
maxSize -= payload.length
|
maxPacketSize -= payload.length
|
||||||
}
|
}
|
||||||
hdr := p.getLongHeader(encLevel)
|
hdr := p.getLongHeader(encLevel)
|
||||||
maxSize -= hdr.GetLength(p.version)
|
maxPacketSize -= hdr.GetLength(p.version)
|
||||||
if hasRetransmission {
|
if hasRetransmission {
|
||||||
for {
|
for {
|
||||||
var f wire.Frame
|
var f wire.Frame
|
||||||
//nolint:exhaustive // 0-RTT packets can't contain any retransmission.s
|
//nolint:exhaustive // 0-RTT packets can't contain any retransmission.s
|
||||||
switch encLevel {
|
switch encLevel {
|
||||||
case protocol.EncryptionInitial:
|
case protocol.EncryptionInitial:
|
||||||
f = p.retransmissionQueue.GetInitialFrame(maxSize)
|
f = p.retransmissionQueue.GetInitialFrame(maxPacketSize)
|
||||||
case protocol.EncryptionHandshake:
|
case protocol.EncryptionHandshake:
|
||||||
f = p.retransmissionQueue.GetHandshakeFrame(maxSize)
|
f = p.retransmissionQueue.GetHandshakeFrame(maxPacketSize)
|
||||||
}
|
}
|
||||||
if f == nil {
|
if f == nil {
|
||||||
break
|
break
|
||||||
|
@ -514,10 +514,10 @@ func (p *packetPacker) maybeGetCryptoPacket(maxSize, currentSize protocol.ByteCo
|
||||||
payload.frames = append(payload.frames, ackhandler.Frame{Frame: f})
|
payload.frames = append(payload.frames, ackhandler.Frame{Frame: f})
|
||||||
frameLen := f.Length(p.version)
|
frameLen := f.Length(p.version)
|
||||||
payload.length += frameLen
|
payload.length += frameLen
|
||||||
maxSize -= frameLen
|
maxPacketSize -= frameLen
|
||||||
}
|
}
|
||||||
} else if s.HasData() {
|
} else if s.HasData() {
|
||||||
cf := s.PopCryptoFrame(maxSize)
|
cf := s.PopCryptoFrame(maxPacketSize)
|
||||||
payload.frames = []ackhandler.Frame{{Frame: cf}}
|
payload.frames = []ackhandler.Frame{{Frame: cf}}
|
||||||
payload.length += cf.Length(p.version)
|
payload.length += cf.Length(p.version)
|
||||||
}
|
}
|
||||||
|
@ -547,18 +547,19 @@ func (p *packetPacker) maybeGetAppDataPacket(maxPacketSize, currentSize protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
maxPayloadSize := maxPacketSize - hdr.GetLength(p.version) - protocol.ByteCount(sealer.Overhead())
|
maxPayloadSize := maxPacketSize - hdr.GetLength(p.version) - protocol.ByteCount(sealer.Overhead())
|
||||||
payload := p.maybeGetAppDataPacketWithEncLevel(maxPayloadSize, currentSize, encLevel)
|
payload := p.maybeGetAppDataPacketWithEncLevel(maxPayloadSize, encLevel == protocol.Encryption1RTT && currentSize == 0)
|
||||||
return sealer, hdr, payload
|
return sealer, hdr, payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *packetPacker) maybeGetAppDataPacketWithEncLevel(maxPayloadSize, currentSize protocol.ByteCount, encLevel protocol.EncryptionLevel) *payload {
|
func (p *packetPacker) maybeGetAppDataPacketWithEncLevel(maxPayloadSize protocol.ByteCount, ackAllowed bool) *payload {
|
||||||
payload := p.composeNextPacket(maxPayloadSize, encLevel == protocol.Encryption1RTT && currentSize == 0)
|
payload := p.composeNextPacket(maxPayloadSize, ackAllowed)
|
||||||
|
|
||||||
// check if we have anything to send
|
// check if we have anything to send
|
||||||
if len(payload.frames) == 0 && payload.ack == nil {
|
if len(payload.frames) == 0 {
|
||||||
|
if payload.ack == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if len(payload.frames) == 0 { // the packet only contains an ACK
|
// the packet only contains an ACK
|
||||||
if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
|
if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
|
||||||
ping := &wire.PingFrame{}
|
ping := &wire.PingFrame{}
|
||||||
payload.frames = append(payload.frames, ackhandler.Frame{Frame: ping})
|
payload.frames = append(payload.frames, ackhandler.Frame{Frame: ping})
|
||||||
|
@ -642,14 +643,12 @@ func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel) (
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sealer = oneRTTSealer
|
sealer = oneRTTSealer
|
||||||
payload = p.maybeGetAppDataPacketWithEncLevel(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), 0, protocol.Encryption1RTT)
|
|
||||||
if payload != nil {
|
|
||||||
hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
|
hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
|
||||||
}
|
payload = p.maybeGetAppDataPacketWithEncLevel(p.maxPacketSize-protocol.ByteCount(sealer.Overhead())-hdr.GetLength(p.version), true)
|
||||||
default:
|
default:
|
||||||
panic("unknown encryption level")
|
panic("unknown encryption level")
|
||||||
}
|
}
|
||||||
if hdr == nil {
|
if payload == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
size := p.packetLength(hdr, payload) + protocol.ByteCount(sealer.Overhead())
|
size := p.packetLength(hdr, payload) + protocol.ByteCount(sealer.Overhead())
|
||||||
|
|
|
@ -1322,6 +1322,25 @@ var _ = Describe("Packet packer", func() {
|
||||||
parsePacket(packet.buffer.Data)
|
parsePacket(packet.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))
|
||||||
|
|
||||||
|
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(BeAssignableToTypeOf(&wire.CryptoFrame{}))
|
||||||
|
Expect(packet.length).To(Equal(maxPacketSize))
|
||||||
|
parsePacket(packet.buffer.Data)
|
||||||
|
})
|
||||||
|
|
||||||
It("packs a 1-RTT probe packet", func() {
|
It("packs a 1-RTT probe packet", func() {
|
||||||
f := &wire.StreamFrame{Data: []byte("1-RTT")}
|
f := &wire.StreamFrame{Data: []byte("1-RTT")}
|
||||||
retransmissionQueue.AddInitial(f)
|
retransmissionQueue.AddInitial(f)
|
||||||
|
@ -1341,8 +1360,33 @@ var _ = Describe("Packet packer", func() {
|
||||||
Expect(packet.frames[0].Frame).To(Equal(f))
|
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)
|
||||||
|
})
|
||||||
|
|
||||||
|
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(BeAssignableToTypeOf(&wire.StreamFrame{}))
|
||||||
|
Expect(packet.length).To(Equal(maxPacketSize))
|
||||||
|
})
|
||||||
|
|
||||||
It("returns nil if there's no probe data to send", func() {
|
It("returns nil if there's no probe data to send", func() {
|
||||||
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
|
sealingManager.EXPECT().Get1RTTSealer().Return(getSealer(), nil)
|
||||||
|
pnManager.EXPECT().PeekPacketNumber(protocol.Encryption1RTT).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
|
||||||
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
|
ackFramer.EXPECT().GetAckFrame(protocol.Encryption1RTT, true)
|
||||||
framer.EXPECT().HasData()
|
framer.EXPECT().HasData()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue