diff --git a/config.go b/config.go index d80e965a6..886ef0d60 100644 --- a/config.go +++ b/config.go @@ -71,10 +71,18 @@ func populateConfig(config *Config) *Config { if config.MaxIdleTimeout != 0 { idleTimeout = config.MaxIdleTimeout } + initialStreamFlowControlWindow := config.InitialStreamFlowControlWindow + if initialStreamFlowControlWindow == 0 { + initialStreamFlowControlWindow = protocol.DefaultInitialMaxStreamData + } maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow if maxReceiveStreamFlowControlWindow == 0 { maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow } + initialConnectionFlowControlWindow := config.InitialConnectionFlowControlWindow + if initialConnectionFlowControlWindow == 0 { + initialConnectionFlowControlWindow = protocol.DefaultInitialMaxData + } maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow if maxReceiveConnectionFlowControlWindow == 0 { maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow @@ -98,7 +106,9 @@ func populateConfig(config *Config) *Config { MaxIdleTimeout: idleTimeout, AcceptToken: config.AcceptToken, KeepAlive: config.KeepAlive, + InitialStreamFlowControlWindow: initialStreamFlowControlWindow, MaxReceiveStreamFlowControlWindow: maxReceiveStreamFlowControlWindow, + InitialConnectionFlowControlWindow: initialConnectionFlowControlWindow, MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow, MaxIncomingStreams: maxIncomingStreams, MaxIncomingUniStreams: maxIncomingUniStreams, diff --git a/config_test.go b/config_test.go index 9e42eec41..e5a1b04dc 100644 --- a/config_test.go +++ b/config_test.go @@ -57,8 +57,12 @@ var _ = Describe("Config", func() { f.Set(reflect.ValueOf(time.Hour)) case "TokenStore": f.Set(reflect.ValueOf(NewLRUTokenStore(2, 3))) + case "InitialStreamFlowControlWindow": + f.Set(reflect.ValueOf(uint64(1234))) case "MaxReceiveStreamFlowControlWindow": f.Set(reflect.ValueOf(uint64(9))) + case "InitialConnectionFlowControlWindow": + f.Set(reflect.ValueOf(uint64(4321))) case "MaxReceiveConnectionFlowControlWindow": f.Set(reflect.ValueOf(uint64(10))) case "MaxIncomingStreams": @@ -142,7 +146,9 @@ var _ = Describe("Config", func() { c := populateConfig(&Config{}) Expect(c.Versions).To(Equal(protocol.SupportedVersions)) Expect(c.HandshakeIdleTimeout).To(Equal(protocol.DefaultHandshakeIdleTimeout)) + Expect(c.InitialStreamFlowControlWindow).To(BeEquivalentTo(protocol.DefaultInitialMaxStreamData)) Expect(c.MaxReceiveStreamFlowControlWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveStreamFlowControlWindow)) + Expect(c.InitialConnectionFlowControlWindow).To(BeEquivalentTo(protocol.DefaultInitialMaxData)) Expect(c.MaxReceiveConnectionFlowControlWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveConnectionFlowControlWindow)) Expect(c.MaxIncomingStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingStreams)) Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingUniStreams)) diff --git a/interface.go b/interface.go index b6df74ff9..683107cc7 100644 --- a/interface.go +++ b/interface.go @@ -255,9 +255,19 @@ type Config struct { // The key used to store tokens is the ServerName from the tls.Config, if set // otherwise the token is associated with the server's IP address. TokenStore TokenStore + // InitialStreamFlowControlWindow is the initial size of the stream-level flow control window for receiving data. + // If the application is consuming data quickly enough, the flow control auto-tuning algorithm + // will increase the window up to MaxReceiveStreamFlowControlWindow. + // If this value is zero, it will default to 512 KB. + InitialStreamFlowControlWindow uint64 // MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data. // If this value is zero, it will default to 6 MB. MaxReceiveStreamFlowControlWindow uint64 + // InitialConnectionFlowControlWindow is the initial size of the stream-level flow control window for receiving data. + // If the application is consuming data quickly enough, the flow control auto-tuning algorithm + // will increase the window up to MaxReceiveConnectionFlowControlWindow. + // If this value is zero, it will default to 512 KB. + InitialConnectionFlowControlWindow uint64 // MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data. // If this value is zero, it will default to 15 MB. MaxReceiveConnectionFlowControlWindow uint64 diff --git a/internal/protocol/params.go b/internal/protocol/params.go index 7d9d5d9bc..4bc33e274 100644 --- a/internal/protocol/params.go +++ b/internal/protocol/params.go @@ -21,11 +21,11 @@ const MaxUndecryptablePackets = 32 // This is the value that Chromium is using const ConnectionFlowControlMultiplier = 1.5 -// InitialMaxStreamData is the stream-level flow control window for receiving data -const InitialMaxStreamData = (1 << 10) * 512 // 512 kb +// DefaultInitialMaxStreamData is the default initial stream-level flow control window for receiving data +const DefaultInitialMaxStreamData = (1 << 10) * 512 // 512 kb -// InitialMaxData is the connection-level flow control window for receiving data -const InitialMaxData = ConnectionFlowControlMultiplier * InitialMaxStreamData +// DefaultInitialMaxData is the connection-level flow control window for receiving data +const DefaultInitialMaxData = ConnectionFlowControlMultiplier * DefaultInitialMaxStreamData // DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB diff --git a/session.go b/session.go index f6999bdbe..2a75fd559 100644 --- a/session.go +++ b/session.go @@ -295,10 +295,10 @@ var newSession = func( initialStream := newCryptoStream() handshakeStream := newCryptoStream() params := &wire.TransportParameters{ - InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, - InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, - InitialMaxStreamDataUni: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, + InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxData: protocol.ByteCount(s.config.InitialConnectionFlowControlWindow), MaxIdleTimeout: s.config.MaxIdleTimeout, MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams), MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams), @@ -419,10 +419,10 @@ var newClientSession = func( initialStream := newCryptoStream() handshakeStream := newCryptoStream() params := &wire.TransportParameters{ - InitialMaxStreamDataBidiRemote: protocol.InitialMaxStreamData, - InitialMaxStreamDataBidiLocal: protocol.InitialMaxStreamData, - InitialMaxStreamDataUni: protocol.InitialMaxStreamData, - InitialMaxData: protocol.InitialMaxData, + InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamFlowControlWindow), + InitialMaxData: protocol.ByteCount(s.config.InitialConnectionFlowControlWindow), MaxIdleTimeout: s.config.MaxIdleTimeout, MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams), MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams), @@ -496,7 +496,7 @@ func (s *session) preSetup() { s.frameParser = wire.NewFrameParser(s.config.EnableDatagrams, s.version) s.rttStats = &utils.RTTStats{} s.connFlowController = flowcontrol.NewConnectionFlowController( - protocol.InitialMaxData, + protocol.ByteCount(s.config.InitialConnectionFlowControlWindow), protocol.ByteCount(s.config.MaxReceiveConnectionFlowControlWindow), s.onHasConnectionWindowUpdate, s.rttStats, @@ -1822,7 +1822,7 @@ func (s *session) newFlowController(id protocol.StreamID) flowcontrol.StreamFlow return flowcontrol.NewStreamFlowController( id, s.connFlowController, - protocol.InitialMaxStreamData, + protocol.ByteCount(s.config.InitialStreamFlowControlWindow), protocol.ByteCount(s.config.MaxReceiveStreamFlowControlWindow), initialSendWindow, s.onHasStreamWindowUpdate,