diff --git a/client.go b/client.go index 3bf686f7..2072ffa4 100644 --- a/client.go +++ b/client.go @@ -9,9 +9,9 @@ import ( "sync" "time" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" ) type client struct { @@ -124,10 +124,14 @@ func populateClientConfig(config *Config) *Config { } return &Config{ - TLSConfig: config.TLSConfig, - Versions: versions, - HandshakeTimeout: handshakeTimeout, - RequestConnectionIDTruncation: config.RequestConnectionIDTruncation, + TLSConfig: config.TLSConfig, + Versions: versions, + HandshakeTimeout: handshakeTimeout, + RequestConnectionIDTruncation: config.RequestConnectionIDTruncation, + MaxReceiveStreamFlowControlWindowServer: config.MaxReceiveStreamFlowControlWindowServer, + MaxReceiveConnectionFlowControlWindowServer: config.MaxReceiveConnectionFlowControlWindowServer, + MaxReceiveStreamFlowControlWindowClient: config.MaxReceiveStreamFlowControlWindowClient, + MaxReceiveConnectionFlowControlWindowClient: config.MaxReceiveConnectionFlowControlWindowClient, } } diff --git a/handshake/connection_parameters_manager.go b/handshake/connection_parameters_manager.go index 1127471b..799dd4bf 100644 --- a/handshake/connection_parameters_manager.go +++ b/handshake/connection_parameters_manager.go @@ -5,9 +5,9 @@ import ( "sync" "time" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" ) // ConnectionParametersManager negotiates and stores the connection parameters @@ -50,6 +50,11 @@ type connectionParametersManager struct { sendConnectionFlowControlWindow protocol.ByteCount receiveStreamFlowControlWindow protocol.ByteCount receiveConnectionFlowControlWindow protocol.ByteCount + + maxReceiveStreamFlowControlWindowServer protocol.ByteCount + maxReceiveConnectionFlowControlWindowServer protocol.ByteCount + maxReceiveStreamFlowControlWindowClient protocol.ByteCount + maxReceiveConnectionFlowControlWindowClient protocol.ByteCount } var _ ConnectionParametersManager = &connectionParametersManager{} @@ -61,7 +66,24 @@ var ( ) // NewConnectionParamatersManager creates a new connection parameters manager -func NewConnectionParamatersManager(pers protocol.Perspective, v protocol.VersionNumber) ConnectionParametersManager { +func NewConnectionParamatersManager( + pers protocol.Perspective, v protocol.VersionNumber, + maxReceiveStreamFlowControlWindowServer protocol.ByteCount, maxReceiveConnectionFlowControlWindowServer protocol.ByteCount, + maxReceiveStreamFlowControlWindowClient protocol.ByteCount, maxReceiveConnectionFlowControlWindowClient protocol.ByteCount, +) ConnectionParametersManager { + if maxReceiveStreamFlowControlWindowServer == 0 { + maxReceiveStreamFlowControlWindowServer = protocol.DefaultMaxReceiveStreamFlowControlWindowServer + } + if maxReceiveConnectionFlowControlWindowServer == 0 { + maxReceiveConnectionFlowControlWindowServer = protocol.DefaultMaxReceiveConnectionFlowControlWindowServer + } + if maxReceiveStreamFlowControlWindowClient == 0 { + maxReceiveStreamFlowControlWindowClient = protocol.DefaultMaxReceiveStreamFlowControlWindowClient + } + if maxReceiveConnectionFlowControlWindowClient == 0 { + maxReceiveConnectionFlowControlWindowClient = protocol.DefaultMaxReceiveConnectionFlowControlWindowClient + } + h := &connectionParametersManager{ perspective: pers, version: v, @@ -69,6 +91,11 @@ func NewConnectionParamatersManager(pers protocol.Perspective, v protocol.Versio sendConnectionFlowControlWindow: protocol.InitialConnectionFlowControlWindow, // can only be changed by the client receiveStreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow, receiveConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow, + + maxReceiveStreamFlowControlWindowServer: maxReceiveStreamFlowControlWindowServer, + maxReceiveConnectionFlowControlWindowServer: maxReceiveConnectionFlowControlWindowServer, + maxReceiveStreamFlowControlWindowClient: maxReceiveStreamFlowControlWindowClient, + maxReceiveConnectionFlowControlWindowClient: maxReceiveConnectionFlowControlWindowClient, } if h.perspective == protocol.PerspectiveServer { @@ -208,9 +235,9 @@ func (h *connectionParametersManager) GetReceiveStreamFlowControlWindow() protoc // GetMaxReceiveStreamFlowControlWindow gets the maximum size of the stream-level flow control window for sending data func (h *connectionParametersManager) GetMaxReceiveStreamFlowControlWindow() protocol.ByteCount { if h.perspective == protocol.PerspectiveServer { - return protocol.MaxReceiveStreamFlowControlWindowServer + return h.maxReceiveStreamFlowControlWindowServer } - return protocol.MaxReceiveStreamFlowControlWindowClient + return h.maxReceiveStreamFlowControlWindowClient } // GetReceiveConnectionFlowControlWindow gets the size of the stream-level flow control window for receiving data @@ -223,9 +250,9 @@ func (h *connectionParametersManager) GetReceiveConnectionFlowControlWindow() pr // GetMaxReceiveConnectionFlowControlWindow gets the maximum size of the stream-level flow control window for sending data func (h *connectionParametersManager) GetMaxReceiveConnectionFlowControlWindow() protocol.ByteCount { if h.perspective == protocol.PerspectiveServer { - return protocol.MaxReceiveConnectionFlowControlWindowServer + return h.maxReceiveConnectionFlowControlWindowServer } - return protocol.MaxReceiveConnectionFlowControlWindowClient + return h.maxReceiveConnectionFlowControlWindowClient } // GetMaxOutgoingStreams gets the maximum number of outgoing streams per connection diff --git a/handshake/connection_parameters_manager_test.go b/handshake/connection_parameters_manager_test.go index 425a9278..ba8f427d 100644 --- a/handshake/connection_parameters_manager_test.go +++ b/handshake/connection_parameters_manager_test.go @@ -2,6 +2,7 @@ package handshake import ( "encoding/binary" + "math" "time" "github.com/lucas-clemente/quic-go/protocol" @@ -12,10 +13,20 @@ import ( var _ = Describe("ConnectionsParameterManager", func() { var cpm *connectionParametersManager // a connectionParametersManager for a server var cpmClient *connectionParametersManager - + const MB = 1 << 20 + maxReceiveStreamFlowControlWindowServer := protocol.ByteCount(math.Floor(1.1 * MB)) // default is 1 MB + maxReceiveConnectionFlowControlWindowServer := protocol.ByteCount(math.Floor(1.5 * MB)) // default is 1.5 MB + maxReceiveStreamFlowControlWindowClient := protocol.ByteCount(math.Floor(6.4 * MB)) // default is 6 MB + maxReceiveConnectionFlowControlWindowClient := protocol.ByteCount(math.Floor(13 * MB)) // default is 15 MB BeforeEach(func() { - cpm = NewConnectionParamatersManager(protocol.PerspectiveServer, protocol.Version36).(*connectionParametersManager) - cpmClient = NewConnectionParamatersManager(protocol.PerspectiveClient, protocol.Version36).(*connectionParametersManager) + cpm = NewConnectionParamatersManager(protocol.PerspectiveServer, protocol.Version36, + maxReceiveStreamFlowControlWindowServer, maxReceiveConnectionFlowControlWindowServer, + maxReceiveStreamFlowControlWindowClient, maxReceiveConnectionFlowControlWindowClient, + ).(*connectionParametersManager) + cpmClient = NewConnectionParamatersManager(protocol.PerspectiveClient, protocol.Version36, + maxReceiveStreamFlowControlWindowServer, maxReceiveConnectionFlowControlWindowServer, + maxReceiveStreamFlowControlWindowClient, maxReceiveConnectionFlowControlWindowClient, + ).(*connectionParametersManager) }) Context("SHLO", func() { @@ -137,10 +148,19 @@ var _ = Describe("ConnectionsParameterManager", func() { }) It("has the correct maximum flow control windows", func() { - Expect(cpm.GetMaxReceiveStreamFlowControlWindow()).To(Equal(protocol.MaxReceiveStreamFlowControlWindowServer)) - Expect(cpm.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(protocol.MaxReceiveConnectionFlowControlWindowServer)) - Expect(cpmClient.GetMaxReceiveStreamFlowControlWindow()).To(Equal(protocol.MaxReceiveStreamFlowControlWindowClient)) - Expect(cpmClient.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(protocol.MaxReceiveConnectionFlowControlWindowClient)) + Expect(cpm.GetMaxReceiveStreamFlowControlWindow()).To(Equal(maxReceiveStreamFlowControlWindowServer)) + Expect(cpm.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(maxReceiveConnectionFlowControlWindowServer)) + Expect(cpmClient.GetMaxReceiveStreamFlowControlWindow()).To(Equal(maxReceiveStreamFlowControlWindowClient)) + Expect(cpmClient.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(maxReceiveConnectionFlowControlWindowClient)) + }) + + It("defaults to the correct maximum flow control windows", func() { + cpmDefault := NewConnectionParamatersManager(protocol.PerspectiveServer, protocol.Version36, 0, 0, 0, 0).(*connectionParametersManager) + cpmClientDefault := NewConnectionParamatersManager(protocol.PerspectiveClient, protocol.Version36, 0, 0, 0, 0).(*connectionParametersManager) + Expect(cpmDefault.GetMaxReceiveStreamFlowControlWindow()).To(Equal(protocol.DefaultMaxReceiveStreamFlowControlWindowServer)) + Expect(cpmDefault.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(protocol.DefaultMaxReceiveConnectionFlowControlWindowServer)) + Expect(cpmClientDefault.GetMaxReceiveStreamFlowControlWindow()).To(Equal(protocol.DefaultMaxReceiveStreamFlowControlWindowClient)) + Expect(cpmClientDefault.GetMaxReceiveConnectionFlowControlWindow()).To(Equal(protocol.DefaultMaxReceiveConnectionFlowControlWindowClient)) }) It("sets a new stream-level flow control window for sending", func() { diff --git a/handshake/crypto_setup_client_test.go b/handshake/crypto_setup_client_test.go index 31053694..aeb1f5a2 100644 --- a/handshake/crypto_setup_client_test.go +++ b/handshake/crypto_setup_client_test.go @@ -8,9 +8,9 @@ import ( "time" "github.com/lucas-clemente/quic-go/crypto" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -111,7 +111,10 @@ var _ = Describe("Client Crypto Setup", func() { version, stream, nil, - NewConnectionParamatersManager(protocol.PerspectiveClient, version), + NewConnectionParamatersManager(protocol.PerspectiveClient, version, + protocol.DefaultMaxReceiveStreamFlowControlWindowServer, protocol.DefaultMaxReceiveConnectionFlowControlWindowServer, + protocol.DefaultMaxReceiveStreamFlowControlWindowClient, protocol.DefaultMaxReceiveConnectionFlowControlWindowClient, + ), aeadChanged, &TransportParameters{}, nil, diff --git a/handshake/crypto_setup_server_test.go b/handshake/crypto_setup_server_test.go index c326de50..4e681604 100644 --- a/handshake/crypto_setup_server_test.go +++ b/handshake/crypto_setup_server_test.go @@ -7,9 +7,9 @@ import ( "net" "github.com/lucas-clemente/quic-go/crypto" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -184,7 +184,10 @@ var _ = Describe("Server Crypto Setup", func() { Expect(err).NotTo(HaveOccurred()) version = protocol.SupportedVersions[len(protocol.SupportedVersions)-1] supportedVersions = []protocol.VersionNumber{version, 98, 99} - cpm = NewConnectionParamatersManager(protocol.PerspectiveServer, protocol.VersionWhatever) + cpm = NewConnectionParamatersManager(protocol.PerspectiveServer, protocol.VersionWhatever, + protocol.DefaultMaxReceiveStreamFlowControlWindowServer, protocol.DefaultMaxReceiveConnectionFlowControlWindowServer, + protocol.DefaultMaxReceiveStreamFlowControlWindowClient, protocol.DefaultMaxReceiveConnectionFlowControlWindowClient, + ) csInt, err := NewCryptoSetup( protocol.ConnectionID(42), remoteAddr, diff --git a/interface.go b/interface.go index 30bc9b6c..9901203f 100644 --- a/interface.go +++ b/interface.go @@ -80,6 +80,18 @@ type Config struct { // If not set, it verifies that the address matches, and that the STK was issued within the last 24 hours // This option is only valid for the server. AcceptSTK func(clientAddr net.Addr, stk *STK) bool + // MaxReceiveStreamFlowControlWindowServer is the maximum stream-level flow control window for receiving data, for the server + // If this value is zero, the timeout is set to protocol.DefaultMaxReceiveStreamFlowControlWindowServer + MaxReceiveStreamFlowControlWindowServer protocol.ByteCount + // MaxReceiveConnectionFlowControlWindowServer is the connection-level flow control window for receiving data, for the server + // If this value is zero, the timeout is set to protocol.DefaultMaxReceiveConnectionFlowControlWindowServer + MaxReceiveConnectionFlowControlWindowServer protocol.ByteCount + // MaxReceiveStreamFlowControlWindowClient is the maximum stream-level flow control window for receiving data, for the client + // If this value is zero, the timeout is set to protocol.DefaultMaxReceiveStreamFlowControlWindowClient + MaxReceiveStreamFlowControlWindowClient protocol.ByteCount + // MaxReceiveConnectionFlowControlWindowClient is the connection-level flow control window for receiving data, for the client + // If this value is zero, the timeout is set to protocol.DefaultMaxReceiveConnectionFlowControlWindowClient + MaxReceiveConnectionFlowControlWindowClient protocol.ByteCount } // A Listener for incoming QUIC connections diff --git a/protocol/server_parameters.go b/protocol/server_parameters.go index b6284685..8e632cc1 100644 --- a/protocol/server_parameters.go +++ b/protocol/server_parameters.go @@ -39,21 +39,21 @@ const ReceiveStreamFlowControlWindow ByteCount = (1 << 10) * 32 // 32 kB // This is the value that Google servers are using const ReceiveConnectionFlowControlWindow ByteCount = (1 << 10) * 48 // 48 kB -// MaxReceiveStreamFlowControlWindowServer is the maximum stream-level flow control window for receiving data, for the server +// DefaultMaxReceiveStreamFlowControlWindowServer is the default maximum stream-level flow control window for receiving data, for the server // This is the value that Google servers are using -const MaxReceiveStreamFlowControlWindowServer ByteCount = 1 * (1 << 20) // 1 MB +const DefaultMaxReceiveStreamFlowControlWindowServer ByteCount = 1 * (1 << 20) // 1 MB -// MaxReceiveConnectionFlowControlWindowServer is the connection-level flow control window for receiving data, for the server +// DefaultMaxReceiveConnectionFlowControlWindowServer is the default connection-level flow control window for receiving data, for the server // This is the value that Google servers are using -const MaxReceiveConnectionFlowControlWindowServer ByteCount = 1.5 * (1 << 20) // 1.5 MB +const DefaultMaxReceiveConnectionFlowControlWindowServer ByteCount = 1.5 * (1 << 20) // 1.5 MB -// MaxReceiveStreamFlowControlWindowClient is the maximum stream-level flow control window for receiving data, for the client +// DefaultMaxReceiveStreamFlowControlWindowClient is the default maximum stream-level flow control window for receiving data, for the client // This is the value that Chromium is using -const MaxReceiveStreamFlowControlWindowClient ByteCount = 6 * (1 << 20) // 6 MB +const DefaultMaxReceiveStreamFlowControlWindowClient ByteCount = 6 * (1 << 20) // 6 MB -// MaxReceiveConnectionFlowControlWindowClient is the connection-level flow control window for receiving data, for the client +// DefaultMaxReceiveConnectionFlowControlWindowClient is the default connection-level flow control window for receiving data, for the client // This is the value that Google servers are using -const MaxReceiveConnectionFlowControlWindowClient ByteCount = 15 * (1 << 20) // 15 MB +const DefaultMaxReceiveConnectionFlowControlWindowClient ByteCount = 15 * (1 << 20) // 15 MB // ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window // This is the value that Chromium is using diff --git a/server.go b/server.go index c373e99a..a613fe93 100644 --- a/server.go +++ b/server.go @@ -9,9 +9,9 @@ import ( "github.com/lucas-clemente/quic-go/crypto" "github.com/lucas-clemente/quic-go/handshake" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" ) // packetHandler handles packets @@ -122,6 +122,10 @@ func populateServerConfig(config *Config) *Config { Versions: versions, HandshakeTimeout: handshakeTimeout, AcceptSTK: vsa, + MaxReceiveStreamFlowControlWindowServer: config.MaxReceiveStreamFlowControlWindowServer, + MaxReceiveConnectionFlowControlWindowServer: config.MaxReceiveConnectionFlowControlWindowServer, + MaxReceiveStreamFlowControlWindowClient: config.MaxReceiveStreamFlowControlWindowClient, + MaxReceiveConnectionFlowControlWindowClient: config.MaxReceiveConnectionFlowControlWindowClient, } } diff --git a/session.go b/session.go index a11bfbb8..22bdaca8 100644 --- a/session.go +++ b/session.go @@ -12,9 +12,9 @@ import ( "github.com/lucas-clemente/quic-go/flowcontrol" "github.com/lucas-clemente/quic-go/frames" "github.com/lucas-clemente/quic-go/handshake" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/qerr" - "github.com/lucas-clemente/quic-go/internal/utils" ) type unpacker interface { @@ -172,7 +172,9 @@ func (s *session) setup( s.sessionCreationTime = now s.rttStats = &congestion.RTTStats{} - s.connectionParameters = handshake.NewConnectionParamatersManager(s.perspective, s.version) + s.connectionParameters = handshake.NewConnectionParamatersManager(s.perspective, s.version, + s.config.MaxReceiveStreamFlowControlWindowServer, s.config.MaxReceiveConnectionFlowControlWindowServer, + s.config.MaxReceiveStreamFlowControlWindowClient, s.config.MaxReceiveConnectionFlowControlWindowClient) s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats) s.flowControlManager = flowcontrol.NewFlowControlManager(s.connectionParameters, s.rttStats) s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.ackAlarmChanged)