forked from quic-go/quic-go
Merge pull request #1724 from lucas-clemente/ack-delay-exponent
implement the ack_delay_exponent
This commit is contained in:
@@ -23,8 +23,9 @@ var _ = Describe("Transport Parameters", func() {
|
||||
MaxUniStreams: 7331,
|
||||
IdleTimeout: 42 * time.Second,
|
||||
OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
|
||||
AckDelayExponent: 14,
|
||||
}
|
||||
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}"))
|
||||
Expect(p.String()).To(Equal("&handshake.TransportParameters{OriginalConnectionID: 0xdeadbeef, InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s, AckDelayExponent: 14}"))
|
||||
})
|
||||
|
||||
getRandomValue := func() uint64 {
|
||||
@@ -45,6 +46,7 @@ var _ = Describe("Transport Parameters", func() {
|
||||
DisableMigration: true,
|
||||
StatelessResetToken: bytes.Repeat([]byte{100}, 16),
|
||||
OriginalConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef},
|
||||
AckDelayExponent: 13,
|
||||
}
|
||||
b := &bytes.Buffer{}
|
||||
params.marshal(b)
|
||||
@@ -61,6 +63,7 @@ var _ = Describe("Transport Parameters", func() {
|
||||
Expect(p.DisableMigration).To(Equal(params.DisableMigration))
|
||||
Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken))
|
||||
Expect(p.OriginalConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
|
||||
Expect(p.AckDelayExponent).To(Equal(uint8(13)))
|
||||
})
|
||||
|
||||
It("errors when the stateless_reset_token has the wrong length", func() {
|
||||
@@ -89,6 +92,22 @@ var _ = Describe("Transport Parameters", func() {
|
||||
Expect(p.unmarshal(b.Bytes(), protocol.PerspectiveServer)).To(MatchError("wrong length for disable_migration: 6 (expected empty)"))
|
||||
})
|
||||
|
||||
It("errors when the ack_delay_exponenent is too large", func() {
|
||||
b := &bytes.Buffer{}
|
||||
(&TransportParameters{AckDelayExponent: 21}).marshal(b)
|
||||
p := &TransportParameters{}
|
||||
Expect(p.unmarshal(b.Bytes(), protocol.PerspectiveServer)).To(MatchError("invalid value for ack_delay_exponent: 21 (maximum 20)"))
|
||||
})
|
||||
|
||||
It("doesn't send the ack_delay_exponent, if it has the default value", func() {
|
||||
b := &bytes.Buffer{}
|
||||
(&TransportParameters{AckDelayExponent: protocol.DefaultAckDelayExponent}).marshal(b)
|
||||
defaultLen := b.Len()
|
||||
b.Reset()
|
||||
(&TransportParameters{AckDelayExponent: protocol.DefaultAckDelayExponent + 1}).marshal(b)
|
||||
Expect(b.Len()).To(Equal(defaultLen + 2 /* parameter ID */ + 2 /* length field */ + 1 /* value */))
|
||||
})
|
||||
|
||||
It("errors when the varint value has the wrong length", func() {
|
||||
b := &bytes.Buffer{}
|
||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||
|
||||
@@ -25,6 +25,7 @@ const (
|
||||
initialMaxStreamDataUniParameterID transportParameterID = 0x7
|
||||
initialMaxStreamsBidiParameterID transportParameterID = 0x8
|
||||
initialMaxStreamsUniParameterID transportParameterID = 0x9
|
||||
ackDelayExponentParameterID transportParameterID = 0xa
|
||||
disableMigrationParameterID transportParameterID = 0xc
|
||||
)
|
||||
|
||||
@@ -35,6 +36,8 @@ type TransportParameters struct {
|
||||
InitialMaxStreamDataUni protocol.ByteCount
|
||||
InitialMaxData protocol.ByteCount
|
||||
|
||||
AckDelayExponent uint8
|
||||
|
||||
MaxPacketSize protocol.ByteCount
|
||||
|
||||
MaxUniStreams uint64
|
||||
@@ -65,7 +68,8 @@ func (p *TransportParameters) unmarshal(data []byte, sentBy protocol.Perspective
|
||||
initialMaxStreamsBidiParameterID,
|
||||
initialMaxStreamsUniParameterID,
|
||||
idleTimeoutParameterID,
|
||||
maxPacketSizeParameterID:
|
||||
maxPacketSizeParameterID,
|
||||
ackDelayExponentParameterID:
|
||||
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -147,6 +151,11 @@ func (p *TransportParameters) readNumericTransportParameter(
|
||||
return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", val)
|
||||
}
|
||||
p.MaxPacketSize = protocol.ByteCount(val)
|
||||
case ackDelayExponentParameterID:
|
||||
if val > protocol.MaxAckDelayExponent {
|
||||
return fmt.Errorf("invalid value for ack_delay_exponent: %d (maximum %d)", val, protocol.MaxAckDelayExponent)
|
||||
}
|
||||
p.AckDelayExponent = uint8(val)
|
||||
default:
|
||||
return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID)
|
||||
}
|
||||
@@ -186,6 +195,13 @@ func (p *TransportParameters) marshal(b *bytes.Buffer) {
|
||||
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
|
||||
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(protocol.MaxReceivePacketSize))))
|
||||
utils.WriteVarInt(b, uint64(protocol.MaxReceivePacketSize))
|
||||
// ack_delay_exponent
|
||||
// Only send it if is different from the default value.
|
||||
if p.AckDelayExponent != protocol.DefaultAckDelayExponent {
|
||||
utils.BigEndian.WriteUint16(b, uint16(ackDelayExponentParameterID))
|
||||
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.AckDelayExponent))))
|
||||
utils.WriteVarInt(b, uint64(p.AckDelayExponent))
|
||||
}
|
||||
// disable_migration
|
||||
if p.DisableMigration {
|
||||
utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID))
|
||||
@@ -206,5 +222,5 @@ func (p *TransportParameters) marshal(b *bytes.Buffer) {
|
||||
|
||||
// String returns a string representation, intended for logging.
|
||||
func (p *TransportParameters) String() string {
|
||||
return fmt.Sprintf("&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s}", p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout)
|
||||
return fmt.Sprintf("&handshake.TransportParameters{OriginalConnectionID: %s, InitialMaxStreamDataBidiLocal: %#x, InitialMaxStreamDataBidiRemote: %#x, InitialMaxStreamDataUni: %#x, InitialMaxData: %#x, MaxBidiStreams: %d, MaxUniStreams: %d, IdleTimeout: %s, AckDelayExponent: %d}", p.OriginalConnectionID, p.InitialMaxStreamDataBidiLocal, p.InitialMaxStreamDataBidiRemote, p.InitialMaxStreamDataUni, p.InitialMaxData, p.MaxBidiStreams, p.MaxUniStreams, p.IdleTimeout, p.AckDelayExponent)
|
||||
}
|
||||
|
||||
@@ -117,3 +117,6 @@ const MinPacingDelay time.Duration = 100 * time.Microsecond
|
||||
// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
|
||||
// if no other value is configured.
|
||||
const DefaultConnectionIDLength = 4
|
||||
|
||||
// AckDelayExponent is the ack delay exponent used when sending ACKs.
|
||||
const AckDelayExponent = 3
|
||||
|
||||
@@ -63,3 +63,9 @@ const MinStatelessResetSize = 1 /* first byte */ + 22 /* random bytes */ + 16 /*
|
||||
|
||||
// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
|
||||
const MinConnectionIDLenInitial = 8
|
||||
|
||||
// DefaultAckDelayExponent is the default ack delay exponent
|
||||
const DefaultAckDelayExponent = 3
|
||||
|
||||
// MaxAckDelayExponent is the maximum ack delay exponent
|
||||
const MaxAckDelayExponent = 20
|
||||
|
||||
@@ -10,9 +10,6 @@ import (
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
// TODO: use the value sent in the transport parameters
|
||||
const ackDelayExponent = 3
|
||||
|
||||
var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges")
|
||||
|
||||
// An AckFrame is an ACK frame
|
||||
@@ -22,7 +19,7 @@ type AckFrame struct {
|
||||
}
|
||||
|
||||
// parseAckFrame reads an ACK frame
|
||||
func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) {
|
||||
func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, version protocol.VersionNumber) (*AckFrame, error) {
|
||||
typeByte, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -225,5 +222,5 @@ func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool {
|
||||
}
|
||||
|
||||
func encodeAckDelay(delay time.Duration) uint64 {
|
||||
return uint64(delay.Nanoseconds() / (1000 * (1 << ackDelayExponent)))
|
||||
return uint64(delay.Nanoseconds() / (1000 * (1 << protocol.AckDelayExponent)))
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0)...) // num blocks
|
||||
data = append(data, encodeVarInt(10)...) // first ack block
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(90)))
|
||||
@@ -34,7 +34,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0)...) // num blocks
|
||||
data = append(data, encodeVarInt(0)...) // first ack block
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(55)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(55)))
|
||||
@@ -49,7 +49,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0)...) // num blocks
|
||||
data = append(data, encodeVarInt(20)...) // first ack block
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(20)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(0)))
|
||||
@@ -64,7 +64,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0)...) // num blocks
|
||||
data = append(data, encodeVarInt(21)...) // first ack block
|
||||
b := bytes.NewReader(data)
|
||||
_, err := parseAckFrame(b, versionIETFFrames)
|
||||
_, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).To(MatchError("invalid first ACK range"))
|
||||
})
|
||||
|
||||
@@ -77,7 +77,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(98)...) // gap
|
||||
data = append(data, encodeVarInt(50)...) // ack block
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(1000)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(750)))
|
||||
@@ -100,7 +100,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(1)...) // gap
|
||||
data = append(data, encodeVarInt(1)...) // ack block
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(94)))
|
||||
@@ -113,6 +113,22 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(b.Len()).To(BeZero())
|
||||
})
|
||||
|
||||
It("uses the ack delay exponent", func() {
|
||||
const delayTime = 1 << 10 * time.Millisecond
|
||||
buf := &bytes.Buffer{}
|
||||
f := &AckFrame{
|
||||
AckRanges: []AckRange{{Smallest: 1, Largest: 1}},
|
||||
DelayTime: delayTime,
|
||||
}
|
||||
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent+i, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.DelayTime).To(Equal(delayTime * (1 << i)))
|
||||
}
|
||||
})
|
||||
|
||||
It("errors on EOF", func() {
|
||||
data := []byte{0x2}
|
||||
data = append(data, encodeVarInt(1000)...) // largest acked
|
||||
@@ -121,10 +137,10 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(100)...) // first ack block
|
||||
data = append(data, encodeVarInt(98)...) // gap
|
||||
data = append(data, encodeVarInt(50)...) // ack block
|
||||
_, err := parseAckFrame(bytes.NewReader(data), versionIETFFrames)
|
||||
_, err := parseAckFrame(bytes.NewReader(data), protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
for i := range data {
|
||||
_, err := parseAckFrame(bytes.NewReader(data[0:i]), versionIETFFrames)
|
||||
_, err := parseAckFrame(bytes.NewReader(data[0:i]), protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).To(MatchError(io.EOF))
|
||||
}
|
||||
})
|
||||
@@ -140,7 +156,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0x12345)...) // ECT(1)
|
||||
data = append(data, encodeVarInt(0x12345678)...) // ECN-CE
|
||||
b := bytes.NewReader(data)
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestAcked()).To(Equal(protocol.PacketNumber(100)))
|
||||
Expect(frame.LowestAcked()).To(Equal(protocol.PacketNumber(90)))
|
||||
@@ -159,10 +175,10 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
data = append(data, encodeVarInt(0x42)...) // ECT(0)
|
||||
data = append(data, encodeVarInt(0x12345)...) // ECT(1)
|
||||
data = append(data, encodeVarInt(0x12345678)...) // ECN-CE
|
||||
_, err := parseAckFrame(bytes.NewReader(data), versionIETFFrames)
|
||||
_, err := parseAckFrame(bytes.NewReader(data), protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
for i := range data {
|
||||
_, err := parseAckFrame(bytes.NewReader(data[0:i]), versionIETFFrames)
|
||||
_, err := parseAckFrame(bytes.NewReader(data[0:i]), protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).To(MatchError(io.EOF))
|
||||
}
|
||||
})
|
||||
@@ -196,7 +212,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
Expect(frame.HasMissingRanges()).To(BeFalse())
|
||||
@@ -213,7 +229,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
Expect(frame.HasMissingRanges()).To(BeFalse())
|
||||
@@ -233,7 +249,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
Expect(frame.HasMissingRanges()).To(BeTrue())
|
||||
@@ -255,7 +271,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f.Length(versionIETFFrames)).To(BeEquivalentTo(buf.Len()))
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
Expect(frame.HasMissingRanges()).To(BeTrue())
|
||||
@@ -278,7 +294,7 @@ var _ = Describe("ACK Frame (for IETF QUIC)", func() {
|
||||
Expect(buf.Len()).To(BeNumerically(">", protocol.MaxAckFrameSize-5))
|
||||
Expect(buf.Len()).To(BeNumerically("<=", protocol.MaxAckFrameSize))
|
||||
b := bytes.NewReader(buf.Bytes())
|
||||
frame, err := parseAckFrame(b, versionIETFFrames)
|
||||
frame, err := parseAckFrame(b, protocol.AckDelayExponent, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.HasMissingRanges()).To(BeTrue())
|
||||
Expect(b.Len()).To(BeZero())
|
||||
|
||||
@@ -8,9 +8,20 @@ import (
|
||||
"github.com/lucas-clemente/quic-go/internal/qerr"
|
||||
)
|
||||
|
||||
type frameParser struct {
|
||||
ackDelayExponent uint8
|
||||
|
||||
version protocol.VersionNumber
|
||||
}
|
||||
|
||||
// NewFrameParser creates a new frame parser.
|
||||
func NewFrameParser(v protocol.VersionNumber) FrameParser {
|
||||
return &frameParser{version: v}
|
||||
}
|
||||
|
||||
// ParseNextFrame parses the next frame
|
||||
// It skips PADDING frames.
|
||||
func ParseNextFrame(r *bytes.Reader, v protocol.VersionNumber) (Frame, error) {
|
||||
func (p *frameParser) ParseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
|
||||
for r.Len() != 0 {
|
||||
typeByte, _ := r.ReadByte()
|
||||
if typeByte == 0x0 { // PADDING frame
|
||||
@@ -18,16 +29,16 @@ func ParseNextFrame(r *bytes.Reader, v protocol.VersionNumber) (Frame, error) {
|
||||
}
|
||||
r.UnreadByte()
|
||||
|
||||
return parseFrame(r, typeByte, v)
|
||||
return p.parseFrame(r, typeByte, encLevel)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func parseFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame, error) {
|
||||
func (p *frameParser) parseFrame(r *bytes.Reader, typeByte byte, encLevel protocol.EncryptionLevel) (Frame, error) {
|
||||
var frame Frame
|
||||
var err error
|
||||
if typeByte&0xf8 == 0x8 {
|
||||
frame, err = parseStreamFrame(r, v)
|
||||
frame, err = parseStreamFrame(r, p.version)
|
||||
if err != nil {
|
||||
return nil, qerr.Error(qerr.InvalidFrameData, err.Error())
|
||||
}
|
||||
@@ -35,39 +46,43 @@ func parseFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame
|
||||
}
|
||||
switch typeByte {
|
||||
case 0x1:
|
||||
frame, err = parsePingFrame(r, v)
|
||||
frame, err = parsePingFrame(r, p.version)
|
||||
case 0x2, 0x3:
|
||||
frame, err = parseAckFrame(r, v)
|
||||
ackDelayExponent := p.ackDelayExponent
|
||||
if encLevel != protocol.Encryption1RTT {
|
||||
ackDelayExponent = protocol.DefaultAckDelayExponent
|
||||
}
|
||||
frame, err = parseAckFrame(r, ackDelayExponent, p.version)
|
||||
case 0x4:
|
||||
frame, err = parseResetStreamFrame(r, v)
|
||||
frame, err = parseResetStreamFrame(r, p.version)
|
||||
case 0x5:
|
||||
frame, err = parseStopSendingFrame(r, v)
|
||||
frame, err = parseStopSendingFrame(r, p.version)
|
||||
case 0x6:
|
||||
frame, err = parseCryptoFrame(r, v)
|
||||
frame, err = parseCryptoFrame(r, p.version)
|
||||
case 0x7:
|
||||
frame, err = parseNewTokenFrame(r, v)
|
||||
frame, err = parseNewTokenFrame(r, p.version)
|
||||
case 0x10:
|
||||
frame, err = parseMaxDataFrame(r, v)
|
||||
frame, err = parseMaxDataFrame(r, p.version)
|
||||
case 0x11:
|
||||
frame, err = parseMaxStreamDataFrame(r, v)
|
||||
frame, err = parseMaxStreamDataFrame(r, p.version)
|
||||
case 0x12, 0x13:
|
||||
frame, err = parseMaxStreamsFrame(r, v)
|
||||
frame, err = parseMaxStreamsFrame(r, p.version)
|
||||
case 0x14:
|
||||
frame, err = parseDataBlockedFrame(r, v)
|
||||
frame, err = parseDataBlockedFrame(r, p.version)
|
||||
case 0x15:
|
||||
frame, err = parseStreamDataBlockedFrame(r, v)
|
||||
frame, err = parseStreamDataBlockedFrame(r, p.version)
|
||||
case 0x16, 0x17:
|
||||
frame, err = parseStreamsBlockedFrame(r, v)
|
||||
frame, err = parseStreamsBlockedFrame(r, p.version)
|
||||
case 0x18:
|
||||
frame, err = parseNewConnectionIDFrame(r, v)
|
||||
frame, err = parseNewConnectionIDFrame(r, p.version)
|
||||
case 0x19:
|
||||
frame, err = parseRetireConnectionIDFrame(r, v)
|
||||
frame, err = parseRetireConnectionIDFrame(r, p.version)
|
||||
case 0x1a:
|
||||
frame, err = parsePathChallengeFrame(r, v)
|
||||
frame, err = parsePathChallengeFrame(r, p.version)
|
||||
case 0x1b:
|
||||
frame, err = parsePathResponseFrame(r, v)
|
||||
frame, err = parsePathResponseFrame(r, p.version)
|
||||
case 0x1c, 0x1d:
|
||||
frame, err = parseConnectionCloseFrame(r, v)
|
||||
frame, err = parseConnectionCloseFrame(r, p.version)
|
||||
default:
|
||||
err = fmt.Errorf("unknown type byte 0x%x", typeByte)
|
||||
}
|
||||
@@ -76,3 +91,7 @@ func parseFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame
|
||||
}
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (p *frameParser) SetAckDelayExponent(exp uint8) {
|
||||
p.ackDelayExponent = exp
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/qerr"
|
||||
@@ -10,14 +11,18 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("Frame parsing", func() {
|
||||
var buf *bytes.Buffer
|
||||
var (
|
||||
buf *bytes.Buffer
|
||||
parser FrameParser
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
buf = &bytes.Buffer{}
|
||||
parser = NewFrameParser(versionIETFFrames)
|
||||
})
|
||||
|
||||
It("returns nil if there's nothing more to read", func() {
|
||||
f, err := ParseNextFrame(bytes.NewReader(nil), protocol.VersionWhatever)
|
||||
f, err := parser.ParseNext(bytes.NewReader(nil), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f).To(BeNil())
|
||||
})
|
||||
@@ -25,14 +30,14 @@ var _ = Describe("Frame parsing", func() {
|
||||
It("skips PADDING frames", func() {
|
||||
buf.Write([]byte{0}) // PADDING frame
|
||||
(&PingFrame{}).Write(buf, versionIETFFrames)
|
||||
f, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
f, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f).To(Equal(&PingFrame{}))
|
||||
})
|
||||
|
||||
It("handles PADDING at the end", func() {
|
||||
r := bytes.NewReader([]byte{0, 0, 0})
|
||||
f, err := ParseNextFrame(r, versionIETFFrames)
|
||||
f, err := parser.ParseNext(r, protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(f).To(BeNil())
|
||||
Expect(r.Len()).To(BeZero())
|
||||
@@ -42,13 +47,39 @@ var _ = Describe("Frame parsing", func() {
|
||||
f := &AckFrame{AckRanges: []AckRange{{Smallest: 1, Largest: 0x13}}}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(BeAssignableToTypeOf(f))
|
||||
Expect(frame.(*AckFrame).LargestAcked()).To(Equal(protocol.PacketNumber(0x13)))
|
||||
})
|
||||
|
||||
It("uses the custom ack delay exponent for 1RTT packets", func() {
|
||||
parser.SetAckDelayExponent(protocol.AckDelayExponent + 2)
|
||||
f := &AckFrame{
|
||||
AckRanges: []AckRange{{Smallest: 1, Largest: 1}},
|
||||
DelayTime: time.Second,
|
||||
}
|
||||
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
// The ACK frame is always written using the protocol.AckDelayExponent.
|
||||
// That's why we expect a different value when parsing.
|
||||
Expect(frame.(*AckFrame).DelayTime).To(Equal(4 * time.Second))
|
||||
})
|
||||
|
||||
It("uses the default ack delay exponent for non-1RTT packets", func() {
|
||||
parser.SetAckDelayExponent(protocol.AckDelayExponent + 2)
|
||||
f := &AckFrame{
|
||||
AckRanges: []AckRange{{Smallest: 1, Largest: 1}},
|
||||
DelayTime: time.Second,
|
||||
}
|
||||
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.EncryptionHandshake)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.(*AckFrame).DelayTime).To(Equal(time.Second))
|
||||
})
|
||||
|
||||
It("unpacks RESET_STREAM frames", func() {
|
||||
f := &ResetStreamFrame{
|
||||
StreamID: 0xdeadbeef,
|
||||
@@ -57,7 +88,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -67,7 +98,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -79,7 +110,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(Equal(f))
|
||||
@@ -89,7 +120,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
f := &NewTokenFrame{Token: []byte("foobar")}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(Equal(f))
|
||||
@@ -104,7 +135,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(Equal(f))
|
||||
@@ -117,7 +148,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -130,7 +161,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -143,7 +174,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -153,7 +184,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -165,7 +196,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -178,7 +209,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -191,7 +222,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -200,7 +231,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
f := &RetireConnectionIDFrame{SequenceNumber: 0x1337}
|
||||
buf := &bytes.Buffer{}
|
||||
Expect(f.Write(buf, versionIETFFrames)).To(Succeed())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
@@ -209,7 +240,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
f := &PathChallengeFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(BeAssignableToTypeOf(f))
|
||||
@@ -220,7 +251,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
f := &PathResponseFrame{Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).ToNot(BeNil())
|
||||
Expect(frame).To(BeAssignableToTypeOf(f))
|
||||
@@ -235,13 +266,13 @@ var _ = Describe("Frame parsing", func() {
|
||||
buf := &bytes.Buffer{}
|
||||
err := f.Write(buf, versionIETFFrames)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
frame, err := ParseNextFrame(bytes.NewReader(buf.Bytes()), versionIETFFrames)
|
||||
frame, err := parser.ParseNext(bytes.NewReader(buf.Bytes()), protocol.Encryption1RTT)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame).To(Equal(f))
|
||||
})
|
||||
|
||||
It("errors on invalid type", func() {
|
||||
_, err := ParseNextFrame(bytes.NewReader([]byte{0x42}), versionIETFFrames)
|
||||
_, err := parser.ParseNext(bytes.NewReader([]byte{0x42}), protocol.Encryption1RTT)
|
||||
Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0x42"))
|
||||
})
|
||||
|
||||
@@ -252,7 +283,7 @@ var _ = Describe("Frame parsing", func() {
|
||||
}
|
||||
b := &bytes.Buffer{}
|
||||
f.Write(b, versionIETFFrames)
|
||||
_, err := ParseNextFrame(bytes.NewReader(b.Bytes()[:b.Len()-2]), versionIETFFrames)
|
||||
_, err := parser.ParseNext(bytes.NewReader(b.Bytes()[:b.Len()-2]), protocol.Encryption1RTT)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidFrameData))
|
||||
})
|
||||
|
||||
@@ -11,3 +11,9 @@ type Frame interface {
|
||||
Write(b *bytes.Buffer, version protocol.VersionNumber) error
|
||||
Length(version protocol.VersionNumber) protocol.ByteCount
|
||||
}
|
||||
|
||||
// A FrameParser parses QUIC frames, one by one.
|
||||
type FrameParser interface {
|
||||
ParseNext(*bytes.Reader, protocol.EncryptionLevel) (Frame, error)
|
||||
SetAckDelayExponent(uint8)
|
||||
}
|
||||
Reference in New Issue
Block a user