forked from quic-go/quic-go
implement (un)marshalling of the transport parameters
This commit is contained in:
@@ -96,98 +96,110 @@ func (p *TransportParameters) getHelloMap() map[Tag][]byte {
|
||||
return tags
|
||||
}
|
||||
|
||||
// readTransportParameters reads the transport parameters sent in the QUIC TLS extension
|
||||
func readTransportParameters(paramsList []transportParameter) (*TransportParameters, error) {
|
||||
params := &TransportParameters{}
|
||||
|
||||
func (p *TransportParameters) unmarshal(data []byte) error {
|
||||
var foundIdleTimeout bool
|
||||
|
||||
for _, p := range paramsList {
|
||||
switch p.Parameter {
|
||||
for len(data) >= 4 {
|
||||
paramID := binary.BigEndian.Uint16(data[:2])
|
||||
paramLen := int(binary.BigEndian.Uint16(data[2:4]))
|
||||
data = data[4:]
|
||||
if len(data) < paramLen {
|
||||
return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(data), paramLen)
|
||||
}
|
||||
switch transportParameterID(paramID) {
|
||||
case initialMaxStreamDataParameterID:
|
||||
if len(p.Value) != 4 {
|
||||
return nil, fmt.Errorf("wrong length for initial_max_stream_data: %d (expected 4)", len(p.Value))
|
||||
if paramLen != 4 {
|
||||
return fmt.Errorf("wrong length for initial_max_stream_data: %d (expected 4)", paramLen)
|
||||
}
|
||||
params.StreamFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(p.Value))
|
||||
p.StreamFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
||||
case initialMaxDataParameterID:
|
||||
if len(p.Value) != 4 {
|
||||
return nil, fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", len(p.Value))
|
||||
if paramLen != 4 {
|
||||
return fmt.Errorf("wrong length for initial_max_data: %d (expected 4)", paramLen)
|
||||
}
|
||||
params.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(p.Value))
|
||||
p.ConnectionFlowControlWindow = protocol.ByteCount(binary.BigEndian.Uint32(data[:4]))
|
||||
case initialMaxBidiStreamsParameterID:
|
||||
if len(p.Value) != 2 {
|
||||
return nil, fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 2)", len(p.Value))
|
||||
if paramLen != 2 {
|
||||
return fmt.Errorf("wrong length for initial_max_stream_id_bidi: %d (expected 2)", paramLen)
|
||||
}
|
||||
params.MaxBidiStreams = binary.BigEndian.Uint16(p.Value)
|
||||
p.MaxBidiStreams = binary.BigEndian.Uint16(data[:2])
|
||||
case initialMaxUniStreamsParameterID:
|
||||
if len(p.Value) != 2 {
|
||||
return nil, fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", len(p.Value))
|
||||
if paramLen != 2 {
|
||||
return fmt.Errorf("wrong length for initial_max_stream_id_uni: %d (expected 2)", paramLen)
|
||||
}
|
||||
params.MaxUniStreams = binary.BigEndian.Uint16(p.Value)
|
||||
p.MaxUniStreams = binary.BigEndian.Uint16(data[:2])
|
||||
case idleTimeoutParameterID:
|
||||
foundIdleTimeout = true
|
||||
if len(p.Value) != 2 {
|
||||
return nil, fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", len(p.Value))
|
||||
if paramLen != 2 {
|
||||
return fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", paramLen)
|
||||
}
|
||||
params.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(binary.BigEndian.Uint16(p.Value))*time.Second)
|
||||
p.IdleTimeout = utils.MaxDuration(protocol.MinRemoteIdleTimeout, time.Duration(binary.BigEndian.Uint16(data[:2]))*time.Second)
|
||||
case maxPacketSizeParameterID:
|
||||
if len(p.Value) != 2 {
|
||||
return nil, fmt.Errorf("wrong length for max_packet_size: %d (expected 2)", len(p.Value))
|
||||
if paramLen != 2 {
|
||||
return fmt.Errorf("wrong length for max_packet_size: %d (expected 2)", paramLen)
|
||||
}
|
||||
maxPacketSize := protocol.ByteCount(binary.BigEndian.Uint16(p.Value))
|
||||
maxPacketSize := protocol.ByteCount(binary.BigEndian.Uint16(data[:2]))
|
||||
if maxPacketSize < 1200 {
|
||||
return nil, fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", maxPacketSize)
|
||||
return fmt.Errorf("invalid value for max_packet_size: %d (minimum 1200)", maxPacketSize)
|
||||
}
|
||||
params.MaxPacketSize = maxPacketSize
|
||||
p.MaxPacketSize = maxPacketSize
|
||||
case disableMigrationParameterID:
|
||||
if len(p.Value) != 0 {
|
||||
return nil, fmt.Errorf("wrong length for disable_migration: %d (expected empty)", len(p.Value))
|
||||
if paramLen != 0 {
|
||||
return fmt.Errorf("wrong length for disable_migration: %d (expected empty)", paramLen)
|
||||
}
|
||||
params.DisableMigration = true
|
||||
p.DisableMigration = true
|
||||
case statelessResetTokenParameterID:
|
||||
if len(p.Value) != 16 {
|
||||
return nil, fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", len(p.Value))
|
||||
if paramLen != 16 {
|
||||
return fmt.Errorf("wrong length for stateless_reset_token: %d (expected 16)", paramLen)
|
||||
}
|
||||
params.StatelessResetToken = p.Value
|
||||
p.StatelessResetToken = data[:16]
|
||||
}
|
||||
data = data[paramLen:]
|
||||
}
|
||||
|
||||
if !foundIdleTimeout {
|
||||
return nil, errors.New("missing parameter")
|
||||
if len(data) != 0 {
|
||||
return fmt.Errorf("should have read all data. Still have %d bytes", len(data))
|
||||
}
|
||||
return params, nil
|
||||
if !foundIdleTimeout {
|
||||
return errors.New("missing parameter")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTransportParameters gets the parameters needed for the TLS handshake.
|
||||
// It doesn't send the initial_max_stream_id_uni parameter, so the peer isn't allowed to open any unidirectional streams.
|
||||
func (p *TransportParameters) getTransportParameters() []transportParameter {
|
||||
initialMaxStreamData := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(initialMaxStreamData, uint32(p.StreamFlowControlWindow))
|
||||
initialMaxData := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(initialMaxData, uint32(p.ConnectionFlowControlWindow))
|
||||
initialMaxBidiStreamID := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(initialMaxBidiStreamID, p.MaxBidiStreams)
|
||||
initialMaxUniStreamID := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(initialMaxUniStreamID, p.MaxUniStreams)
|
||||
idleTimeout := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(idleTimeout, uint16(p.IdleTimeout/time.Second))
|
||||
maxPacketSize := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(maxPacketSize, uint16(protocol.MaxReceivePacketSize))
|
||||
params := []transportParameter{
|
||||
{initialMaxStreamDataParameterID, initialMaxStreamData},
|
||||
{initialMaxDataParameterID, initialMaxData},
|
||||
{initialMaxBidiStreamsParameterID, initialMaxBidiStreamID},
|
||||
{initialMaxUniStreamsParameterID, initialMaxUniStreamID},
|
||||
{idleTimeoutParameterID, idleTimeout},
|
||||
{maxPacketSizeParameterID, maxPacketSize},
|
||||
}
|
||||
func (p *TransportParameters) marshal(b *bytes.Buffer) {
|
||||
// initial_max_stream_data
|
||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxStreamDataParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 4)
|
||||
utils.BigEndian.WriteUint32(b, uint32(p.StreamFlowControlWindow))
|
||||
// initial_max_data
|
||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxDataParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 4)
|
||||
utils.BigEndian.WriteUint32(b, uint32(p.ConnectionFlowControlWindow))
|
||||
// initial_max_bidi_streams
|
||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxBidiStreamsParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 2)
|
||||
utils.BigEndian.WriteUint16(b, p.MaxBidiStreams)
|
||||
// initial_max_uni_streams
|
||||
utils.BigEndian.WriteUint16(b, uint16(initialMaxUniStreamsParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 2)
|
||||
utils.BigEndian.WriteUint16(b, p.MaxUniStreams)
|
||||
// idle_timeout
|
||||
utils.BigEndian.WriteUint16(b, uint16(idleTimeoutParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 2)
|
||||
utils.BigEndian.WriteUint16(b, uint16(p.IdleTimeout/time.Second))
|
||||
// max_packet_size
|
||||
utils.BigEndian.WriteUint16(b, uint16(maxPacketSizeParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 2)
|
||||
utils.BigEndian.WriteUint16(b, uint16(protocol.MaxReceivePacketSize))
|
||||
// disable_migration
|
||||
if p.DisableMigration {
|
||||
params = append(params, transportParameter{disableMigrationParameterID, nil})
|
||||
utils.BigEndian.WriteUint16(b, uint16(disableMigrationParameterID))
|
||||
utils.BigEndian.WriteUint16(b, 0)
|
||||
}
|
||||
if len(p.StatelessResetToken) > 0 {
|
||||
params = append(params, transportParameter{statelessResetTokenParameterID, p.StatelessResetToken})
|
||||
utils.BigEndian.WriteUint16(b, uint16(statelessResetTokenParameterID))
|
||||
utils.BigEndian.WriteUint16(b, uint16(len(p.StatelessResetToken))) // should always be 16 bytes
|
||||
b.Write(p.StatelessResetToken)
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
// String returns a string representation, intended for logging.
|
||||
|
||||
Reference in New Issue
Block a user