Files
quic-go/internal/handshake/params_negotiator_gquic.go
Marten Seemann daff6256b9 don't negotiate the maximum incoming streams value
The maximum number of incoming streams doesn't need to be negotiated. It
is a value that is only announced by the peer, and has to be respected.
Furthermore, Chrome doesn't seem to care about the MSPC value anymore
(since MIDS was introduced), so there's no need to send this in the
handshake any more.
2017-10-20 17:35:30 +07:00

117 lines
3.6 KiB
Go

package handshake
import (
"bytes"
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// errMalformedTag is returned when the tag value cannot be read
var (
errMalformedTag = qerr.Error(qerr.InvalidCryptoMessageParameter, "malformed Tag value")
errFlowControlRenegotiationNotSupported = qerr.Error(qerr.InvalidCryptoMessageParameter, "renegotiation of flow control parameters not supported")
)
type paramsNegotiatorGQUIC struct {
paramsNegotiatorBase
}
var _ ParamsNegotiator = &paramsNegotiatorGQUIC{}
// newParamsNegotiatorGQUIC creates a new connection parameters manager
func newParamsNegotiatorGQUIC(pers protocol.Perspective, v protocol.VersionNumber, params *TransportParameters) *paramsNegotiatorGQUIC {
h := &paramsNegotiatorGQUIC{}
h.perspective = pers
h.version = v
h.init(params)
return h
}
// SetFromMap reads all params.
func (h *paramsNegotiatorGQUIC) SetFromMap(params map[Tag][]byte) error {
h.mutex.Lock()
defer h.mutex.Unlock()
if value, ok := params[TagTCID]; ok && h.perspective == protocol.PerspectiveServer {
clientValue, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value))
if err != nil {
return errMalformedTag
}
h.omitConnectionID = (clientValue == 0)
}
if value, ok := params[TagMIDS]; ok {
clientValue, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value))
if err != nil {
return errMalformedTag
}
h.maxIncomingDynamicStreamsPerConnection = h.negotiateMaxIncomingDynamicStreamsPerConnection(clientValue)
}
if value, ok := params[TagICSL]; ok {
clientValue, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value))
if err != nil {
return errMalformedTag
}
h.setRemoteIdleTimeout(time.Duration(clientValue) * time.Second)
}
if value, ok := params[TagSFCW]; ok {
if h.flowControlNegotiated {
return errFlowControlRenegotiationNotSupported
}
sendStreamFlowControlWindow, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value))
if err != nil {
return errMalformedTag
}
h.sendStreamFlowControlWindow = protocol.ByteCount(sendStreamFlowControlWindow)
}
if value, ok := params[TagCFCW]; ok {
if h.flowControlNegotiated {
return errFlowControlRenegotiationNotSupported
}
sendConnectionFlowControlWindow, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value))
if err != nil {
return errMalformedTag
}
h.sendConnectionFlowControlWindow = protocol.ByteCount(sendConnectionFlowControlWindow)
}
_, containsSFCW := params[TagSFCW]
_, containsCFCW := params[TagCFCW]
if containsCFCW || containsSFCW {
h.flowControlNegotiated = true
}
return nil
}
// GetHelloMap gets all parameters needed for the Hello message.
func (h *paramsNegotiatorGQUIC) GetHelloMap() (map[Tag][]byte, error) {
sfcw := bytes.NewBuffer([]byte{})
utils.LittleEndian.WriteUint32(sfcw, uint32(h.GetReceiveStreamFlowControlWindow()))
cfcw := bytes.NewBuffer([]byte{})
utils.LittleEndian.WriteUint32(cfcw, uint32(h.GetReceiveConnectionFlowControlWindow()))
mids := bytes.NewBuffer([]byte{})
utils.LittleEndian.WriteUint32(mids, protocol.MaxIncomingDynamicStreamsPerConnection)
icsl := bytes.NewBuffer([]byte{})
utils.LittleEndian.WriteUint32(icsl, uint32(h.idleTimeout/time.Second))
return map[Tag][]byte{
TagICSL: icsl.Bytes(),
TagMIDS: mids.Bytes(),
TagCFCW: cfcw.Bytes(),
TagSFCW: sfcw.Bytes(),
}, nil
}
func (h *paramsNegotiatorGQUIC) OmitConnectionID() bool {
if h.perspective == protocol.PerspectiveClient {
return false
}
h.mutex.RLock()
defer h.mutex.RUnlock()
return h.omitConnectionID
}