diff --git a/integrationtests/chrome/chrome_test.go b/integrationtests/chrome/chrome_test.go index 72d1edccc..b6a9ec5bf 100644 --- a/integrationtests/chrome/chrome_test.go +++ b/integrationtests/chrome/chrome_test.go @@ -54,7 +54,7 @@ var _ = Describe("Chrome tests", func() { }) It("uploads many small files", func() { - num := protocol.MaxStreamsPerConnection + 20 + num := protocol.MaxIncomingStreams + 20 chromeTest( version, fmt.Sprintf("https://quic.clemente.io/uploadtest?num=%d&len=%d", num, dataLen), diff --git a/internal/handshake/params_negotiator_base.go b/internal/handshake/params_negotiator_base.go index d99d5a55c..3465cc3c4 100644 --- a/internal/handshake/params_negotiator_base.go +++ b/internal/handshake/params_negotiator_base.go @@ -39,13 +39,13 @@ type paramsNegotiatorBase struct { omitConnectionID bool requestConnectionIDOmission bool - maxIncomingDynamicStreamsPerConnection uint32 - idleTimeout time.Duration - remoteIdleTimeout time.Duration - sendStreamFlowControlWindow protocol.ByteCount - sendConnectionFlowControlWindow protocol.ByteCount - receiveStreamFlowControlWindow protocol.ByteCount - receiveConnectionFlowControlWindow protocol.ByteCount + maxOutgoingStreams uint32 + idleTimeout time.Duration + remoteIdleTimeout time.Duration + sendStreamFlowControlWindow protocol.ByteCount + sendConnectionFlowControlWindow protocol.ByteCount + receiveStreamFlowControlWindow protocol.ByteCount + receiveConnectionFlowControlWindow protocol.ByteCount } func (h *paramsNegotiatorBase) init(params *TransportParameters) { @@ -56,15 +56,8 @@ func (h *paramsNegotiatorBase) init(params *TransportParameters) { h.requestConnectionIDOmission = params.RequestConnectionIDOmission h.idleTimeout = params.IdleTimeout - if h.perspective == protocol.PerspectiveServer { - h.maxIncomingDynamicStreamsPerConnection = protocol.MaxStreamsPerConnection // "incoming" seen from the client's perspective - } else { - h.maxIncomingDynamicStreamsPerConnection = protocol.MaxStreamsPerConnection // "incoming" seen from the server's perspective - } -} - -func (h *paramsNegotiatorBase) negotiateMaxIncomingDynamicStreamsPerConnection(clientValue uint32) uint32 { - return utils.MinUint32(clientValue, protocol.MaxIncomingDynamicStreamsPerConnection) + // use this as a default value. As soon as the client sends its value, this gets updated + h.maxOutgoingStreams = protocol.MaxOutgoingStreams } // GetSendStreamFlowControlWindow gets the size of the stream-level flow control window for sending data @@ -97,8 +90,11 @@ func (h *paramsNegotiatorBase) GetReceiveConnectionFlowControlWindow() protocol. func (h *paramsNegotiatorBase) GetMaxOutgoingStreams() uint32 { h.mutex.RLock() defer h.mutex.RUnlock() + return h.maxOutgoingStreams +} - return h.maxIncomingDynamicStreamsPerConnection +func (h *paramsNegotiatorBase) setMaxOutgoingStreams(clientValue uint32) { + h.maxOutgoingStreams = utils.MinUint32(clientValue, protocol.MaxOutgoingStreams) } func (h *paramsNegotiatorBase) setRemoteIdleTimeout(t time.Duration) { diff --git a/internal/handshake/params_negotiator_gquic.go b/internal/handshake/params_negotiator_gquic.go index 89b415382..6d05f073e 100644 --- a/internal/handshake/params_negotiator_gquic.go +++ b/internal/handshake/params_negotiator_gquic.go @@ -47,7 +47,7 @@ func (h *paramsNegotiatorGQUIC) SetFromMap(params map[Tag][]byte) error { if err != nil { return errMalformedTag } - h.maxIncomingDynamicStreamsPerConnection = h.negotiateMaxIncomingDynamicStreamsPerConnection(clientValue) + h.setMaxOutgoingStreams(clientValue) } if value, ok := params[TagICSL]; ok { clientValue, err := utils.LittleEndian.ReadUint32(bytes.NewBuffer(value)) @@ -93,7 +93,7 @@ func (h *paramsNegotiatorGQUIC) GetHelloMap() (map[Tag][]byte, error) { cfcw := bytes.NewBuffer([]byte{}) utils.LittleEndian.WriteUint32(cfcw, uint32(h.GetReceiveConnectionFlowControlWindow())) mids := bytes.NewBuffer([]byte{}) - utils.LittleEndian.WriteUint32(mids, protocol.MaxIncomingDynamicStreamsPerConnection) + utils.LittleEndian.WriteUint32(mids, protocol.MaxIncomingStreams) icsl := bytes.NewBuffer([]byte{}) utils.LittleEndian.WriteUint32(icsl, uint32(h.idleTimeout/time.Second)) diff --git a/internal/handshake/params_negotiator_gquic_test.go b/internal/handshake/params_negotiator_gquic_test.go index 6f154d66f..1a1dfc771 100644 --- a/internal/handshake/params_negotiator_gquic_test.go +++ b/internal/handshake/params_negotiator_gquic_test.go @@ -72,7 +72,7 @@ var _ = Describe("Params Negotiator (for gQUIC)", func() { Expect(err).ToNot(HaveOccurred()) entryMap, err := pn.GetHelloMap() Expect(err).ToNot(HaveOccurred()) - Expect(entryMap[TagMIDS]).To(Equal([]byte{byte(protocol.MaxIncomingDynamicStreamsPerConnection), 0, 0, 0})) + Expect(entryMap[TagMIDS]).To(Equal([]byte{byte(protocol.MaxIncomingStreams), 0, 0, 0})) }) }) @@ -88,7 +88,7 @@ var _ = Describe("Params Negotiator (for gQUIC)", func() { Expect(entryMap).To(HaveKey(TagICSL)) Expect(binary.LittleEndian.Uint32(entryMap[TagICSL])).To(BeEquivalentTo(idleTimeout / time.Second)) Expect(entryMap).To(HaveKey(TagMIDS)) - Expect(binary.LittleEndian.Uint32(entryMap[TagMIDS])).To(BeEquivalentTo(protocol.MaxIncomingDynamicStreamsPerConnection)) + Expect(binary.LittleEndian.Uint32(entryMap[TagMIDS])).To(BeEquivalentTo(protocol.MaxIncomingStreams)) Expect(entryMap).To(HaveKey(TagSFCW)) Expect(binary.LittleEndian.Uint32(entryMap[TagSFCW])).To(BeEquivalentTo(protocol.ReceiveStreamFlowControlWindow)) Expect(entryMap).To(HaveKey(TagCFCW)) diff --git a/internal/protocol/server_parameters.go b/internal/protocol/server_parameters.go index 8472fe8da..2fd3b8504 100644 --- a/internal/protocol/server_parameters.go +++ b/internal/protocol/server_parameters.go @@ -56,11 +56,11 @@ const DefaultMaxReceiveConnectionFlowControlWindowClient = 15 * (1 << 20) // 15 // This is the value that Chromium is using const ConnectionFlowControlMultiplier = 1.5 -// MaxStreamsPerConnection is the maximum value accepted for the number of streams per connection -const MaxStreamsPerConnection = 100 +// MaxOutgoingStreams is the maximum number of streams that we will open to a peer +const MaxOutgoingStreams = 100 -// MaxIncomingDynamicStreamsPerConnection is the maximum value accepted for the incoming number of dynamic streams per connection -const MaxIncomingDynamicStreamsPerConnection = 100 +// MaxIncomingStreams is the maximum number of streams that a peer may open +const MaxIncomingStreams = 100 // MaxStreamsMultiplier is the slack the client is allowed for the maximum number of streams per connection, needed e.g. when packets are out of order or dropped. The minimum of this procentual increase and the absolute increment specified by MaxStreamsMinimumIncrement is used. const MaxStreamsMultiplier = 1.1 @@ -70,7 +70,7 @@ const MaxStreamsMinimumIncrement = 10 // MaxNewStreamIDDelta is the maximum difference between and a newly opened Stream and the highest StreamID that a client has ever opened // note that the number of streams is half this value, since the client can only open streams with open StreamID -const MaxNewStreamIDDelta = 4 * MaxStreamsPerConnection +const MaxNewStreamIDDelta = 4 * MaxOutgoingStreams // MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed. const MaxSessionUnprocessedPackets = DefaultMaxCongestionWindow diff --git a/session_test.go b/session_test.go index 12165de51..3522f982f 100644 --- a/session_test.go +++ b/session_test.go @@ -1563,7 +1563,7 @@ var _ = Describe("Session", func() { Context("counting streams", func() { It("errors when too many streams are opened", func() { - for i := 0; i < protocol.MaxStreamsPerConnection; i++ { + for i := 0; i < protocol.MaxIncomingStreams; i++ { _, err := sess.GetOrOpenStream(protocol.StreamID(i*2 + 1)) Expect(err).NotTo(HaveOccurred()) } diff --git a/streams_map.go b/streams_map.go index 2e7dc9ed1..5bd04d139 100644 --- a/streams_map.go +++ b/streams_map.go @@ -46,7 +46,7 @@ var errMapAccess = errors.New("streamsMap: Error accessing the streams map") func newStreamsMap(newStream newStreamLambda, removeStreamCallback removeStreamCallback, pers protocol.Perspective, connParams handshake.ParamsNegotiator) *streamsMap { // add some tolerance to the maximum incoming streams value - maxStreams := uint32(protocol.MaxIncomingDynamicStreamsPerConnection) + maxStreams := uint32(protocol.MaxIncomingStreams) maxIncomingStreams := utils.MaxUint32( maxStreams+protocol.MaxStreamsMinimumIncrement, uint32(float64(maxStreams)*float64(protocol.MaxStreamsMultiplier)),