Have separate uni- and bi-directional stream limits for IETF QUIC IETF QUIC supports unidirectional and bidirectional streams, each of which can have a different stream limit. The stream limit is first negotiated using the transport parameters. This change connects the transport parameters to the stream-id-manager so that the former can configure both the types of streams. gfe-relnote: N/A all for version99 code. PiperOrigin-RevId: 248325885 Change-Id: I4675c147dfda856b73337aac87a4290958599a18
diff --git a/quic/core/crypto/crypto_handshake_message.cc b/quic/core/crypto/crypto_handshake_message.cc index 1bbed74..579bb37 100644 --- a/quic/core/crypto/crypto_handshake_message.cc +++ b/quic/core/crypto/crypto_handshake_message.cc
@@ -274,7 +274,8 @@ case kCFCW: case kSFCW: case kIRTT: - case kMIDS: + case kMIUS: + case kMIBS: case kSCLS: case kTCID: // uint32_t value
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index a3abb33..e8c8d84 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -218,7 +218,8 @@ const QuicTag kCLOP = TAG('C', 'L', 'O', 'P'); // Client connection options const QuicTag kICSL = TAG('I', 'C', 'S', 'L'); // Idle network timeout const QuicTag kSCLS = TAG('S', 'C', 'L', 'S'); // Silently close on timeout -const QuicTag kMIDS = TAG('M', 'I', 'D', 'S'); // Max incoming dynamic streams +const QuicTag kMIBS = TAG('M', 'I', 'D', 'S'); // Max incoming bidi streams +const QuicTag kMIUS = TAG('M', 'I', 'U', 'S'); // Max incoming unidi streams const QuicTag kIRTT = TAG('I', 'R', 'T', 'T'); // Estimated initial RTT in us. const QuicTag kSNI = TAG('S', 'N', 'I', '\0'); // Server name // indication
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index 2675428..209bc81 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -1389,7 +1389,7 @@ // Set a limit on maximum number of incoming dynamic streams. // Make sure the limit is respected. const uint32_t kServerMaxIncomingDynamicStreams = 1; - server_config_.SetMaxIncomingDynamicStreamsToSend( + server_config_.SetMaxIncomingBidirectionalStreamsToSend( kServerMaxIncomingDynamicStreams); ASSERT_TRUE(Initialize()); if (GetParam().negotiated_version.transport_version == QUIC_VERSION_99) { @@ -1430,10 +1430,15 @@ // Each endpoint can set max incoming dynamic streams independently. const uint32_t kClientMaxIncomingDynamicStreams = 2; const uint32_t kServerMaxIncomingDynamicStreams = 1; - client_config_.SetMaxIncomingDynamicStreamsToSend( + client_config_.SetMaxIncomingBidirectionalStreamsToSend( kClientMaxIncomingDynamicStreams); - server_config_.SetMaxIncomingDynamicStreamsToSend( + server_config_.SetMaxIncomingBidirectionalStreamsToSend( kServerMaxIncomingDynamicStreams); + client_config_.SetMaxIncomingUnidirectionalStreamsToSend( + kClientMaxIncomingDynamicStreams); + server_config_.SetMaxIncomingUnidirectionalStreamsToSend( + kServerMaxIncomingDynamicStreams); + ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); @@ -2739,8 +2744,10 @@ const size_t kNumMaxStreams = 10; EndToEndTestServerPush() : EndToEndTest() { - client_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); - server_config_.SetMaxIncomingDynamicStreamsToSend(kNumMaxStreams); + client_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams); + server_config_.SetMaxIncomingBidirectionalStreamsToSend(kNumMaxStreams); + client_config_.SetMaxIncomingUnidirectionalStreamsToSend(kNumMaxStreams); + server_config_.SetMaxIncomingUnidirectionalStreamsToSend(kNumMaxStreams); support_server_push_ = true; }
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc index 0527f0b..b532601 100644 --- a/quic/core/http/quic_server_session_base_test.cc +++ b/quic/core/http/quic_server_session_base_test.cc
@@ -131,9 +131,12 @@ TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { - config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, - kMaxStreamsForTest); + config_.SetMaxIncomingBidirectionalStreamsToSend(kMaxStreamsForTest); + config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( + &config_, kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + &config_, kMaxStreamsForTest); config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend(
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc index 8460c7d..599f939 100644 --- a/quic/core/http/quic_spdy_client_session_test.cc +++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -153,7 +153,15 @@ QuicCryptoClientStream* stream = static_cast<QuicCryptoClientStream*>( session_->GetMutableCryptoStream()); QuicConfig config = DefaultQuicConfig(); - config.SetMaxIncomingDynamicStreamsToSend(server_max_incoming_streams); + if (connection_->transport_version() == QUIC_VERSION_99) { + config.SetMaxIncomingUnidirectionalStreamsToSend( + server_max_incoming_streams); + config.SetMaxIncomingBidirectionalStreamsToSend( + server_max_incoming_streams); + } else { + config.SetMaxIncomingBidirectionalStreamsToSend( + server_max_incoming_streams); + } crypto_test_utils::HandshakeWithFakeServer( &config, &helper_, &alarm_factory_, connection_, stream); }
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc index 26ec153..c7ce057 100644 --- a/quic/core/http/quic_spdy_session_test.cc +++ b/quic/core/http/quic_spdy_session_test.cc
@@ -69,7 +69,7 @@ kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - session()->config()->ToHandshakeMessage(&msg); + session()->config()->ToHandshakeMessage(&msg, transport_version()); const QuicErrorCode error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -565,7 +565,11 @@ TEST_P(QuicSpdySessionTestServer, ManyAvailableStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 200); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); // Create one stream. session_.GetOrCreateDynamicStream(stream_id); @@ -1179,7 +1183,7 @@ QuicStreamOffset offset = crypto_stream->stream_bytes_written(); QuicConfig config; CryptoHandshakeMessage crypto_message; - config.ToHandshakeMessage(&crypto_message); + config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); @@ -1500,7 +1504,12 @@ // with a FIN or RST then we send an RST to refuse streams for versions other // than version 99. In version 99 the connection gets closed. const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } // GetNth assumes that both the crypto and header streams have been // open, but the stream id manager, using GetFirstBidirectional... only // assumes that the crypto stream is open. This means that GetNth...(0) @@ -1573,7 +1582,12 @@ } EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (IsVersion99()) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } // Create kMaxStreams + 1 data streams, and mark them draining. const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0);
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc index 4880c6d..0914809 100644 --- a/quic/core/quic_config.cc +++ b/quic/core/quic_config.cc
@@ -404,7 +404,7 @@ client_connection_options_(kCLOP, PRESENCE_OPTIONAL), idle_network_timeout_seconds_(kICSL, PRESENCE_REQUIRED), silent_close_(kSCLS, PRESENCE_OPTIONAL), - max_incoming_dynamic_streams_(kMIDS, PRESENCE_REQUIRED), + max_incoming_bidirectional_streams_(kMIBS, PRESENCE_REQUIRED), bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL), initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL), initial_stream_flow_control_window_bytes_(kSFCW, PRESENCE_OPTIONAL), @@ -412,7 +412,8 @@ connection_migration_disabled_(kNCMR, PRESENCE_OPTIONAL), alternate_server_address_(kASAD, PRESENCE_OPTIONAL), support_max_header_list_size_(kSMHL, PRESENCE_OPTIONAL), - stateless_reset_token_(kSRST, PRESENCE_OPTIONAL) { + stateless_reset_token_(kSRST, PRESENCE_OPTIONAL), + max_incoming_unidirectional_streams_(kMIUS, PRESENCE_OPTIONAL) { SetDefaults(); } @@ -505,21 +506,38 @@ return silent_close_.GetUint32() > 0; } -void QuicConfig::SetMaxIncomingDynamicStreamsToSend( - uint32_t max_incoming_dynamic_streams) { - max_incoming_dynamic_streams_.SetSendValue(max_incoming_dynamic_streams); +void QuicConfig::SetMaxIncomingBidirectionalStreamsToSend( + uint32_t max_streams) { + max_incoming_bidirectional_streams_.SetSendValue(max_streams); } -uint32_t QuicConfig::GetMaxIncomingDynamicStreamsToSend() { - return max_incoming_dynamic_streams_.GetSendValue(); +uint32_t QuicConfig::GetMaxIncomingBidirectionalStreamsToSend() { + return max_incoming_bidirectional_streams_.GetSendValue(); } -bool QuicConfig::HasReceivedMaxIncomingDynamicStreams() { - return max_incoming_dynamic_streams_.HasReceivedValue(); +bool QuicConfig::HasReceivedMaxIncomingBidirectionalStreams() { + return max_incoming_bidirectional_streams_.HasReceivedValue(); } -uint32_t QuicConfig::ReceivedMaxIncomingDynamicStreams() { - return max_incoming_dynamic_streams_.GetReceivedValue(); +uint32_t QuicConfig::ReceivedMaxIncomingBidirectionalStreams() { + return max_incoming_bidirectional_streams_.GetReceivedValue(); +} + +void QuicConfig::SetMaxIncomingUnidirectionalStreamsToSend( + uint32_t max_streams) { + max_incoming_unidirectional_streams_.SetSendValue(max_streams); +} + +uint32_t QuicConfig::GetMaxIncomingUnidirectionalStreamsToSend() { + return max_incoming_unidirectional_streams_.GetSendValue(); +} + +bool QuicConfig::HasReceivedMaxIncomingUnidirectionalStreams() { + return max_incoming_unidirectional_streams_.HasReceivedValue(); +} + +uint32_t QuicConfig::ReceivedMaxIncomingUnidirectionalStreams() { + return max_incoming_unidirectional_streams_.GetReceivedValue(); } bool QuicConfig::HasSetBytesForConnectionIdToSend() const { @@ -664,7 +682,8 @@ idle_network_timeout_seconds_.set(kMaximumIdleTimeoutSecs, kDefaultIdleTimeoutSecs); silent_close_.set(1, 0); - SetMaxIncomingDynamicStreamsToSend(kDefaultMaxStreamsPerConnection); + SetMaxIncomingBidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); + SetMaxIncomingUnidirectionalStreamsToSend(kDefaultMaxStreamsPerConnection); max_time_before_crypto_handshake_ = QuicTime::Delta::FromSeconds(kMaxTimeForCryptoHandshakeSecs); max_idle_time_before_crypto_handshake_ = @@ -676,10 +695,18 @@ SetSupportMaxHeaderListSize(); } -void QuicConfig::ToHandshakeMessage(CryptoHandshakeMessage* out) const { +void QuicConfig::ToHandshakeMessage( + CryptoHandshakeMessage* out, + QuicTransportVersion transport_version) const { idle_network_timeout_seconds_.ToHandshakeMessage(out); silent_close_.ToHandshakeMessage(out); - max_incoming_dynamic_streams_.ToHandshakeMessage(out); + // Do not need a version check here, max...bi... will encode + // as "MIDS" -- the max initial dynamic streams tag -- if + // doing some version other than IETF QUIC/V99. + max_incoming_bidirectional_streams_.ToHandshakeMessage(out); + if (transport_version == QUIC_VERSION_99) { + max_incoming_unidirectional_streams_.ToHandshakeMessage(out); + } bytes_for_connection_id_.ToHandshakeMessage(out); initial_round_trip_time_us_.ToHandshakeMessage(out); initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out); @@ -707,7 +734,11 @@ silent_close_.ProcessPeerHello(peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { - error = max_incoming_dynamic_streams_.ProcessPeerHello( + error = max_incoming_bidirectional_streams_.ProcessPeerHello( + peer_hello, hello_type, error_details); + } + if (error == QUIC_NO_ERROR) { + error = max_incoming_unidirectional_streams_.ProcessPeerHello( peer_hello, hello_type, error_details); } if (error == QUIC_NO_ERROR) { @@ -771,9 +802,9 @@ params->initial_max_stream_data_uni.set_value( initial_stream_flow_control_window_bytes_.GetSendValue()); params->initial_max_streams_bidi.set_value( - max_incoming_dynamic_streams_.GetSendValue()); + max_incoming_bidirectional_streams_.GetSendValue()); params->initial_max_streams_uni.set_value( - max_incoming_dynamic_streams_.GetSendValue()); + max_incoming_unidirectional_streams_.GetSendValue()); params->max_ack_delay.set_value(kDefaultDelayedAckTimeMs); params->disable_migration = connection_migration_disabled_.HasSendValue() && @@ -846,10 +877,12 @@ initial_session_flow_control_window_bytes_.SetReceivedValue( std::min<uint64_t>(params.initial_max_data.value(), std::numeric_limits<uint32_t>::max())); - - max_incoming_dynamic_streams_.SetReceivedValue( + max_incoming_bidirectional_streams_.SetReceivedValue( std::min<uint64_t>(params.initial_max_streams_bidi.value(), std::numeric_limits<uint32_t>::max())); + max_incoming_unidirectional_streams_.SetReceivedValue( + std::min<uint64_t>(params.initial_max_streams_uni.value(), + std::numeric_limits<uint32_t>::max())); initial_stream_flow_control_window_bytes_.SetReceivedValue( std::min<uint64_t>(params.initial_max_stream_data_bidi_local.value(),
diff --git a/quic/core/quic_config.h b/quic/core/quic_config.h index 8ad161d..ae15b6a 100644 --- a/quic/core/quic_config.h +++ b/quic/core/quic_config.h
@@ -305,14 +305,24 @@ bool SilentClose() const; - void SetMaxIncomingDynamicStreamsToSend( - uint32_t max_incoming_dynamic_streams); + // Configuration for the Google QUIC and IETF QUIC stream ID managers. Note + // that the naming is a bit weird; it is from the perspective of the node + // generating (sending) the configuration and, thus, The "incoming" counts are + // the number of streams that the node sending the configuration is willing to + // accept and therefore the number that the node receiving the confguration + // can create .. the number of outbound streams that may be intiated.. + // There are two sets, one for unidirectional streams and one for + // bidirectional. The bidirectional set also covers Google-QUICs + // dynamic stream count (which are bidirectional streams). + void SetMaxIncomingBidirectionalStreamsToSend(uint32_t max_streams); + uint32_t GetMaxIncomingBidirectionalStreamsToSend(); + bool HasReceivedMaxIncomingBidirectionalStreams(); + uint32_t ReceivedMaxIncomingBidirectionalStreams(); - uint32_t GetMaxIncomingDynamicStreamsToSend(); - - bool HasReceivedMaxIncomingDynamicStreams(); - - uint32_t ReceivedMaxIncomingDynamicStreams(); + void SetMaxIncomingUnidirectionalStreamsToSend(uint32_t max_streams); + uint32_t GetMaxIncomingUnidirectionalStreamsToSend(); + bool HasReceivedMaxIncomingUnidirectionalStreams(); + uint32_t ReceivedMaxIncomingUnidirectionalStreams(); void set_max_time_before_crypto_handshake( QuicTime::Delta max_time_before_crypto_handshake) { @@ -412,7 +422,8 @@ // ToHandshakeMessage serialises the settings in this object as a series of // tags /value pairs and adds them to |out|. - void ToHandshakeMessage(CryptoHandshakeMessage* out) const; + void ToHandshakeMessage(CryptoHandshakeMessage* out, + QuicTransportVersion transport_version) const; // Calls ProcessPeerHello on each negotiable parameter. On failure returns // the corresponding QuicErrorCode and sets detailed error in |error_details|. @@ -456,8 +467,10 @@ QuicNegotiableUint32 idle_network_timeout_seconds_; // Whether to use silent close. Defaults to 0 (false) and is otherwise true. QuicNegotiableUint32 silent_close_; - // Maximum number of incoming dynamic streams that the connection can support. - QuicFixedUint32 max_incoming_dynamic_streams_; + // Maximum number of incoming dynamic streams that a Google QUIC connection + // can support or the maximum number of incoming bidirectional streams that + // an IETF QUIC connection can support. + QuicFixedUint32 max_incoming_bidirectional_streams_; // The number of bytes required for the connection ID. QuicFixedUint32 bytes_for_connection_id_; // Initial round trip time estimate in microseconds. @@ -484,6 +497,10 @@ // be created. This allows for CHLOs that are larger than a single // packet to be processed. QuicTagVector create_session_tag_indicators_; + + // Maximum number of incoming unidirectional streams that the connection can + // support. + QuicFixedUint32 max_incoming_unidirectional_streams_; }; } // namespace quic
diff --git a/quic/core/quic_config_test.cc b/quic/core/quic_config_test.cc index c18c520..84e89c1 100644 --- a/quic/core/quic_config_test.cc +++ b/quic/core/quic_config_test.cc
@@ -21,12 +21,17 @@ namespace test { namespace { -class QuicConfigTest : public QuicTest { +class QuicConfigTest : public QuicTestWithParam<QuicTransportVersion> { protected: QuicConfig config_; }; -TEST_F(QuicConfigTest, ToHandshakeMessage) { +// Run all tests with all versions of QUIC. +INSTANTIATE_TEST_SUITE_P(QuicConfigTests, + QuicConfigTest, + ::testing::ValuesIn(AllSupportedTransportVersions())); + +TEST_P(QuicConfigTest, ToHandshakeMessage) { config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend( @@ -34,7 +39,7 @@ config_.SetIdleNetworkTimeout(QuicTime::Delta::FromSeconds(5), QuicTime::Delta::FromSeconds(2)); CryptoHandshakeMessage msg; - config_.ToHandshakeMessage(&msg); + config_.ToHandshakeMessage(&msg, GetParam()); uint32_t value; QuicErrorCode error = msg.GetUint32(kICSL, &value); @@ -50,7 +55,7 @@ EXPECT_EQ(kInitialSessionFlowControlWindowForTest, value); } -TEST_F(QuicConfigTest, ProcessClientHello) { +TEST_P(QuicConfigTest, ProcessClientHello) { QuicConfig client_config; QuicTagVector cgst; cgst.push_back(kQBIC); @@ -66,7 +71,7 @@ copt.push_back(kTBBR); client_config.SetConnectionOptionsToSend(copt); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; QuicTagVector initial_received_options; @@ -96,7 +101,7 @@ 2 * kInitialSessionFlowControlWindowForTest); } -TEST_F(QuicConfigTest, ProcessServerHello) { +TEST_P(QuicConfigTest, ProcessServerHello) { QuicIpAddress host; host.FromString("127.0.3.1"); const QuicSocketAddress kTestServerAddress = QuicSocketAddress(host, 1234); @@ -115,7 +120,7 @@ server_config.SetAlternateServerAddressToSend(kTestServerAddress); server_config.SetStatelessResetTokenToSend(kTestResetToken); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg); + server_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); @@ -134,13 +139,13 @@ EXPECT_EQ(kTestResetToken, config_.ReceivedStatelessResetToken()); } -TEST_F(QuicConfigTest, MissingOptionalValuesInCHLO) { +TEST_P(QuicConfigTest, MissingOptionalValuesInCHLO) { CryptoHandshakeMessage msg; msg.SetValue(kICSL, 1); // Set all REQUIRED tags. msg.SetValue(kICSL, 1); - msg.SetValue(kMIDS, 1); + msg.SetValue(kMIBS, 1); // No error, as rest are optional. std::string error_details; @@ -150,12 +155,12 @@ EXPECT_TRUE(config_.negotiated()); } -TEST_F(QuicConfigTest, MissingOptionalValuesInSHLO) { +TEST_P(QuicConfigTest, MissingOptionalValuesInSHLO) { CryptoHandshakeMessage msg; // Set all REQUIRED tags. msg.SetValue(kICSL, 1); - msg.SetValue(kMIDS, 1); + msg.SetValue(kMIBS, 1); // No error, as rest are optional. std::string error_details; @@ -165,7 +170,7 @@ EXPECT_TRUE(config_.negotiated()); } -TEST_F(QuicConfigTest, MissingValueInCHLO) { +TEST_P(QuicConfigTest, MissingValueInCHLO) { // Server receives CHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -174,7 +179,7 @@ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); } -TEST_F(QuicConfigTest, MissingValueInSHLO) { +TEST_P(QuicConfigTest, MissingValueInSHLO) { // Client receives SHLO with missing kICSL. CryptoHandshakeMessage msg; std::string error_details; @@ -183,21 +188,21 @@ EXPECT_EQ(QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND, error); } -TEST_F(QuicConfigTest, OutOfBoundSHLO) { +TEST_P(QuicConfigTest, OutOfBoundSHLO) { QuicConfig server_config; server_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs), QuicTime::Delta::FromSeconds(2 * kMaximumIdleTimeoutSecs)); CryptoHandshakeMessage msg; - server_config.ToHandshakeMessage(&msg); + server_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = config_.ProcessPeerHello(msg, SERVER, &error_details); EXPECT_EQ(QUIC_INVALID_NEGOTIATED_VALUE, error); } -TEST_F(QuicConfigTest, InvalidFlowControlWindow) { +TEST_P(QuicConfigTest, InvalidFlowControlWindow) { // QuicConfig should not accept an invalid flow control window to send to the // peer: the receive window must be at least the default of 16 Kb. QuicConfig config; @@ -210,7 +215,7 @@ config.GetInitialStreamFlowControlWindowToSend()); } -TEST_F(QuicConfigTest, HasClientSentConnectionOption) { +TEST_P(QuicConfigTest, HasClientSentConnectionOption) { QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); @@ -219,7 +224,7 @@ kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = @@ -233,14 +238,14 @@ config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER)); } -TEST_F(QuicConfigTest, DontSendClientConnectionOptions) { +TEST_P(QuicConfigTest, DontSendClientConnectionOptions) { QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); client_config.SetClientConnectionOptions(copt); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error = @@ -251,7 +256,7 @@ EXPECT_FALSE(config_.HasReceivedConnectionOptions()); } -TEST_F(QuicConfigTest, HasClientRequestedIndependentOption) { +TEST_P(QuicConfigTest, HasClientRequestedIndependentOption) { QuicConfig client_config; QuicTagVector client_opt; client_opt.push_back(kRENO); @@ -267,7 +272,7 @@ kTBBR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, GetParam()); std::string error_details; const QuicErrorCode error =
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 0bae7d5..d80b55f 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -4988,7 +4988,7 @@ client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -5055,7 +5055,7 @@ client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -5111,7 +5111,7 @@ client_config.SetIdleNetworkTimeout( QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); + client_config.ToHandshakeMessage(&msg, connection_.transport_version()); const QuicErrorCode error = config.ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error);
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc index 57d8c28..b0c26be 100644 --- a/quic/core/quic_crypto_client_handshaker.cc +++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -263,7 +263,7 @@ DCHECK(session()->config() != nullptr); // Send all the options, regardless of whether we're sending an // inchoate or subsequent hello. - session()->config()->ToHandshakeMessage(&out); + session()->config()->ToHandshakeMessage(&out, session()->transport_version()); if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { crypto_config_->FillInchoateClientHello(
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc index 9e46d6d..025e391 100644 --- a/quic/core/quic_crypto_server_handshaker.cc +++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -208,7 +208,7 @@ session()->OnConfigNegotiated(); - config->ToHandshakeMessage(reply.get()); + config->ToHandshakeMessage(reply.get(), session()->transport_version()); // Receiving a full CHLO implies the client is prepared to decrypt with // the new server write key. We can start to encrypt with the new server
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index 0545fa6..d56689f 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -55,10 +55,13 @@ config_(config), stream_id_manager_(this, kDefaultMaxStreamsPerConnection, - config_.GetMaxIncomingDynamicStreamsToSend()), - v99_streamid_manager_(this, - kDefaultMaxStreamsPerConnection, - config_.GetMaxIncomingDynamicStreamsToSend()), + config_.GetMaxIncomingBidirectionalStreamsToSend()), + v99_streamid_manager_( + this, + kDefaultMaxStreamsPerConnection, + kDefaultMaxStreamsPerConnection, + config_.GetMaxIncomingBidirectionalStreamsToSend(), + config_.GetMaxIncomingUnidirectionalStreamsToSend()), num_dynamic_incoming_streams_(0), num_draining_incoming_streams_(0), num_outgoing_static_streams_(0), @@ -973,23 +976,33 @@ void QuicSession::OnConfigNegotiated() { connection_->SetFromConfig(config_); - uint32_t max_streams = 0; - if (config_.HasReceivedMaxIncomingDynamicStreams()) { - max_streams = config_.ReceivedMaxIncomingDynamicStreams(); - } - QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams; if (connection_->transport_version() == QUIC_VERSION_99) { - // TODO: When transport negotiation knows about bi- and uni- directional - // streams, this should be modified to indicate which one to the manager. - // Currently, BOTH are set to the same value. - // TODO(fkastenholz): AdjustMax is cognizant of the number of static streams - // and sets the maximum to be max_streams + number_of_statics. This should - // eventually be removed from IETF QUIC. -- Replace the call with - // ConfigureMaxOpen... - v99_streamid_manager_.AdjustMaxOpenOutgoingStreams(max_streams); + uint32_t max_streams = 0; + if (config_.HasReceivedMaxIncomingBidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingBidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting Bidirectional outgoing_max_streams_ to " + << max_streams; + v99_streamid_manager_.AdjustMaxOpenOutgoingBidirectionalStreams( + max_streams); + + max_streams = 0; + if (config_.HasReceivedMaxIncomingUnidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingUnidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting Unidirectional outgoing_max_streams_ to " + << max_streams; + v99_streamid_manager_.AdjustMaxOpenOutgoingUnidirectionalStreams( + max_streams); } else { + uint32_t max_streams = 0; + if (config_.HasReceivedMaxIncomingBidirectionalStreams()) { + max_streams = config_.ReceivedMaxIncomingBidirectionalStreams(); + } + QUIC_DVLOG(1) << "Setting max_open_outgoing_streams_ to " << max_streams; stream_id_manager_.set_max_open_outgoing_streams(max_streams); } + if (perspective() == Perspective::IS_SERVER) { if (config_.HasReceivedConnectionOptions()) { // The following variations change the initial receive flow control @@ -1014,17 +1027,19 @@ config_.SetStatelessResetTokenToSend(GetStatelessResetToken()); } - // A small number of additional incoming streams beyond the limit should be - // allowed. This helps avoid early connection termination when FIN/RSTs for - // old streams are lost or arrive out of order. - // Use a minimum number of additional streams, or a percentage increase, - // whichever is larger. - uint32_t max_incoming_streams_to_send = - config_.GetMaxIncomingDynamicStreamsToSend(); if (connection_->transport_version() == QUIC_VERSION_99) { - v99_streamid_manager_.SetMaxOpenIncomingStreams( - max_incoming_streams_to_send); + v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + config_.GetMaxIncomingBidirectionalStreamsToSend()); + v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + config_.GetMaxIncomingUnidirectionalStreamsToSend()); } else { + // A small number of additional incoming streams beyond the limit should be + // allowed. This helps avoid early connection termination when FIN/RSTs for + // old streams are lost or arrive out of order. + // Use a minimum number of additional streams, or a percentage increase, + // whichever is larger. + uint32_t max_incoming_streams_to_send = + config_.GetMaxIncomingBidirectionalStreamsToSend(); uint32_t max_incoming_streams = std::max(max_incoming_streams_to_send + kMaxStreamsMinimumIncrement, static_cast<uint32_t>(max_incoming_streams_to_send *
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index f16477c..7da8ec3 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -419,6 +419,10 @@ static void RecordConnectionCloseAtServer(QuicErrorCode error, ConnectionCloseSource source); + inline QuicTransportVersion transport_version() const { + return connection_->transport_version(); + } + protected: using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>;
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index 8f418c0..95bb6d4 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -69,7 +69,8 @@ kInitialStreamFlowControlWindowForTest); session()->config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - session()->config()->ToHandshakeMessage(&msg); + session()->config()->ToHandshakeMessage( + &msg, session()->connection()->transport_version()); const QuicErrorCode error = session()->config()->ProcessPeerHello(msg, CLIENT, &error_details); EXPECT_EQ(QUIC_NO_ERROR, error); @@ -707,31 +708,86 @@ TEST_P(QuicSessionTestServer, ManyAvailableBidirectionalStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 200); + // Smaller limit on unidirectional streams to help detect crossed wires. + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(&session_, 50); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } + // Create a stream at the start of the range. QuicStreamId stream_id = GetNthClientInitiatedBidirectionalId(0); - // Create one stream. EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); // Create the largest stream ID of a threatened total of 200 streams. // GetNth... starts at 0, so for 200 streams, get the 199th. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( GetNthClientInitiatedBidirectionalId(199))); + + if (transport_version() == QUIC_VERSION_99) { + // If IETF QUIC, check to make sure that creating bidirectional + // streams does not mess up the unidirectional streams. + stream_id = GetNthClientInitiatedUnidirectionalId(0); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + // Now try to get the last possible unidirectional stream. + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedUnidirectionalId(49))); + // and this should fail because it exceeds the unidirectional limit + // (but not the bi-) + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 798 would exceed stream count limit 50", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET + + )) + .Times(1); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedUnidirectionalId(199))); + } } TEST_P(QuicSessionTestServer, ManyAvailableUnidirectionalStreams) { // When max_open_streams_ is 200, should be able to create 200 streams // out-of-order, that is, creating the one with the largest stream ID first. - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); - QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams(&session_, 200); + // Smaller limit on unidirectional streams to help detect crossed wires. + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, 50); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, 200); + } // Create one stream. + QuicStreamId stream_id = GetNthClientInitiatedUnidirectionalId(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); - EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); // Create the largest stream ID of a threatened total of 200 streams. // GetNth... starts at 0, so for 200 streams, get the 199th. + EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( GetNthClientInitiatedUnidirectionalId(199))); + if (transport_version() == QUIC_VERSION_99) { + // If IETF QUIC, check to make sure that creating unidirectional + // streams does not mess up the bidirectional streams. + stream_id = GetNthClientInitiatedBidirectionalId(0); + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream(stream_id)); + // Now try to get the last possible bidirectional stream. + EXPECT_NE(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedBidirectionalId(49))); + // and this should fail because it exceeds the bnidirectional limit + // (but not the uni-) + EXPECT_CALL( + *connection_, + CloseConnection(QUIC_INVALID_STREAM_ID, + "Stream id 800 would exceed stream count limit 51", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET + + )) + .Times(1); + EXPECT_EQ(nullptr, session_.GetOrCreateDynamicStream( + GetNthClientInitiatedBidirectionalId(199))); + } } TEST_P(QuicSessionTestServer, DebugDFatalIfMarkingClosedStreamWriteBlocked) { @@ -1304,7 +1360,7 @@ QuicStreamOffset offset = crypto_stream->stream_bytes_written(); QuicConfig config; CryptoHandshakeMessage crypto_message; - config.ToHandshakeMessage(&crypto_message); + config.ToHandshakeMessage(&crypto_message, transport_version()); crypto_stream->SendHandshakeMessage(crypto_message); char buf[1000]; QuicDataWriter writer(1000, buf, NETWORK_BYTE_ORDER); @@ -1528,7 +1584,12 @@ // with a FIN or RST then we send an RST to refuse streams. For V99 the // connection is closed. const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0); const QuicStreamId kFinalStreamId = GetNthClientInitiatedBidirectionalId(kMaxStreams); @@ -1653,7 +1714,12 @@ } EXPECT_CALL(*connection_, OnStreamReset(_, QUIC_REFUSED_STREAM)).Times(0); const QuicStreamId kMaxStreams = 5; - QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + if (transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams(&session_, + kMaxStreams); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(&session_, kMaxStreams); + } // Create kMaxStreams + 1 data streams, and mark them draining. const QuicStreamId kFirstStreamId = GetNthClientInitiatedBidirectionalId(0);
diff --git a/quic/core/quic_stream_id_manager.cc b/quic/core/quic_stream_id_manager.cc index f68401a..94a8487 100644 --- a/quic/core/quic_stream_id_manager.cc +++ b/quic/core/quic_stream_id_manager.cc
@@ -130,12 +130,13 @@ outgoing_max_streams_ = std::min( static_cast<QuicStreamCount>(max_open_streams), QuicUtils::GetMaxStreamCount(unidirectional_, session_->perspective())); - return true; } void QuicStreamIdManager::SetMaxOpenOutgoingStreams(size_t max_open_streams) { QUIC_BUG_IF(!using_default_max_streams_); + // TODO(fkastenholz): when static streams are removed from I-Quic, this + // should be revised to invoke ConfigureMaxOpen... AdjustMaxOpenOutgoingStreams(max_open_streams); } @@ -143,8 +144,8 @@ // including static streams. If the new stream limit wraps, will peg // the limit at the implementation max. // TODO(fkastenholz): AdjustMax is cognizant of the number of static streams and -// sets the maximum to be max_streams + number_of_statics. This should -// eventually be removed from IETF QUIC. +// sets the maximum to be max_streams + number_of_statics. This should be +// removed from IETF QUIC when static streams are gone. void QuicStreamIdManager::AdjustMaxOpenOutgoingStreams( size_t max_open_streams) { if ((outgoing_static_stream_count_ + max_open_streams) < max_open_streams) {
diff --git a/quic/core/uber_quic_stream_id_manager.cc b/quic/core/uber_quic_stream_id_manager.cc index e2261a0..75f7c6a 100644 --- a/quic/core/uber_quic_stream_id_manager.cc +++ b/quic/core/uber_quic_stream_id_manager.cc
@@ -11,17 +11,19 @@ UberQuicStreamIdManager::UberQuicStreamIdManager( QuicSession* session, - QuicStreamCount max_open_outgoing_streams, - QuicStreamCount max_open_incoming_streams) + QuicStreamCount max_open_outgoing_bidirectional_streams, + QuicStreamCount max_open_outgoing_unidirectional_streams, + QuicStreamCount max_open_incoming_bidirectional_streams, + QuicStreamCount max_open_incoming_unidirectional_streams) : bidirectional_stream_id_manager_(session, /*unidirectional=*/false, - max_open_outgoing_streams, - max_open_incoming_streams), - unidirectional_stream_id_manager_(session, - /*unidirectional=*/true, - max_open_outgoing_streams, - max_open_incoming_streams) {} - + max_open_outgoing_bidirectional_streams, + max_open_incoming_bidirectional_streams), + unidirectional_stream_id_manager_( + session, + /*unidirectional=*/true, + max_open_outgoing_unidirectional_streams, + max_open_incoming_unidirectional_streams) {} void UberQuicStreamIdManager::RegisterStaticStream(QuicStreamId id) { if (QuicUtils::IsBidirectionalStreamId(id)) { bidirectional_stream_id_manager_.RegisterStaticStream(id); @@ -30,35 +32,42 @@ unidirectional_stream_id_manager_.RegisterStaticStream(id); } -void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingStreams( +void UberQuicStreamIdManager::AdjustMaxOpenOutgoingUnidirectionalStreams( size_t max_streams) { - // TODO(fkastenholz): When transport configuration negotiation knows uni- vs - // bi- directionality, this method needs modifying to select the correct - // manager to configure. - bidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams(max_streams); - unidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams( - max_streams); + unidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); +} +void UberQuicStreamIdManager::AdjustMaxOpenOutgoingBidirectionalStreams( + size_t max_streams) { + bidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); } -void UberQuicStreamIdManager::AdjustMaxOpenOutgoingStreams(size_t max_streams) { - // TODO(fkastenholz): When transport configuration negotiation knows uni- vs - // bi- directionality, this method needs modifying to select the correct - // manager to configure. - bidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); - unidirectional_stream_id_manager_.AdjustMaxOpenOutgoingStreams(max_streams); +void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingBidirectionalStreams( + size_t max_streams) { + bidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams(max_streams); +} +void UberQuicStreamIdManager::ConfigureMaxOpenOutgoingUnidirectionalStreams( + size_t max_streams) { + unidirectional_stream_id_manager_.ConfigureMaxOpenOutgoingStreams( + max_streams); } // TODO(fkastenholz): SetMax is cognizant of the number of static streams and // sets the maximum to be max_streams + number_of_statics. This should // eventually be removed from IETF QUIC. -void UberQuicStreamIdManager::SetMaxOpenOutgoingStreams( +void UberQuicStreamIdManager::SetMaxOpenOutgoingBidirectionalStreams( size_t max_open_streams) { bidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_open_streams); +} +void UberQuicStreamIdManager::SetMaxOpenOutgoingUnidirectionalStreams( + size_t max_open_streams) { unidirectional_stream_id_manager_.SetMaxOpenOutgoingStreams(max_open_streams); } -void UberQuicStreamIdManager::SetMaxOpenIncomingStreams( +void UberQuicStreamIdManager::SetMaxOpenIncomingBidirectionalStreams( size_t max_open_streams) { bidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_open_streams); +} +void UberQuicStreamIdManager::SetMaxOpenIncomingUnidirectionalStreams( + size_t max_open_streams) { unidirectional_stream_id_manager_.SetMaxOpenIncomingStreams(max_open_streams); }
diff --git a/quic/core/uber_quic_stream_id_manager.h b/quic/core/uber_quic_stream_id_manager.h index 41fa12b..288f0c0 100644 --- a/quic/core/uber_quic_stream_id_manager.h +++ b/quic/core/uber_quic_stream_id_manager.h
@@ -20,9 +20,12 @@ // unidirectional stream IDs, respectively. class QUIC_EXPORT_PRIVATE UberQuicStreamIdManager { public: - UberQuicStreamIdManager(QuicSession* session, - QuicStreamCount max_open_outgoing_streams, - QuicStreamCount max_open_incoming_streams); + UberQuicStreamIdManager( + QuicSession* session, + QuicStreamCount max_open_outgoing_bidirectional_streams, + QuicStreamCount max_open_outgoing_unidirectional_streams, + QuicStreamCount max_open_incoming_bidirectional_streams, + QuicStreamCount max_open_incoming_unidirectional_streams); // Called when a stream with |stream_id| is registered as a static stream. void RegisterStaticStream(QuicStreamId id); @@ -30,21 +33,26 @@ // Sets the maximum outgoing stream count as a result of doing the transport // configuration negotiation. Forces the limit to max_streams, regardless of // static streams. - void ConfigureMaxOpenOutgoingStreams(size_t max_streams); + void ConfigureMaxOpenOutgoingBidirectionalStreams(size_t max_streams); + void ConfigureMaxOpenOutgoingUnidirectionalStreams(size_t max_streams); // Sets the limits to max_open_streams + number of static streams // in existence. SetMaxOpenOutgoingStreams will QUIC_BUG if it is called - // after getting the first MAX_STREAMS frame. + // after getting the first MAX_STREAMS frame or the transport configuration + // was done. // TODO(fkastenholz): SetMax is cognizant of the number of static streams and // sets the maximum to be max_streams + number_of_statics. This should // eventually be removed from IETF QUIC. - void SetMaxOpenOutgoingStreams(size_t max_open_streams); - void SetMaxOpenIncomingStreams(size_t max_open_streams); + void SetMaxOpenOutgoingBidirectionalStreams(size_t max_open_streams); + void SetMaxOpenOutgoingUnidirectionalStreams(size_t max_open_streams); + void SetMaxOpenIncomingBidirectionalStreams(size_t max_open_streams); + void SetMaxOpenIncomingUnidirectionalStreams(size_t max_open_streams); // Sets the outgoing stream count to the number of static streams + max // outgoing streams. Unlike SetMaxOpenOutgoingStreams, this method will // not QUIC_BUG if called after getting the first MAX_STREAMS frame. - void AdjustMaxOpenOutgoingStreams(size_t max_streams); + void AdjustMaxOpenOutgoingBidirectionalStreams(size_t max_streams); + void AdjustMaxOpenOutgoingUnidirectionalStreams(size_t max_streams); // Returns true if next outgoing bidirectional stream ID can be allocated. bool CanOpenNextOutgoingBidirectionalStream(); @@ -58,7 +66,7 @@ // Returns the next outgoing unidirectional stream id. QuicStreamId GetNextOutgoingUnidirectionalStreamId(); - // Returns true if allow to open the incoming |id|. + // Returns true if the incoming |id| is within the limit. bool MaybeIncreaseLargestPeerStreamId(QuicStreamId id); // Called when |id| is released.
diff --git a/quic/core/uber_quic_stream_id_manager_test.cc b/quic/core/uber_quic_stream_id_manager_test.cc index ed08d8f..b9420bf 100644 --- a/quic/core/uber_quic_stream_id_manager_test.cc +++ b/quic/core/uber_quic_stream_id_manager_test.cc
@@ -60,6 +60,28 @@ kV99StreamIdIncrement * n; } + // TODO(fkastenholz): Existing tests can use these helper functions. + QuicStreamId GetNthPeerInitiatedBidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_SERVER) + ? GetNthClientInitiatedBidirectionalId(n) + : GetNthServerInitiatedBidirectionalId(n)); + } + QuicStreamId GetNthPeerInitiatedUnidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_SERVER) + ? GetNthClientInitiatedUnidirectionalId(n) + : GetNthServerInitiatedUnidirectionalId(n)); + } + QuicStreamId GetNthSelfInitiatedBidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_CLIENT) + ? GetNthClientInitiatedBidirectionalId(n) + : GetNthServerInitiatedBidirectionalId(n)); + } + QuicStreamId GetNthSelfInitiatedUnidirectionalStreamId(int n) { + return ((GetParam() == Perspective::IS_CLIENT) + ? GetNthClientInitiatedUnidirectionalId(n) + : GetNthServerInitiatedUnidirectionalId(n)); + } + QuicStreamId StreamCountToId(QuicStreamCount stream_count, Perspective perspective, bool bidirectional) { @@ -129,17 +151,39 @@ TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreams) { const size_t kNumMaxOutgoingStream = 123; - manager_->SetMaxOpenOutgoingStreams(kNumMaxOutgoingStream); + // Set the uni- and bi- directional limits to different values to ensure + // that they are managed separately. + manager_->SetMaxOpenOutgoingBidirectionalStreams(kNumMaxOutgoingStream); + manager_->SetMaxOpenOutgoingUnidirectionalStreams(kNumMaxOutgoingStream + 1); EXPECT_EQ(kNumMaxOutgoingStream, manager_->max_allowed_outgoing_bidirectional_streams()); - EXPECT_EQ(kNumMaxOutgoingStream, + EXPECT_EQ(kNumMaxOutgoingStream + 1, manager_->max_allowed_outgoing_unidirectional_streams()); + // Check that, for each directionality, we can open the correct number of + // streams. + int i = kNumMaxOutgoingStream; + while (i) { + EXPECT_TRUE(manager_->CanOpenNextOutgoingBidirectionalStream()); + manager_->GetNextOutgoingBidirectionalStreamId(); + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + i--; + } + // One more unidirectional + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + + // Both should be exhausted... + EXPECT_FALSE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); } TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenIncomingStreams) { const size_t kNumMaxIncomingStreams = 456; - manager_->SetMaxOpenIncomingStreams(kNumMaxIncomingStreams); - EXPECT_EQ(kNumMaxIncomingStreams, + manager_->SetMaxOpenIncomingUnidirectionalStreams(kNumMaxIncomingStreams); + // Do +1 for bidirectional to ensure that uni- and bi- get properly set. + manager_->SetMaxOpenIncomingBidirectionalStreams(kNumMaxIncomingStreams + 1); + EXPECT_EQ(kNumMaxIncomingStreams + 1, manager_->GetMaxAllowdIncomingBidirectionalStreams()); EXPECT_EQ(kNumMaxIncomingStreams, manager_->GetMaxAllowdIncomingUnidirectionalStreams()); @@ -147,6 +191,24 @@ manager_->advertised_max_allowed_incoming_bidirectional_streams()); EXPECT_EQ(manager_->actual_max_allowed_incoming_unidirectional_streams(), manager_->advertised_max_allowed_incoming_unidirectional_streams()); + // Make sure that we can create kNumMaxIncomingStreams incoming unidirectional + // streams and kNumMaxIncomingStreams+1 incoming bidirectional streams. + size_t i; + for (i = 0; i < kNumMaxIncomingStreams; i++) { + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedUnidirectionalStreamId(i))); + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i))); + } + // Should be able to open the next bidirectional stream + EXPECT_TRUE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i))); + + // We should have exhausted the counts, the next streams should fail + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedUnidirectionalStreamId(i))); + EXPECT_FALSE(manager_->MaybeIncreaseLargestPeerStreamId( + GetNthPeerInitiatedBidirectionalStreamId(i + 1))); } TEST_P(UberQuicStreamIdManagerTest, GetNextOutgoingStreamId) { @@ -339,6 +401,44 @@ } } +TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreamsPlusFrame) { + const size_t kNumMaxOutgoingStream = 123; + // Set the uni- and bi- directional limits to different values to ensure + // that they are managed separately. + manager_->SetMaxOpenOutgoingBidirectionalStreams(kNumMaxOutgoingStream); + manager_->SetMaxOpenOutgoingUnidirectionalStreams(kNumMaxOutgoingStream + 1); + EXPECT_EQ(kNumMaxOutgoingStream, + manager_->max_allowed_outgoing_bidirectional_streams()); + EXPECT_EQ(kNumMaxOutgoingStream + 1, + manager_->max_allowed_outgoing_unidirectional_streams()); + // Check that, for each directionality, we can open the correct number of + // streams. + int i = kNumMaxOutgoingStream; + while (i) { + EXPECT_TRUE(manager_->CanOpenNextOutgoingBidirectionalStream()); + manager_->GetNextOutgoingBidirectionalStreamId(); + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + i--; + } + // One more unidirectional + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + manager_->GetNextOutgoingUnidirectionalStreamId(); + + // Both should be exhausted... + EXPECT_FALSE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); + + // Now cons a MAX STREAMS frame for unidirectional streams to raise + // the limit. + QuicMaxStreamsFrame frame(1, kNumMaxOutgoingStream + 10, + /*unidirectional=*/true); + manager_->OnMaxStreamsFrame(frame); + // We now should be able to get another uni- stream, but not a bi. + EXPECT_TRUE(manager_->CanOpenNextOutgoingUnidirectionalStream()); + EXPECT_FALSE(manager_->CanOpenNextOutgoingBidirectionalStream()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/quartc/quartc_factory.cc b/quic/quartc/quartc_factory.cc index cb457ff..5b83a46 100644 --- a/quic/quartc/quartc_factory.cc +++ b/quic/quartc/quartc_factory.cc
@@ -190,7 +190,7 @@ // incomplete streams, but targets 1 second for recovery. Increasing the // number of open streams gives sufficient headroom to recover before QUIC // refuses new streams. - quic_config.SetMaxIncomingDynamicStreamsToSend(1000); + quic_config.SetMaxIncomingBidirectionalStreamsToSend(1000); return quic_config; }
diff --git a/quic/test_tools/quic_config_peer.cc b/quic/test_tools/quic_config_peer.cc index f5a5b31..f9ce04f 100644 --- a/quic/test_tools/quic_config_peer.cc +++ b/quic/test_tools/quic_config_peer.cc
@@ -45,10 +45,16 @@ } // static -void QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams( +void QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( QuicConfig* config, uint32_t max_streams) { - config->max_incoming_dynamic_streams_.SetReceivedValue(max_streams); + config->max_incoming_bidirectional_streams_.SetReceivedValue(max_streams); +} +// static +void QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + QuicConfig* config, + uint32_t max_streams) { + config->max_incoming_unidirectional_streams_.SetReceivedValue(max_streams); } // static
diff --git a/quic/test_tools/quic_config_peer.h b/quic/test_tools/quic_config_peer.h index 8869d27..7faee7e 100644 --- a/quic/test_tools/quic_config_peer.h +++ b/quic/test_tools/quic_config_peer.h
@@ -33,8 +33,10 @@ static void SetReceivedDisableConnectionMigration(QuicConfig* config); - static void SetReceivedMaxIncomingDynamicStreams(QuicConfig* config, - uint32_t max_streams); + static void SetReceivedMaxIncomingBidirectionalStreams(QuicConfig* config, + uint32_t max_streams); + static void SetReceivedMaxIncomingUnidirectionalStreams(QuicConfig* config, + uint32_t max_streams); static void SetConnectionOptionsToSend(QuicConfig* config, const QuicTagVector& options);
diff --git a/quic/test_tools/quic_session_peer.cc b/quic/test_tools/quic_session_peer.cc index 176e22a..0683fd7 100644 --- a/quic/test_tools/quic_session_peer.cc +++ b/quic/test_tools/quic_session_peer.cc
@@ -39,23 +39,73 @@ void QuicSessionPeer::SetMaxOpenIncomingStreams(QuicSession* session, uint32_t max_streams) { if (session->connection()->transport_version() == QUIC_VERSION_99) { - session->v99_streamid_manager_.SetMaxOpenIncomingStreams(max_streams); + QUIC_BUG << "SetmaxOpenIncomingStreams deprecated for IETF QUIC/V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + max_streams); + session->v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + max_streams); return; } session->stream_id_manager_.set_max_open_incoming_streams(max_streams); } // static +void QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenIncomingBidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingBidirectionalStreams( + max_streams); +} +// static +void QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenIncomingUnidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenIncomingUnidirectionalStreams( + max_streams); +} + +// static void QuicSessionPeer::SetMaxOpenOutgoingStreams(QuicSession* session, uint32_t max_streams) { if (session->connection()->transport_version() == QUIC_VERSION_99) { - session->v99_streamid_manager_.SetMaxOpenOutgoingStreams(max_streams); + QUIC_BUG << "SetmaxOpenOutgoingStreams deprecated for IETF QUIC/V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingUnidirectionalStreams( + max_streams); + session->v99_streamid_manager_.SetMaxOpenOutgoingBidirectionalStreams( + max_streams); return; } session->stream_id_manager_.set_max_open_outgoing_streams(max_streams); } // static +void QuicSessionPeer::SetMaxOpenOutgoingBidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenOutgoingBidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingBidirectionalStreams( + max_streams); +} +// static +void QuicSessionPeer::SetMaxOpenOutgoingUnidirectionalStreams( + QuicSession* session, + uint32_t max_streams) { + DCHECK_EQ(QUIC_VERSION_99, session->connection()->transport_version()) + << "SetmaxOpenOutgoingUnidirectionalStreams not supported for Google " + "QUIC/not-V99"; + session->v99_streamid_manager_.SetMaxOpenOutgoingUnidirectionalStreams( + max_streams); +} + +// static QuicCryptoStream* QuicSessionPeer::GetMutableCryptoStream( QuicSession* session) { return session->GetMutableCryptoStream();
diff --git a/quic/test_tools/quic_session_peer.h b/quic/test_tools/quic_session_peer.h index 30e358f..994a36c 100644 --- a/quic/test_tools/quic_session_peer.h +++ b/quic/test_tools/quic_session_peer.h
@@ -32,10 +32,24 @@ QuicSession* session); static void SetNextOutgoingBidirectionalStreamId(QuicSession* session, QuicStreamId id); + // Following is only for Google-QUIC, will QUIC_BUG if called for IETF + // QUIC. static void SetMaxOpenIncomingStreams(QuicSession* session, uint32_t max_streams); + // Following two are only for IETF-QUIC, will QUIC_BUG if called for Google + // QUIC. + static void SetMaxOpenIncomingBidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenIncomingUnidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenOutgoingStreams(QuicSession* session, uint32_t max_streams); + static void SetMaxOpenOutgoingBidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static void SetMaxOpenOutgoingUnidirectionalStreams(QuicSession* session, + uint32_t max_streams); + static QuicCryptoStream* GetMutableCryptoStream(QuicSession* session); static QuicWriteBlockedList* GetWriteBlockedStreams(QuicSession* session); static QuicStream* GetOrCreateDynamicStream(QuicSession* session,
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc index d74e0ba..00cd34a 100644 --- a/quic/test_tools/quic_test_utils.cc +++ b/quic/test_tools/quic_test_utils.cc
@@ -1051,7 +1051,7 @@ kInitialStreamFlowControlWindowForTest); config.SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams( + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( &config, kDefaultMaxStreamsPerConnection); // Default enable NSTP. // This is unnecessary for versions > 44
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc index 61d253f..043eae9 100644 --- a/quic/test_tools/simulator/quic_endpoint.cc +++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -113,7 +113,7 @@ CryptoHandshakeMessage peer_hello; peer_hello.SetValue(kICSL, static_cast<uint32_t>(kMaximumIdleTimeoutSecs - 1)); - peer_hello.SetValue(kMIDS, + peer_hello.SetValue(kMIBS, static_cast<uint32_t>(kDefaultMaxStreamsPerConnection)); QuicConfig config; QuicErrorCode error_code = config.ProcessPeerHello(
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc index 330862a..577ff26 100644 --- a/quic/tools/quic_simple_server_session_test.cc +++ b/quic/tools/quic_simple_server_session_test.cc
@@ -200,9 +200,13 @@ TlsServerHandshaker::CreateSslCtx()), compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { - config_.SetMaxIncomingDynamicStreamsToSend(kMaxStreamsForTest); - QuicConfigPeer::SetReceivedMaxIncomingDynamicStreams(&config_, - kMaxStreamsForTest); + config_.SetMaxIncomingBidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingBidirectionalStreams( + &config_, kMaxStreamsForTest); + config_.SetMaxIncomingUnidirectionalStreamsToSend(kMaxStreamsForTest); + QuicConfigPeer::SetReceivedMaxIncomingUnidirectionalStreams( + &config_, kMaxStreamsForTest); + config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); config_.SetInitialSessionFlowControlWindowToSend(
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc index 7572a75..8aaaf6b 100644 --- a/quic/tools/quic_simple_server_stream_test.cc +++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -100,8 +100,15 @@ crypto_config, compressed_certs_cache, quic_simple_server_backend) { - QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest); - QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest); + if (connection->transport_version() == QUIC_VERSION_99) { + QuicSessionPeer::SetMaxOpenIncomingUnidirectionalStreams( + this, kMaxStreamsForTest); + QuicSessionPeer::SetMaxOpenIncomingBidirectionalStreams( + this, kMaxStreamsForTest); + } else { + QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest); + QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest); + } ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(Invoke(MockQuicSession::ConsumeData)); }