mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-07 06:07:36 +03:00
use varints for numeric transport parameters
This commit is contained in:
parent
7087a16c7f
commit
66a72a1199
5 changed files with 223 additions and 248 deletions
|
@ -402,8 +402,8 @@ func (c *client) createNewTLSSession(version protocol.VersionNumber) error {
|
||||||
InitialMaxStreamDataUni: protocol.InitialMaxStreamData,
|
InitialMaxStreamDataUni: protocol.InitialMaxStreamData,
|
||||||
InitialMaxData: protocol.InitialMaxData,
|
InitialMaxData: protocol.InitialMaxData,
|
||||||
IdleTimeout: c.config.IdleTimeout,
|
IdleTimeout: c.config.IdleTimeout,
|
||||||
MaxBidiStreams: uint16(c.config.MaxIncomingStreams),
|
MaxBidiStreams: uint64(c.config.MaxIncomingStreams),
|
||||||
MaxUniStreams: uint16(c.config.MaxIncomingUniStreams),
|
MaxUniStreams: uint64(c.config.MaxIncomingUniStreams),
|
||||||
DisableMigration: true,
|
DisableMigration: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,12 +185,10 @@ type Config struct {
|
||||||
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
|
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
|
||||||
// If not set, it will default to 100.
|
// If not set, it will default to 100.
|
||||||
// If set to a negative value, it doesn't allow any bidirectional streams.
|
// If set to a negative value, it doesn't allow any bidirectional streams.
|
||||||
// Values larger than 65535 (math.MaxUint16) are invalid.
|
|
||||||
MaxIncomingStreams int
|
MaxIncomingStreams int
|
||||||
// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
|
// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
|
||||||
// If not set, it will default to 100.
|
// If not set, it will default to 100.
|
||||||
// If set to a negative value, it doesn't allow any unidirectional streams.
|
// If set to a negative value, it doesn't allow any unidirectional streams.
|
||||||
// Values larger than 65535 (math.MaxUint16) are invalid.
|
|
||||||
MaxIncomingUniStreams int
|
MaxIncomingUniStreams int
|
||||||
// KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive.
|
// KeepAlive defines whether this peer will periodically send PING frames to keep the connection alive.
|
||||||
KeepAlive bool
|
KeepAlive bool
|
||||||
|
|
|
@ -2,7 +2,8 @@ package handshake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"math"
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||||
|
@ -25,172 +26,135 @@ var _ = Describe("Transport Parameters", func() {
|
||||||
Expect(p.String()).To(Equal("&handshake.TransportParameters{InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}"))
|
Expect(p.String()).To(Equal("&handshake.TransportParameters{InitialMaxStreamDataBidiLocal: 0x1234, InitialMaxStreamDataBidiRemote: 0x2345, InitialMaxStreamDataUni: 0x3456, InitialMaxData: 0x4567, MaxBidiStreams: 1337, MaxUniStreams: 7331, IdleTimeout: 42s}"))
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("parsing", func() {
|
getRandomValue := func() uint64 {
|
||||||
var (
|
maxVals := []int64{math.MaxUint8 / 4, math.MaxUint16 / 4, math.MaxUint32 / 4, math.MaxUint64 / 4}
|
||||||
params *TransportParameters
|
rand.Seed(GinkgoRandomSeed())
|
||||||
parameters map[transportParameterID][]byte
|
return uint64(rand.Int63n(maxVals[int(rand.Int31n(4))]))
|
||||||
statelessResetToken []byte
|
}
|
||||||
)
|
|
||||||
|
|
||||||
marshal := func(p map[transportParameterID][]byte) []byte {
|
It("marshals und unmarshals", func() {
|
||||||
b := &bytes.Buffer{}
|
params := &TransportParameters{
|
||||||
for id, val := range p {
|
InitialMaxStreamDataBidiLocal: protocol.ByteCount(getRandomValue()),
|
||||||
utils.BigEndian.WriteUint16(b, uint16(id))
|
InitialMaxStreamDataBidiRemote: protocol.ByteCount(getRandomValue()),
|
||||||
utils.BigEndian.WriteUint16(b, uint16(len(val)))
|
InitialMaxStreamDataUni: protocol.ByteCount(getRandomValue()),
|
||||||
b.Write(val)
|
InitialMaxData: protocol.ByteCount(getRandomValue()),
|
||||||
}
|
IdleTimeout: 0xcafe * time.Second,
|
||||||
return b.Bytes()
|
MaxBidiStreams: getRandomValue(),
|
||||||
|
MaxUniStreams: getRandomValue(),
|
||||||
|
DisableMigration: true,
|
||||||
|
StatelessResetToken: bytes.Repeat([]byte{100}, 16),
|
||||||
}
|
}
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
params.marshal(b)
|
||||||
|
|
||||||
BeforeEach(func() {
|
p := &TransportParameters{}
|
||||||
params = &TransportParameters{}
|
Expect(p.unmarshal(b.Bytes())).To(Succeed())
|
||||||
statelessResetToken = bytes.Repeat([]byte{42}, 16)
|
Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal))
|
||||||
parameters = map[transportParameterID][]byte{
|
Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote))
|
||||||
initialMaxStreamDataBidiLocalParameterID: {0x11, 0x22, 0x33, 0x44},
|
Expect(p.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni))
|
||||||
initialMaxStreamDataBidiRemoteParameterID: {0x22, 0x33, 0x44, 0x55},
|
Expect(p.InitialMaxData).To(Equal(params.InitialMaxData))
|
||||||
initialMaxStreamDataUniParameterID: {0x33, 0x44, 0x55, 0x66},
|
Expect(p.MaxUniStreams).To(Equal(params.MaxUniStreams))
|
||||||
initialMaxDataParameterID: {0x44, 0x55, 0x66, 0x77},
|
Expect(p.MaxBidiStreams).To(Equal(params.MaxBidiStreams))
|
||||||
initialMaxBidiStreamsParameterID: {0x33, 0x44},
|
Expect(p.IdleTimeout).To(Equal(params.IdleTimeout))
|
||||||
initialMaxUniStreamsParameterID: {0x44, 0x55},
|
Expect(p.DisableMigration).To(Equal(params.DisableMigration))
|
||||||
idleTimeoutParameterID: {0x13, 0x37},
|
Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken))
|
||||||
maxPacketSizeParameterID: {0x73, 0x31},
|
|
||||||
disableMigrationParameterID: {},
|
|
||||||
statelessResetTokenParameterID: statelessResetToken,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
It("reads parameters", func() {
|
|
||||||
Expect(params.unmarshal(marshal(parameters))).To(Succeed())
|
|
||||||
Expect(params.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x11223344)))
|
|
||||||
Expect(params.InitialMaxStreamDataBidiRemote).To(Equal(protocol.ByteCount(0x22334455)))
|
|
||||||
Expect(params.InitialMaxStreamDataUni).To(Equal(protocol.ByteCount(0x33445566)))
|
|
||||||
Expect(params.InitialMaxData).To(Equal(protocol.ByteCount(0x44556677)))
|
|
||||||
Expect(params.MaxBidiStreams).To(Equal(uint16(0x3344)))
|
|
||||||
Expect(params.MaxUniStreams).To(Equal(uint16(0x4455)))
|
|
||||||
Expect(params.IdleTimeout).To(Equal(0x1337 * time.Second))
|
|
||||||
Expect(params.MaxPacketSize).To(Equal(protocol.ByteCount(0x7331)))
|
|
||||||
Expect(params.DisableMigration).To(BeTrue())
|
|
||||||
Expect(params.StatelessResetToken).To(Equal(statelessResetToken))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("errors if a parameter is sent twice", func() {
|
|
||||||
data := marshal(parameters)
|
|
||||||
parameters = map[transportParameterID][]byte{
|
|
||||||
maxPacketSizeParameterID: {0x73, 0x31},
|
|
||||||
}
|
|
||||||
data = append(data, marshal(parameters)...)
|
|
||||||
err := params.unmarshal(data)
|
|
||||||
Expect(err).To(MatchError(fmt.Sprintf("received duplicate transport parameter %#x", maxPacketSizeParameterID)))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("doesn't allow values below the minimum remote idle timeout", func() {
|
|
||||||
t := 2 * time.Second
|
|
||||||
Expect(t).To(BeNumerically("<", protocol.MinRemoteIdleTimeout))
|
|
||||||
parameters[idleTimeoutParameterID] = []byte{0, uint8(t.Seconds())}
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
Expect(params.IdleTimeout).To(Equal(protocol.MinRemoteIdleTimeout))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_stream_data_bidi_local has the wrong length", func() {
|
|
||||||
parameters[initialMaxStreamDataBidiLocalParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_stream_data_bidi_local: 3 (expected 4)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_stream_data_bidi_remote has the wrong length", func() {
|
|
||||||
parameters[initialMaxStreamDataBidiRemoteParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_stream_data_bidi_remote: 3 (expected 4)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_stream_data_uni has the wrong length", func() {
|
|
||||||
parameters[initialMaxStreamDataUniParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_stream_data_uni: 3 (expected 4)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_data has the wrong length", func() {
|
|
||||||
parameters[initialMaxDataParameterID] = []byte{0x11, 0x22, 0x33} // should be 4 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_data: 3 (expected 4)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_stream_id_bidi has the wrong length", func() {
|
|
||||||
parameters[initialMaxBidiStreamsParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_stream_id_bidi: 3 (expected 2)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_max_stream_id_bidi has the wrong length", func() {
|
|
||||||
parameters[initialMaxUniStreamsParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for initial_max_stream_id_uni: 3 (expected 2)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the initial_idle_timeout has the wrong length", func() {
|
|
||||||
parameters[idleTimeoutParameterID] = []byte{0x11, 0x22, 0x33} // should be 2 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for idle_timeout: 3 (expected 2)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if max_packet_size has the wrong length", func() {
|
|
||||||
parameters[maxPacketSizeParameterID] = []byte{0x11} // should be 2 bytes
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for max_packet_size: 1 (expected 2)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects max_packet_sizes smaller than 1200 bytes", func() {
|
|
||||||
parameters[maxPacketSizeParameterID] = []byte{0x4, 0xaf} // 0x4af = 1199
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("invalid value for max_packet_size: 1199 (minimum 1200)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if disable_connection_migration has the wrong length", func() {
|
|
||||||
parameters[disableMigrationParameterID] = []byte{0x11} // should empty
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for disable_migration: 1 (expected empty)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("rejects the parameters if the stateless_reset_token has the wrong length", func() {
|
|
||||||
parameters[statelessResetTokenParameterID] = statelessResetToken[1:]
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).To(MatchError("wrong length for stateless_reset_token: 15 (expected 16)"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("ignores unknown parameters", func() {
|
|
||||||
parameters[1337] = []byte{42}
|
|
||||||
err := params.unmarshal(marshal(parameters))
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("marshalling", func() {
|
It("errors when the stateless_reset_token has the wrong length", func() {
|
||||||
It("marshals", func() {
|
params := &TransportParameters{StatelessResetToken: bytes.Repeat([]byte{100}, 15)}
|
||||||
params := &TransportParameters{
|
b := &bytes.Buffer{}
|
||||||
InitialMaxStreamDataBidiLocal: 0xdeadbeef,
|
params.marshal(b)
|
||||||
InitialMaxStreamDataBidiRemote: 0xbeef,
|
p := &TransportParameters{}
|
||||||
InitialMaxStreamDataUni: 0xcafe,
|
Expect(p.unmarshal(b.Bytes())).To(MatchError("wrong length for stateless_reset_token: 15 (expected 16)"))
|
||||||
InitialMaxData: 0xdecafbad,
|
})
|
||||||
IdleTimeout: 0xcafe * time.Second,
|
|
||||||
MaxBidiStreams: 0x1234,
|
|
||||||
MaxUniStreams: 0x4321,
|
|
||||||
DisableMigration: true,
|
|
||||||
StatelessResetToken: bytes.Repeat([]byte{100}, 16),
|
|
||||||
}
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
params.marshal(b)
|
|
||||||
|
|
||||||
p := &TransportParameters{}
|
It("errors when the max_packet_size is too small", func() {
|
||||||
Expect(p.unmarshal(b.Bytes())).To(Succeed())
|
b := &bytes.Buffer{}
|
||||||
Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(params.InitialMaxStreamDataBidiLocal))
|
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
|
||||||
Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(params.InitialMaxStreamDataBidiRemote))
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(1199)))
|
||||||
Expect(p.InitialMaxStreamDataUni).To(Equal(params.InitialMaxStreamDataUni))
|
utils.WriteVarInt(b, 1199)
|
||||||
Expect(p.InitialMaxData).To(Equal(params.InitialMaxData))
|
p := &TransportParameters{}
|
||||||
Expect(p.MaxUniStreams).To(Equal(params.MaxUniStreams))
|
Expect(p.unmarshal(b.Bytes())).To(MatchError("invalid value for max_packet_size: 1199 (minimum 1200)"))
|
||||||
Expect(p.MaxBidiStreams).To(Equal(params.MaxBidiStreams))
|
})
|
||||||
Expect(p.IdleTimeout).To(Equal(params.IdleTimeout))
|
|
||||||
Expect(p.DisableMigration).To(Equal(params.DisableMigration))
|
It("errors when disable_migration has content", func() {
|
||||||
Expect(p.StatelessResetToken).To(Equal(params.StatelessResetToken))
|
b := &bytes.Buffer{}
|
||||||
})
|
utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, 6)
|
||||||
|
b.Write([]byte("foobar"))
|
||||||
|
p := &TransportParameters{}
|
||||||
|
Expect(p.unmarshal(b.Bytes())).To(MatchError("wrong length for disable_migration: 6 (expected empty)"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("errors when the varint value has the wrong length", func() {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, 2)
|
||||||
|
val := uint64(0xdeadbeef)
|
||||||
|
Expect(utils.VarIntLen(val)).ToNot(BeEquivalentTo(2))
|
||||||
|
utils.WriteVarInt(b, val)
|
||||||
|
p := &TransportParameters{}
|
||||||
|
err := p.unmarshal(b.Bytes())
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("inconsistent transport parameter length"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("skips unknown parameters", func() {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
// write a known parameter
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x1337)))
|
||||||
|
utils.WriteVarInt(b, 0x1337)
|
||||||
|
// write an unknown parameter
|
||||||
|
utils.BigEndian.WriteUint16(b, 0x42)
|
||||||
|
utils.BigEndian.WriteUint16(b, 6)
|
||||||
|
b.Write([]byte("foobar"))
|
||||||
|
// write a known parameter
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x42)))
|
||||||
|
utils.WriteVarInt(b, 0x42)
|
||||||
|
p := &TransportParameters{}
|
||||||
|
Expect(p.unmarshal(b.Bytes())).To(Succeed())
|
||||||
|
Expect(p.InitialMaxStreamDataBidiLocal).To(Equal(protocol.ByteCount(0x1337)))
|
||||||
|
Expect(p.InitialMaxStreamDataBidiRemote).To(Equal(protocol.ByteCount(0x42)))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("rejects duplicate parameters", func() {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
// write first parameter
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x1337)))
|
||||||
|
utils.WriteVarInt(b, 0x1337)
|
||||||
|
// write a second parameter
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x42)))
|
||||||
|
utils.WriteVarInt(b, 0x42)
|
||||||
|
// write first parameter again
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x1337)))
|
||||||
|
utils.WriteVarInt(b, 0x1337)
|
||||||
|
p := &TransportParameters{}
|
||||||
|
err := p.unmarshal(b.Bytes())
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err.Error()).To(ContainSubstring("received duplicate transport parameter"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("errors if there's not enough data to read", func() {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
utils.BigEndian.WriteUint16(b, 0x42)
|
||||||
|
utils.BigEndian.WriteUint16(b, 7)
|
||||||
|
b.Write([]byte("foobar"))
|
||||||
|
p := &TransportParameters{}
|
||||||
|
Expect(p.unmarshal(b.Bytes())).To(MatchError("remaining length (6) smaller than parameter length (7)"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("errors if there's unprocessed data after reading", func() {
|
||||||
|
b := &bytes.Buffer{}
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(0x1337)))
|
||||||
|
utils.WriteVarInt(b, 0x1337)
|
||||||
|
b.Write([]byte("foo"))
|
||||||
|
p := &TransportParameters{}
|
||||||
|
Expect(p.unmarshal(b.Bytes())).To(MatchError("should have read all data. Still have 3 bytes"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,8 +2,8 @@ package handshake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ type TransportParameters struct {
|
||||||
|
|
||||||
MaxPacketSize protocol.ByteCount
|
MaxPacketSize protocol.ByteCount
|
||||||
|
|
||||||
MaxUniStreams uint16
|
MaxUniStreams uint64
|
||||||
MaxBidiStreams uint16
|
MaxBidiStreams uint64
|
||||||
|
|
||||||
IdleTimeout time.Duration
|
IdleTimeout time.Duration
|
||||||
DisableMigration bool
|
DisableMigration bool
|
||||||
|
@ -47,71 +47,45 @@ func (p *TransportParameters) unmarshal(data []byte) error {
|
||||||
// needed to check that every parameter is only sent at most once
|
// needed to check that every parameter is only sent at most once
|
||||||
var parameterIDs []transportParameterID
|
var parameterIDs []transportParameterID
|
||||||
|
|
||||||
for len(data) >= 4 {
|
r := bytes.NewReader(data)
|
||||||
paramID := transportParameterID(binary.BigEndian.Uint16(data[:2]))
|
for r.Len() >= 4 {
|
||||||
paramLen := int(binary.BigEndian.Uint16(data[2:4]))
|
paramIDInt, _ := utils.BigEndian.ReadUint16(r)
|
||||||
data = data[4:]
|
paramID := transportParameterID(paramIDInt)
|
||||||
if len(data) < paramLen {
|
paramLen, _ := utils.BigEndian.ReadUint16(r)
|
||||||
return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(data), paramLen)
|
|
||||||
}
|
|
||||||
parameterIDs = append(parameterIDs, paramID)
|
parameterIDs = append(parameterIDs, paramID)
|
||||||
switch paramID {
|
switch paramID {
|
||||||
case initialMaxStreamDataBidiLocalParameterID:
|
case initialMaxStreamDataBidiLocalParameterID,
|
||||||
if paramLen != 4 {
|
initialMaxStreamDataBidiRemoteParameterID,
|
||||||
return fmt.Errorf("wrong length for initial_max_stream_data_bidi_local: %d (expected 4)", paramLen)
|
initialMaxStreamDataUniParameterID,
|
||||||
|
initialMaxDataParameterID,
|
||||||
|
initialMaxBidiStreamsParameterID,
|
||||||
|
initialMaxUniStreamsParameterID,
|
||||||
|
idleTimeoutParameterID,
|
||||||
|
maxPacketSizeParameterID:
|
||||||
|
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
default:
|
||||||
case initialMaxStreamDataBidiRemoteParameterID:
|
if r.Len() < int(paramLen) {
|
||||||
if paramLen != 4 {
|
return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", r.Len(), paramLen)
|
||||||
return fmt.Errorf("wrong length for initial_max_stream_data_bidi_remote: %d (expected 4)", paramLen)
|
|
||||||
}
|
}
|
||||||
p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
switch paramID {
|
||||||
case initialMaxStreamDataUniParameterID:
|
case disableMigrationParameterID:
|
||||||
if paramLen != 4 {
|
if paramLen != 0 {
|
||||||
return fmt.Errorf("wrong length for initial_max_stream_data_uni: %d (expected 4)", paramLen)
|
return fmt.Errorf("wrong length for disable_migration: %d (expected empty)", paramLen)
|
||||||
|
}
|
||||||
|
p.DisableMigration = true
|
||||||
|
case statelessResetTokenParameterID:
|
||||||
|
if paramLen != 16 {
|
||||||
|
return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen)
|
||||||
|
}
|
||||||
|
b := make([]byte, 16)
|
||||||
|
r.Read(b)
|
||||||
|
p.StatelessResetToken = b
|
||||||
|
default:
|
||||||
|
r.Seek(int64(paramLen), io.SeekCurrent)
|
||||||
}
|
}
|
||||||
p.InitialMaxStreamDataUni = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
|
||||||
case initialMaxDataParameterID:
|
|
||||||
if paramLen != 4 {
|
|
||||||
return fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", paramLen)
|
|
||||||
}
|
|
||||||
p.InitialMaxData = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
|
||||||
case initialMaxBidiStreamsParameterID:
|
|
||||||
if paramLen != 2 {
|
|
||||||
return fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 2)", paramLen)
|
|
||||||
}
|
|
||||||
p.MaxBidiStreams = binary.BigEndian.Uint16(data[:2])
|
|
||||||
case initialMaxUniStreamsParameterID:
|
|
||||||
if paramLen != 2 {
|
|
||||||
return fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", paramLen)
|
|
||||||
}
|
|
||||||
p.MaxUniStreams = binary.BigEndian.Uint16(data[:2])
|
|
||||||
case idleTimeoutParameterID:
|
|
||||||
if paramLen != 2 {
|
|
||||||
return fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", paramLen)
|
|
||||||
}
|
|
||||||
p.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(binary.BigEndian.Uint16(data[:2]))*time.Second)
|
|
||||||
case maxPacketSizeParameterID:
|
|
||||||
if paramLen != 2 {
|
|
||||||
return fmt.Errorf("wrong length for max_packet_size: %d (expected 2)", paramLen)
|
|
||||||
}
|
|
||||||
maxPacketSize := protocol.ByteCount(binary.BigEndian.Uint16(data[:2]))
|
|
||||||
if maxPacketSize < 1200 {
|
|
||||||
return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", maxPacketSize)
|
|
||||||
}
|
|
||||||
p.MaxPacketSize = maxPacketSize
|
|
||||||
case disableMigrationParameterID:
|
|
||||||
if paramLen != 0 {
|
|
||||||
return fmt.Errorf("wrong length for disable_migration: %d (expected empty)", paramLen)
|
|
||||||
}
|
|
||||||
p.DisableMigration = true
|
|
||||||
case statelessResetTokenParameterID:
|
|
||||||
if paramLen != 16 {
|
|
||||||
return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen)
|
|
||||||
}
|
|
||||||
p.StatelessResetToken = data[:16]
|
|
||||||
}
|
}
|
||||||
data = data[paramLen:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that every transport parameter was sent at most once
|
// check that every transport parameter was sent at most once
|
||||||
|
@ -122,8 +96,47 @@ func (p *TransportParameters) unmarshal(data []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data) != 0 {
|
if r.Len() != 0 {
|
||||||
return fmt.Errorf("should have read all data. Still have %d bytes", len(data))
|
return fmt.Errorf("should have read all data. Still have %d bytes", r.Len())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TransportParameters) readNumericTransportParameter(
|
||||||
|
r *bytes.Reader,
|
||||||
|
paramID transportParameterID,
|
||||||
|
expectedLen int,
|
||||||
|
) error {
|
||||||
|
remainingLen := r.Len()
|
||||||
|
val, err := utils.ReadVarInt(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while reading transport parameter %d: %s", paramID, err)
|
||||||
|
}
|
||||||
|
if remainingLen-r.Len() != expectedLen {
|
||||||
|
return fmt.Errorf("inconsistent transport parameter length for %d", paramID)
|
||||||
|
}
|
||||||
|
switch paramID {
|
||||||
|
case initialMaxStreamDataBidiLocalParameterID:
|
||||||
|
p.InitialMaxStreamDataBidiLocal = protocol.ByteCount(val)
|
||||||
|
case initialMaxStreamDataBidiRemoteParameterID:
|
||||||
|
p.InitialMaxStreamDataBidiRemote = protocol.ByteCount(val)
|
||||||
|
case initialMaxStreamDataUniParameterID:
|
||||||
|
p.InitialMaxStreamDataUni = protocol.ByteCount(val)
|
||||||
|
case initialMaxDataParameterID:
|
||||||
|
p.InitialMaxData = protocol.ByteCount(val)
|
||||||
|
case initialMaxBidiStreamsParameterID:
|
||||||
|
p.MaxBidiStreams = val
|
||||||
|
case initialMaxUniStreamsParameterID:
|
||||||
|
p.MaxUniStreams = val
|
||||||
|
case idleTimeoutParameterID:
|
||||||
|
p.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(val)*time.Second)
|
||||||
|
case maxPacketSizeParameterID:
|
||||||
|
if val < 1200 {
|
||||||
|
return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", val)
|
||||||
|
}
|
||||||
|
p.MaxPacketSize = protocol.ByteCount(val)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("TransportParameter BUG: transport parameter %d not found", paramID)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -131,36 +144,36 @@ func (p *TransportParameters) unmarshal(data []byte) error {
|
||||||
func (p *TransportParameters) marshal(b *bytes.Buffer) {
|
func (p *TransportParameters) marshal(b *bytes.Buffer) {
|
||||||
// initial_max_stream_data_bidi_local
|
// initial_max_stream_data_bidi_local
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiLocalParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 4)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiLocal))))
|
||||||
utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataBidiLocal))
|
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiLocal))
|
||||||
// initial_max_stream_data_bidi_remote
|
// initial_max_stream_data_bidi_remote
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataBidiRemoteParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 4)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataBidiRemote))))
|
||||||
utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataBidiRemote))
|
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataBidiRemote))
|
||||||
// initial_max_stream_data_uni
|
// initial_max_stream_data_uni
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataUniParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataUniParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 4)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxStreamDataUni))))
|
||||||
utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxStreamDataUni))
|
utils.WriteVarInt(b, uint64(p.InitialMaxStreamDataUni))
|
||||||
// initial_max_data
|
// initial_max_data
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 4)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.InitialMaxData))))
|
||||||
utils.BigEndian.WriteUint32(b, uint32(p.InitialMaxData))
|
utils.WriteVarInt(b, uint64(p.InitialMaxData))
|
||||||
// initial_max_bidi_streams
|
// initial_max_bidi_streams
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxBidiStreamsParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxBidiStreamsParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 2)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxBidiStreams)))
|
||||||
utils.BigEndian.WriteUint16(b, p.MaxBidiStreams)
|
utils.WriteVarInt(b, p.MaxBidiStreams)
|
||||||
// initial_max_uni_streams
|
// initial_max_uni_streams
|
||||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxUniStreamsParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(initialMaxUniStreamsParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 2)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(p.MaxUniStreams)))
|
||||||
utils.BigEndian.WriteUint16(b, p.MaxUniStreams)
|
utils.WriteVarInt(b, p.MaxUniStreams)
|
||||||
// idle_timeout
|
// idle_timeout
|
||||||
utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 2)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(p.IdleTimeout/time.Second))))
|
||||||
utils.BigEndian.WriteUint16(b, uint16(p.IdleTimeout/time.Second))
|
utils.WriteVarInt(b, uint64(p.IdleTimeout/time.Second))
|
||||||
// max_packet_size
|
// max_packet_size
|
||||||
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
|
||||||
utils.BigEndian.WriteUint16(b, 2)
|
utils.BigEndian.WriteUint16(b, uint16(utils.VarIntLen(uint64(protocol.MaxReceivePacketSize))))
|
||||||
utils.BigEndian.WriteUint16(b, uint16(protocol.MaxReceivePacketSize))
|
utils.WriteVarInt(b, uint64(protocol.MaxReceivePacketSize))
|
||||||
// disable_migration
|
// disable_migration
|
||||||
if p.DisableMigration {
|
if p.DisableMigration {
|
||||||
utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID))
|
utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID))
|
||||||
|
|
|
@ -380,8 +380,8 @@ func (s *server) createNewSession(
|
||||||
InitialMaxStreamDataUni: protocol.InitialMaxStreamData,
|
InitialMaxStreamDataUni: protocol.InitialMaxStreamData,
|
||||||
InitialMaxData: protocol.InitialMaxData,
|
InitialMaxData: protocol.InitialMaxData,
|
||||||
IdleTimeout: s.config.IdleTimeout,
|
IdleTimeout: s.config.IdleTimeout,
|
||||||
MaxBidiStreams: uint16(s.config.MaxIncomingStreams),
|
MaxBidiStreams: uint64(s.config.MaxIncomingStreams),
|
||||||
MaxUniStreams: uint16(s.config.MaxIncomingUniStreams),
|
MaxUniStreams: uint64(s.config.MaxIncomingUniStreams),
|
||||||
DisableMigration: true,
|
DisableMigration: true,
|
||||||
// TODO(#855): generate a real token
|
// TODO(#855): generate a real token
|
||||||
StatelessResetToken: bytes.Repeat([]byte{42}, 16),
|
StatelessResetToken: bytes.Repeat([]byte{42}, 16),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue