gfe-relnote: (n/a) Delete some functions from QuicCryptoServerStream and tests that uses those function. Not protected. The deleted functions are - UseStatelessRejectsIfPeerSupported - PeerSupportsStatelessRejects - SetPeerSupportsStatelessRejects These functions are not needed since cl/246435575. PiperOrigin-RevId: 247938469 Change-Id: I9933906c213dad5e01e365fdd399e85e72c73534
diff --git a/quic/core/quic_crypto_client_stream_test.cc b/quic/core/quic_crypto_client_stream_test.cc index 2d3702f..042d973 100644 --- a/quic/core/quic_crypto_client_stream_test.cc +++ b/quic/core/quic_crypto_client_stream_test.cc
@@ -352,115 +352,6 @@ client_version_label); } -class QuicCryptoClientStreamStatelessTest : public QuicTest { - public: - QuicCryptoClientStreamStatelessTest() - : client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()), - server_crypto_config_(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance(), - crypto_test_utils::ProofSourceForTesting(), - KeyExchangeSource::Default(), - TlsServerHandshaker::CreateSslCtx()), - server_compressed_certs_cache_( - QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), - server_id_(kServerHostname, kServerPort, false) { - TestQuicSpdyClientSession* client_session = nullptr; - CreateClientSessionForTest(server_id_, - /* supports_stateless_rejects= */ true, - QuicTime::Delta::FromSeconds(100000), - AllSupportedVersions(), &helper_, - &alarm_factory_, &client_crypto_config_, - &client_connection_, &client_session); - CHECK(client_session); - client_session_.reset(client_session); - } - - QuicCryptoServerStream* server_stream() { - return server_session_->GetMutableCryptoStream(); - } - - void AdvanceHandshakeWithFakeServer() { - client_session_->GetMutableCryptoStream()->CryptoConnect(); - EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _)) - .Times(testing::AnyNumber()); - EXPECT_CALL(*server_session_->helper(), GenerateConnectionIdForReject(_, _)) - .Times(testing::AnyNumber()); - crypto_test_utils::AdvanceHandshake( - client_connection_, client_session_->GetMutableCryptoStream(), 0, - server_connection_, server_stream(), 0); - } - - // Initializes the server_stream_ for stateless rejects. - void InitializeFakeStatelessRejectServer() { - TestQuicSpdyServerSession* server_session = nullptr; - CreateServerSessionForTest( - server_id_, QuicTime::Delta::FromSeconds(100000), - ParsedVersionOfIndex(AllSupportedVersions(), 0), &helper_, - &alarm_factory_, &server_crypto_config_, - &server_compressed_certs_cache_, &server_connection_, &server_session); - CHECK(server_session); - server_session_.reset(server_session); - server_session_->OnSuccessfulVersionNegotiation(AllSupportedVersions()[0]); - crypto_test_utils::FakeServerOptions options; - crypto_test_utils::SetupCryptoServerConfigForTest( - server_connection_->clock(), server_connection_->random_generator(), - &server_crypto_config_, options); - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - } - - MockQuicConnectionHelper helper_; - MockAlarmFactory alarm_factory_; - - // Client crypto stream state - PacketSavingConnection* client_connection_; - std::unique_ptr<TestQuicSpdyClientSession> client_session_; - QuicCryptoClientConfig client_crypto_config_; - - // Server crypto stream state - PacketSavingConnection* server_connection_; - std::unique_ptr<TestQuicSpdyServerSession> server_session_; - QuicCryptoServerConfig server_crypto_config_; - QuicCompressedCertsCache server_compressed_certs_cache_; - QuicServerId server_id_; -}; - -TEST_F(QuicCryptoClientStreamStatelessTest, StatelessReject) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - EXPECT_CALL(*client_session_, OnProofValid(testing::_)); - - InitializeFakeStatelessRejectServer(); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeServer(); - - EXPECT_EQ(1, server_stream()->NumHandshakeMessages()); - EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces()); - - EXPECT_FALSE(client_session_->IsEncryptionEstablished()); - EXPECT_FALSE(client_session_->IsCryptoHandshakeConfirmed()); - // Even though the handshake was not complete, the cached client_state is - // complete, and can be used for a subsequent successful handshake. - EXPECT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); - - ASSERT_TRUE(client_state->has_server_nonce()); - ASSERT_FALSE(client_state->GetNextServerNonce().empty()); - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - QuicConnectionId server_designated_id = - client_state->GetNextServerDesignatedConnectionId(); - QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_session_->connection()->random_generator()); - EXPECT_EQ(expected_id, server_designated_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); -} - } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc index c0e61ef..9e46d6d 100644 --- a/quic/core/quic_crypto_server_handshaker.cc +++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -138,18 +138,11 @@ QuicReferenceCountedPointer<ValidateClientHelloResultCallback::Result> result, std::unique_ptr<ProofSource::Details> details) { - const CryptoHandshakeMessage& message = result->client_hello; - // Clear the callback that got us here. DCHECK(validate_client_hello_cb_ != nullptr); DCHECK(process_client_hello_cb_ == nullptr); validate_client_hello_cb_ = nullptr; - if (stream_->UseStatelessRejectsIfPeerSupported()) { - stream_->SetPeerSupportsStatelessRejects( - QuicCryptoServerStreamBase::DoesPeerSupportStatelessRejects(message)); - } - std::unique_ptr<ProcessClientHelloCallback> cb( new ProcessClientHelloCallback(this, result)); process_client_hello_cb_ = cb.get(); @@ -177,8 +170,7 @@ if (reply->tag() != kSHLO) { if (reply->tag() == kSREJ) { - DCHECK(stream_->UseStatelessRejectsIfPeerSupported()); - DCHECK(stream_->PeerSupportsStatelessRejects()); + DCHECK(false) << "Unexpected SREJ reply."; // Before sending the SREJ, cause the connection to save crypto packets // so that they can be added to the time wait list manager and // retransmitted. @@ -189,8 +181,7 @@ SendHandshakeMessage(*reply); if (reply->tag() == kSREJ) { - DCHECK(stream_->UseStatelessRejectsIfPeerSupported()); - DCHECK(stream_->PeerSupportsStatelessRejects()); + DCHECK(false) << "Unexpected SREJ reply."; DCHECK(!handshake_confirmed()); QUIC_DLOG(INFO) << "Closing connection " << session()->connection()->connection_id() @@ -431,16 +422,13 @@ } previous_source_address_tokens_ = result->info.source_address_tokens; - const bool use_stateless_rejects_in_crypto_config = - stream_->UseStatelessRejectsIfPeerSupported() && - stream_->PeerSupportsStatelessRejects(); QuicConnection* connection = session()->connection(); const QuicConnectionId server_designated_connection_id = - GenerateConnectionIdForReject(use_stateless_rejects_in_crypto_config); + GenerateConnectionIdForReject(/*use_stateless_rejects=*/false); crypto_config_->ProcessClientHello( result, /*reject_only=*/false, connection->connection_id(), connection->self_address(), GetClientAddress(), connection->version(), - session()->supported_versions(), use_stateless_rejects_in_crypto_config, + session()->supported_versions(), /*use_stateless_rejects=*/false, server_designated_connection_id, connection->clock(), connection->random_generator(), compressed_certs_cache_, crypto_negotiated_params_, signed_config_,
diff --git a/quic/core/quic_crypto_server_stream.cc b/quic/core/quic_crypto_server_stream.cc index 010ac36..3375e46 100644 --- a/quic/core/quic_crypto_server_stream.cc +++ b/quic/core/quic_crypto_server_stream.cc
@@ -97,23 +97,10 @@ return handshaker()->PreviousCachedNetworkParams(); } -bool QuicCryptoServerStream::UseStatelessRejectsIfPeerSupported() const { - return use_stateless_rejects_if_peer_supported_; -} - -bool QuicCryptoServerStream::PeerSupportsStatelessRejects() const { - return peer_supports_stateless_rejects_; -} - bool QuicCryptoServerStream::ZeroRttAttempted() const { return handshaker()->ZeroRttAttempted(); } -void QuicCryptoServerStream::SetPeerSupportsStatelessRejects( - bool peer_supports_stateless_rejects) { - peer_supports_stateless_rejects_ = peer_supports_stateless_rejects; -} - void QuicCryptoServerStream::SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) { handshaker()->SetPreviousCachedNetworkParams(cached_network_params);
diff --git a/quic/core/quic_crypto_server_stream.h b/quic/core/quic_crypto_server_stream.h index a003027..a31f133 100644 --- a/quic/core/quic_crypto_server_stream.h +++ b/quic/core/quic_crypto_server_stream.h
@@ -51,10 +51,7 @@ // These are all accessors and setters to their respective counters. virtual uint8_t NumHandshakeMessages() const = 0; virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0; - virtual bool UseStatelessRejectsIfPeerSupported() const = 0; - virtual bool PeerSupportsStatelessRejects() const = 0; virtual bool ZeroRttAttempted() const = 0; - virtual void SetPeerSupportsStatelessRejects(bool set) = 0; virtual const CachedNetworkParameters* PreviousCachedNetworkParams() const = 0; virtual void SetPreviousCachedNetworkParams( @@ -171,11 +168,7 @@ uint8_t NumHandshakeMessagesWithServerNonces() const override; int NumServerConfigUpdateMessagesSent() const override; const CachedNetworkParameters* PreviousCachedNetworkParams() const override; - bool UseStatelessRejectsIfPeerSupported() const override; - bool PeerSupportsStatelessRejects() const override; bool ZeroRttAttempted() const override; - void SetPeerSupportsStatelessRejects( - bool peer_supports_stateless_rejects) override; void SetPreviousCachedNetworkParams( CachedNetworkParameters cached_network_params) override;
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc index ff7111c..30f954d 100644 --- a/quic/core/quic_crypto_server_stream_test.cc +++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -45,14 +45,6 @@ namespace quic { namespace test { -class QuicCryptoServerStreamPeer { - public: - static bool DoesPeerSupportStatelessRejects( - const CryptoHandshakeMessage& message) { - return QuicCryptoServerStream::DoesPeerSupportStatelessRejects(message); - } -}; - namespace { const char kServerHostname[] = "test.example.com"; @@ -74,9 +66,7 @@ QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, false), client_crypto_config_(crypto_test_utils::ProofVerifierForTesting(), - TlsClientHandshaker::CreateSslCtx()) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, false); - } + TlsClientHandshaker::CreateSslCtx()) {} void Initialize() { InitializeServer(); } @@ -197,12 +187,6 @@ EXPECT_FALSE(server_stream()->handshake_confirmed()); } -TEST_P(QuicCryptoServerStreamTest, NotInitiallySendingStatelessRejects) { - Initialize(); - EXPECT_FALSE(server_stream()->UseStatelessRejectsIfPeerSupported()); - EXPECT_FALSE(server_stream()->PeerSupportsStatelessRejects()); -} - TEST_P(QuicCryptoServerStreamTest, ConnectedAfterCHLO) { // CompleteCryptoHandshake returns the number of client hellos sent. This // test should send: @@ -251,109 +235,6 @@ server_session_->connection()->encryption_level()); } -TEST_P(QuicCryptoServerStreamTest, StatelessRejectAfterCHLO) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeClient(); - - // Check the server to make the sure the handshake did not succeed. - EXPECT_FALSE(server_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->handshake_confirmed()); - - // Check the client state to make sure that it received a server-designated - // connection id. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_TRUE(client_state->has_server_nonce()); - ASSERT_FALSE(client_state->GetNextServerNonce().empty()); - ASSERT_FALSE(client_state->has_server_nonce()); - - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - const QuicConnectionId server_designated_connection_id = - client_state->GetNextServerDesignatedConnectionId(); - const QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_connection_->random_generator()); - EXPECT_EQ(expected_id, server_designated_connection_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); -} - -TEST_P(QuicCryptoServerStreamTest, ConnectedAfterStatelessHandshake) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - EXPECT_CALL(*client_connection_, - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - AdvanceHandshakeWithFakeClient(); - - // On the first round, encryption will not be established. - EXPECT_FALSE(server_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->handshake_confirmed()); - EXPECT_EQ(1, server_stream()->NumHandshakeMessages()); - EXPECT_EQ(0, server_stream()->NumHandshakeMessagesWithServerNonces()); - - // Now check the client state. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_TRUE(client_state->has_server_designated_connection_id()); - const QuicConnectionId server_designated_connection_id = - client_state->GetNextServerDesignatedConnectionId(); - const QuicConnectionId expected_id = QuicUtils::CreateRandomConnectionId( - server_connection_->random_generator()); - EXPECT_EQ(expected_id, server_designated_connection_id); - EXPECT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); - - // Now create new client and server streams with the existing config - // and try the handshake again (0-RTT handshake). - InitializeServer(); - - InitializeFakeClient(/* supports_stateless_rejects= */ true); - // In the stateless case, the second handshake contains a server-nonce, so the - // AsyncStrikeRegisterVerification() case will still succeed (unlike a 0-RTT - // handshake). - AdvanceHandshakeWithFakeClient(); - - // On the second round, encryption will be established. - EXPECT_TRUE(server_stream()->encryption_established()); - EXPECT_TRUE(server_stream()->handshake_confirmed()); - EXPECT_EQ(1, server_stream()->NumHandshakeMessages()); - EXPECT_EQ(1, server_stream()->NumHandshakeMessagesWithServerNonces()); -} - -TEST_P(QuicCryptoServerStreamTest, NoStatelessRejectIfNoClientSupport) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - Initialize(); - - // The server is configured to use stateless rejects, but the client does not - // support it. - InitializeFakeClient(/* supports_stateless_rejects= */ false); - AdvanceHandshakeWithFakeClient(); - - // Check the server to make the sure the handshake did not succeed. - EXPECT_FALSE(server_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->handshake_confirmed()); - - // Check the client state to make sure that it did not receive a - // server-designated connection id. - QuicCryptoClientConfig::CachedState* client_state = - client_crypto_config_.LookupOrCreate(server_id_); - - ASSERT_FALSE(client_state->has_server_designated_connection_id()); - ASSERT_TRUE(client_state->IsComplete(QuicWallTime::FromUNIXSeconds(0))); -} - TEST_P(QuicCryptoServerStreamTest, ZeroRTT) { Initialize(); InitializeFakeClient(/* supports_stateless_rejects= */ false); @@ -450,21 +331,6 @@ EXPECT_EQ(1, client_stream()->num_scup_messages_received()); } -TEST_P(QuicCryptoServerStreamTest, DoesPeerSupportStatelessRejects) { - Initialize(); - - QuicConfig stateless_reject_config = DefaultQuicConfigStatelessRejects(); - stateless_reject_config.ToHandshakeMessage(&message_); - EXPECT_TRUE( - QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); - - message_.Clear(); - QuicConfig stateful_reject_config = DefaultQuicConfig(); - stateful_reject_config.ToHandshakeMessage(&message_); - EXPECT_FALSE( - QuicCryptoServerStreamPeer::DoesPeerSupportStatelessRejects(message_)); -} - class QuicCryptoServerStreamTestWithFailingProofSource : public QuicCryptoServerStreamTest { public:
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index 16d2584..9c7cd1e 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -1071,262 +1071,6 @@ bool handshake_confirmed_; }; -struct StatelessRejectTestParams { - StatelessRejectTestParams(bool enable_stateless_rejects_via_flag, - bool client_supports_statelesss_rejects, - bool crypto_handshake_successful) - : enable_stateless_rejects_via_flag(enable_stateless_rejects_via_flag), - client_supports_statelesss_rejects(client_supports_statelesss_rejects), - crypto_handshake_successful(crypto_handshake_successful) {} - - friend std::ostream& operator<<(std::ostream& os, - const StatelessRejectTestParams& p) { - os << "{ enable_stateless_rejects_via_flag: " - << p.enable_stateless_rejects_via_flag << std::endl; - os << " client_supports_statelesss_rejects: " - << p.client_supports_statelesss_rejects << std::endl; - os << " crypto_handshake_successful: " << p.crypto_handshake_successful - << " }"; - return os; - } - - // This only enables the stateless reject feature via the feature-flag. - // This should be a no-op if the peer does not support them. - bool enable_stateless_rejects_via_flag; - // Whether or not the client supports stateless rejects. - bool client_supports_statelesss_rejects; - // Should the initial crypto handshake succeed or not. - bool crypto_handshake_successful; -}; - -// Constructs various test permutations for stateless rejects. -std::vector<StatelessRejectTestParams> GetStatelessRejectTestParams() { - std::vector<StatelessRejectTestParams> params; - for (bool enable_stateless_rejects_via_flag : {true, false}) { - for (bool client_supports_statelesss_rejects : {true, false}) { - for (bool crypto_handshake_successful : {true, false}) { - params.push_back(StatelessRejectTestParams( - enable_stateless_rejects_via_flag, - client_supports_statelesss_rejects, crypto_handshake_successful)); - } - } - } - return params; -} - -class QuicDispatcherStatelessRejectTest - : public QuicDispatcherTest, - public testing::WithParamInterface<StatelessRejectTestParams> { - public: - QuicDispatcherStatelessRejectTest() - : QuicDispatcherTest(), crypto_stream1_(nullptr) {} - - ~QuicDispatcherStatelessRejectTest() override { - if (crypto_stream1_) { - delete crypto_stream1_; - } - } - - // This test setup assumes that all testing will be done using - // crypto_stream1_. - void SetUp() override { - QuicDispatcherTest::SetUp(); - SetQuicReloadableFlag(enable_quic_stateless_reject_support, - GetParam().enable_stateless_rejects_via_flag); - } - - // Returns true or false, depending on whether the server will emit - // a stateless reject, depending upon the parameters of the test. - bool ExpectStatelessReject() { - return GetParam().enable_stateless_rejects_via_flag && - !GetParam().crypto_handshake_successful && - GetParam().client_supports_statelesss_rejects; - } - - // Sets up dispatcher_, session1_, and crypto_stream1_ based on - // the test parameters. - QuicServerSessionBase* CreateSessionBasedOnTestParams( - QuicConnectionId connection_id, - const QuicSocketAddress& client_address) { - CreateSession(dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_); - - crypto_stream1_ = new MockQuicCryptoServerStream( - crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - session1_, session1_->stream_helper()); - session1_->SetCryptoStream(crypto_stream1_); - crypto_stream1_->set_handshake_confirmed_for_testing( - GetParam().crypto_handshake_successful); - crypto_stream1_->SetPeerSupportsStatelessRejects( - GetParam().client_supports_statelesss_rejects); - return session1_; - } - - MockQuicCryptoServerStream* crypto_stream1_; -}; - -// Parameterized test for stateless rejects. Should test all -// combinations of enabling/disabling, reject/no-reject for stateless -// rejects. -INSTANTIATE_TEST_SUITE_P(QuicDispatcherStatelessRejectTests, - QuicDispatcherStatelessRejectTest, - ::testing::ValuesIn(GetStatelessRejectTestParams())); - -TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) { - CreateTimeWaitListManager(); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - QuicConnectionId connection_id = TestConnectionId(1); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - - // Process the first packet for the connection. - ProcessPacket(client_address, connection_id, true, SerializeCHLO()); - if (ExpectStatelessReject()) { - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - CloseConnection(QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, _, _)); - // If this is a stateless reject, the crypto stream will close the - // connection. - session1_->connection()->CloseConnection( - QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT, "stateless reject", - ConnectionCloseBehavior::SILENT_CLOSE); - } - - // Send a second packet and check the results. If this is a stateless reject, - // the existing connection_id will go on the time-wait list. - EXPECT_EQ(ExpectStatelessReject(), - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); - if (ExpectStatelessReject()) { - // The second packet will be processed on the time-wait list. - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(1); - } else { - // The second packet will trigger a packet-validation - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .Times(1) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - } - ProcessPacket(client_address, connection_id, true, "data"); -} - -TEST_P(QuicDispatcherStatelessRejectTest, CheapRejects) { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - CreateTimeWaitListManager(); - - QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - QuicConnectionId connection_id = TestConnectionId(1); - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_CALL(*dispatcher_, - CreateQuicSession(connection_id, client_address, _, _)) - .Times(0); - } else { - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("h2"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - } - - QUIC_LOG(INFO) << "ExpectStatelessReject: " << ExpectStatelessReject(); - QUIC_LOG(INFO) << "Params: " << GetParam(); - // Process the first packet for the connection. - CryptoHandshakeMessage client_hello = - crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"COPT", "SREJ"}, - {"NONC", "1234567890123456789012"}, - {"ALPN", "h2"}, - {"VER\0", "Q025"}}, - kClientHelloMinimumSize); - - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, _, connection_id, _, _)) - .Times(1); - } else { - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - } - ProcessPacket(client_address, connection_id, true, - std::string(client_hello.GetSerialized().AsStringPiece())); - - if (GetParam().enable_stateless_rejects_via_flag) { - EXPECT_EQ(true, - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); - } -} - -TEST_P(QuicDispatcherStatelessRejectTest, BufferNonChlo) { - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - CreateTimeWaitListManager(); - - const QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - const QuicConnectionId connection_id = TestConnectionId(1); - - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)) - .Times(1); - ProcessPacket(client_address, connection_id, true, "NOT DATA FOR A CHLO"); - - // Process the first packet for the connection. - CryptoHandshakeMessage client_hello = - crypto_test_utils::CreateCHLO({{"AEAD", "AESG"}, - {"KEXS", "C255"}, - {"NONC", "1234567890123456789012"}, - {"ALPN", "h3"}, - {"VER\0", "Q025"}}, - kClientHelloMinimumSize); - - // If stateless rejects are enabled then a connection will be created now - // and the buffered packet will be processed - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("h3"), _)) - .WillOnce(testing::Return( - CreateSessionBasedOnTestParams(connection_id, client_address))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, client_address, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - // Expect both packets to be passed to ProcessUdpPacket(). And one of them - // is already expected in CreateSessionBasedOnTestParams(). - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, client_address, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))) - .RetiresOnSaturation(); - ProcessPacket(client_address, connection_id, true, - std::string(client_hello.GetSerialized().AsStringPiece())); - EXPECT_FALSE( - time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id)); -} - // Verify the stopgap test: Packets with truncated connection IDs should be // dropped. class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {}; @@ -2190,666 +1934,6 @@ dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate); } -// Test which exercises the async GetProof codepaths, especially in the context -// of stateless rejection. -class AsyncGetProofTest : public QuicDispatcherTest { - public: - AsyncGetProofTest() - : QuicDispatcherTest( - std::unique_ptr<FakeProofSource>(new FakeProofSource())), - client_addr_(QuicIpAddress::Loopback4(), 1234), - client_addr_2_(QuicIpAddress::Loopback4(), 1357), - crypto_config_peer_(&crypto_config_), - server_addr_(QuicIpAddress::Any4(), 5), - signed_config_(new QuicSignedServerConfig) { - SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); - SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); - } - - void SetUp() override { - QuicDispatcherTest::SetUp(); - - clock_ = QuicDispatcherPeer::GetHelper(dispatcher_.get())->GetClock(); - QuicTransportVersion version = AllSupportedTransportVersions().front(); - chlo_ = crypto_test_utils::GenerateDefaultInchoateCHLO(clock_, version, - &crypto_config_); - chlo_.SetVector(kCOPT, QuicTagVector{kSREJ}); - chlo_.SetStringPiece(kALPN, "HTTP/1"); - // Pass an inchoate CHLO. - crypto_test_utils::GenerateFullCHLO( - chlo_, &crypto_config_, server_addr_, client_addr_, version, clock_, - signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - &full_chlo_); - - crypto_test_utils::GenerateFullCHLO( - chlo_, &crypto_config_, server_addr_, client_addr_2_, version, clock_, - signed_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - &full_chlo_2_); - - GetFakeProofSource()->Activate(); - } - - FakeProofSource* GetFakeProofSource() const { - return static_cast<FakeProofSource*>(crypto_config_peer_.GetProofSource()); - } - - std::string SerializeFullCHLO() { - return std::string(full_chlo_.GetSerialized().AsStringPiece()); - } - - std::string SerializeFullCHLOForClient2() { - return std::string(full_chlo_2_.GetSerialized().AsStringPiece()); - } - - std::string SerializeCHLO() { - return std::string(chlo_.GetSerialized().AsStringPiece()); - } - - // Sets up a session, and crypto stream based on the test parameters. - QuicServerSessionBase* GetSession(QuicConnectionId connection_id, - QuicSocketAddress client_address) { - auto it = sessions_.find(connection_id); - if (it != sessions_.end()) { - return it->second.session; - } - - TestQuicSpdyServerSession* session; - CreateSession(dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session); - - std::unique_ptr<MockQuicCryptoServerStream> crypto_stream( - new MockQuicCryptoServerStream( - crypto_config_, QuicDispatcherPeer::GetCache(dispatcher_.get()), - session, session->stream_helper())); - session->SetCryptoStream(crypto_stream.get()); - crypto_stream->SetPeerSupportsStatelessRejects(true); - const bool ok = - sessions_ - .insert(std::make_pair( - connection_id, SessionInfo{session, std::move(crypto_stream)})) - .second; - CHECK(ok); - return session; - } - - protected: - const QuicSocketAddress client_addr_; - const QuicSocketAddress client_addr_2_; - CryptoHandshakeMessage chlo_; - - private: - QuicCryptoServerConfigPeer crypto_config_peer_; - QuicSocketAddress server_addr_; - QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config_; - const QuicClock* clock_; - CryptoHandshakeMessage full_chlo_; // CHLO for client_addr_ - CryptoHandshakeMessage full_chlo_2_; // CHLO for client_addr_2_ - - struct SessionInfo { - TestQuicSpdyServerSession* session; - std::unique_ptr<MockQuicCryptoServerStream> crypto_stream; - }; - std::map<QuicConnectionId, SessionInfo> sessions_; -}; - -// Test a simple situation of connections which the StatelessRejector will -// accept. -TEST_F(AsyncGetProofTest, BasicAccept) { - QuicConnectionId conn_id = TestConnectionId(1); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - check.Call(1); - // Complete the ProofSource::GetProof call and verify that a session is - // created. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - - check.Call(2); - // Verify that a data packet gets processed immediately. - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); -} - -TEST_F(AsyncGetProofTest, RestorePacketContext) { - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_1, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillRepeatedly(WithArg<2>( - Invoke([this, conn_id_1](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_1, packet); - }))); - - EXPECT_CALL(check, Call(2)); - - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_2, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_2_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_2_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_2_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - dispatcher_->custom_packet_context_ = "connection 1"; - ProcessPacket(client_addr_, conn_id_1, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will accept. - dispatcher_->custom_packet_context_ = "connection 2"; - ProcessPacket(client_addr_2_, conn_id_2, true, SerializeFullCHLOForClient2()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the first ProofSource::GetProof call and verify that a session is - // created. - check.Call(1); - - EXPECT_EQ(client_addr_2_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_2_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 2", dispatcher_->custom_packet_context_); - - // Runs the async proof callback for conn_id_1 from client_addr_. - GetFakeProofSource()->InvokePendingCallback(0); - - EXPECT_EQ(client_addr_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 1", dispatcher_->custom_packet_context_); - - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the second ProofSource::GetProof call and verify that a session is - // created. - check.Call(2); - - EXPECT_EQ(client_addr_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 1", dispatcher_->custom_packet_context_); - - // Runs the async proof callback for conn_id_2 from client_addr_2_. - GetFakeProofSource()->InvokePendingCallback(0); - - EXPECT_EQ(client_addr_2_, dispatcher_->current_client_address()); - EXPECT_EQ(client_addr_2_, dispatcher_->current_peer_address()); - EXPECT_EQ("connection 2", dispatcher_->custom_packet_context_); - - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - -// Test a simple situation of connections which the StatelessRejector will -// reject. -TEST_F(AsyncGetProofTest, BasicReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id = TestConnectionId(1); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("hq"), _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the ProofSource::GetProof call and verify that the connection and - // packet are processed by the time wait list manager. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - - // Verify that a data packet is passed to the time wait list manager. - check.Call(2); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); -} - -// Test a situation with multiple interleaved connections which the -// StatelessRejector will accept. -TEST_F(AsyncGetProofTest, MultipleAccept) { - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_2, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_2, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id_2](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_2, packet); - }))); - - EXPECT_CALL(check, Call(3)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(4)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id_1, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillRepeatedly(WithArg<2>( - Invoke([this, conn_id_1](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id_1, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id_1, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id_2, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the second ProofSource::GetProof call and verify that a session is - // created. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Verify that a data packet on that connection gets processed immediately. - check.Call(2); - ProcessPacket(client_addr_, conn_id_2, true, "My name is Data"); - - // Verify that a data packet on the other connection does not get processed - // yet. - check.Call(3); - ProcessPacket(client_addr_, conn_id_1, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); - - // Complete the first ProofSource::GetProof call and verify that a session is - // created and the buffered packet is processed. - check.Call(4); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - -// Test a situation with multiple interleaved connections which the -// StatelessRejector will reject. -TEST_F(AsyncGetProofTest, MultipleReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicConnectionId conn_id_2 = TestConnectionId(2); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, _, _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_2, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_2, _, _)); - - EXPECT_CALL(check, Call(3)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(4)); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_1, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Send another CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_2, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the second ProofSource::GetProof call and verify that the - // connection and packet are processed by the time wait manager. - check.Call(1); - GetFakeProofSource()->InvokePendingCallback(1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Verify that a data packet on that connection gets processed immediately by - // the time wait manager. - check.Call(2); - ProcessPacket(client_addr_, conn_id_2, true, "My name is Data"); - - // Verify that a data packet on the first connection gets buffered. - check.Call(3); - ProcessPacket(client_addr_, conn_id_1, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); - - // Complete the first ProofSource::GetProof call and verify that the CHLO is - // processed by the time wait manager and the remaining packets are discarded. - check.Call(4); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_2)); -} - -// Test a situation with multiple identical CHLOs which the StatelessRejector -// will reject. -TEST_F(AsyncGetProofTest, MultipleIdenticalReject) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id_1 = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id_1, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_, - QuicStringPiece(), _)) - .Times(0); - EXPECT_CALL(*time_wait_list_manager_, - AddConnectionIdToTimeWait(conn_id_1, _, _, _, _)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id_1, _, _)); - } - - // Send a CHLO that the StatelessRejector will reject. - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); - - // Send an identical CHLO which should get buffered. - check.Call(1); - ProcessPacket(client_addr_, conn_id_1, true, SerializeCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_TRUE(store->HasBufferedPackets(conn_id_1)); - - // Complete the ProofSource::GetProof call and verify that the CHLO is - // rejected and the copy is discarded. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id_1)); -} - -// Test dispatcher behavior when packets time out of the buffer while CHLO -// validation is still pending. -TEST_F(AsyncGetProofTest, BufferTimeout) { - CreateTimeWaitListManager(); - - QuicConnectionId conn_id = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*time_wait_list_manager_, - ProcessPacket(_, client_addr_, conn_id, _, _)); - EXPECT_CALL(*dispatcher_, - CreateQuicSession(conn_id, client_addr_, QuicStringPiece(), _)) - .Times(0); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - - // Send a data packet that will get buffered - check.Call(1); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id)); - - // Pretend that enough time has gone by for the packets to get expired out of - // the buffer - mock_helper_.AdvanceTime( - QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)); - QuicBufferedPacketStorePeer::expiration_alarm(store)->Cancel(); - store->OnExpirationTimeout(); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Now allow the CHLO validation to complete, and verify that no connection - // gets created. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); -} - -// Test behavior when packets time out of the buffer *and* the connection times -// out of the time wait manager while CHLO validation is still pending. This -// *should* be impossible, but anything can happen with timing conditions. -TEST_F(AsyncGetProofTest, TimeWaitTimeout) { - QuicConnectionId conn_id = TestConnectionId(1); - QuicBufferedPacketStore* store = - QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get()); - QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); - CreateTimeWaitListManager(); - QuicTimeWaitListManagerPeer::set_clock(time_wait_list_manager_, - mock_helper_.GetClock()); - - testing::MockFunction<void(int check_point)> check; - { - InSequence s; - EXPECT_CALL(check, Call(1)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - - EXPECT_CALL(check, Call(2)); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(conn_id, _)); - EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_, - QuicStringPiece("HTTP/1"), _)) - .WillOnce(testing::Return(GetSession(conn_id, client_addr_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>( - GetSession(conn_id, client_addr_)->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, conn_id](const QuicEncryptedPacket& packet) { - ValidatePacket(conn_id, packet); - }))); - } - - // Send a CHLO that the StatelessRejector will accept. - ProcessPacket(client_addr_, conn_id, true, SerializeFullCHLO()); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - - // Send a data packet that will get buffered - check.Call(1); - ProcessPacket(client_addr_, conn_id, true, "My name is Data"); - EXPECT_TRUE(store->HasBufferedPackets(conn_id)); - - // Pretend that enough time has gone by for the packets to get expired out of - // the buffer - mock_helper_.AdvanceTime( - QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs)); - QuicBufferedPacketStorePeer::expiration_alarm(store)->Cancel(); - store->OnExpirationTimeout(); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_TRUE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Pretend that enough time has gone by for the connection ID to be removed - // from the time wait manager - mock_helper_.AdvanceTime( - QuicTimeWaitListManagerPeer::time_wait_period(time_wait_list_manager_)); - QuicTimeWaitListManagerPeer::expiration_alarm(time_wait_list_manager_) - ->Cancel(); - time_wait_list_manager_->CleanUpOldConnectionIds(); - EXPECT_FALSE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); - - // Now allow the CHLO validation to complete. Expect that a connection is - // indeed created, since QUIC has forgotten that this connection ever existed. - // This is a miniscule corner case which should never happen in the wild, so - // really we are just verifying that the dispatcher does not explode in this - // situation. - check.Call(2); - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); - EXPECT_FALSE(store->HasBufferedPackets(conn_id)); - EXPECT_FALSE(time_wait_list_manager_->IsConnectionIdInTimeWait(conn_id)); -} - -// Regression test for -// https://bugs.chromium.org/p/chromium/issues/detail?id=748289 -TEST_F(AsyncGetProofTest, DispatcherFailedToPickUpVersionForAsyncProof) { - // This test mimics the scenario that dispatcher's framer can have different - // version when async proof returns. - // When dispatcher sends SREJ, the SREJ frame can be serialized in - // different endianness which causes the client to close the connection - // because of QUIC_INVALID_STREAM_DATA. - - SetQuicReloadableFlag(quic_disable_version_39, false); - ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); - chlo_.SetVersion(kVER, chlo_version); - // Send a CHLO with v43. Dispatcher framer's version is set to v43. - ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Send another CHLO with v39. Dispatcher framer's version is set to v39. - chlo_version.transport_version = QUIC_VERSION_39; - chlo_.SetVersion(kVER, chlo_version); - // Invalidate the cached serialized form. - chlo_.MarkDirty(); - ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the ProofSource::GetProof call for v43. This would cause the - // version mismatch between the CHLO packet and the dispatcher. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); -} - -// Regression test for b/116200989. -TEST_F(AsyncGetProofTest, DispatcherHasWrongLastPacketIsIetfQuic) { - // Process a packet of v44. - ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44); - chlo_.SetVersion(kVER, chlo_version); - ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Process another packet of v43. - chlo_version.transport_version = QUIC_VERSION_43; - chlo_.SetVersion(kVER, chlo_version); - // Invalidate the cached serialized form. - chlo_.MarkDirty(); - ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version, - SerializeCHLO(), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, 1); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - - // Complete the ProofSource::GetProof call for v44. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); - - // Complete the ProofSource::GetProof call for v43. - GetFakeProofSource()->InvokePendingCallback(0); - ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); -} - } // namespace } // namespace test } // namespace quic