diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc')
-rw-r--r-- | chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc | 330 |
1 files changed, 284 insertions, 46 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 9f692a8029a..3f2f8cc2bb3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" +#include "quic/core/quic_dispatcher.h" #include <memory> #include <ostream> @@ -10,35 +10,38 @@ #include <utility> #include "absl/base/macros.h" -#include "net/third_party/quiche/src/quic/core/chlo_extractor.h" -#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" -#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" -#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" -#include "net/third_party/quiche/src/quic/core/quic_config.h" -#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" -#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h" -#include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" -#include "net/third_party/quiche/src/quic/core/quic_time_wait_list_manager.h" -#include "net/third_party/quiche/src/quic/core/quic_types.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" -#include "net/third_party/quiche/src/quic/test_tools/first_flight.h" -#include "net/third_party/quiche/src/quic/test_tools/mock_quic_time_wait_list_manager.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_buffered_packet_store_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_crypto_server_config_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_dispatcher_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_time_wait_list_manager_peer.h" -#include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" -#include "net/third_party/quiche/src/common/test_tools/quiche_test_utils.h" +#include "absl/strings/str_cat.h" +#include "quic/core/chlo_extractor.h" +#include "quic/core/crypto/crypto_handshake.h" +#include "quic/core/crypto/crypto_protocol.h" +#include "quic/core/crypto/quic_crypto_server_config.h" +#include "quic/core/crypto/quic_random.h" +#include "quic/core/frames/quic_new_connection_id_frame.h" +#include "quic/core/quic_config.h" +#include "quic/core/quic_connection.h" +#include "quic/core/quic_connection_id.h" +#include "quic/core/quic_crypto_stream.h" +#include "quic/core/quic_packet_writer_wrapper.h" +#include "quic/core/quic_time_wait_list_manager.h" +#include "quic/core/quic_types.h" +#include "quic/core/quic_utils.h" +#include "quic/core/quic_versions.h" +#include "quic/platform/api/quic_expect_bug.h" +#include "quic/platform/api/quic_flags.h" +#include "quic/platform/api/quic_logging.h" +#include "quic/platform/api/quic_test.h" +#include "quic/test_tools/crypto_test_utils.h" +#include "quic/test_tools/fake_proof_source.h" +#include "quic/test_tools/first_flight.h" +#include "quic/test_tools/mock_quic_time_wait_list_manager.h" +#include "quic/test_tools/quic_buffered_packet_store_peer.h" +#include "quic/test_tools/quic_connection_peer.h" +#include "quic/test_tools/quic_crypto_server_config_peer.h" +#include "quic/test_tools/quic_dispatcher_peer.h" +#include "quic/test_tools/quic_test_utils.h" +#include "quic/test_tools/quic_time_wait_list_manager_peer.h" +#include "quic/tools/quic_simple_crypto_server_stream_helper.h" +#include "common/test_tools/quiche_test_utils.h" using testing::_; using testing::ByMove; @@ -183,7 +186,26 @@ class MockServerConnection : public MockQuicConnection { helper, alarm_factory, Perspective::IS_SERVER), - dispatcher_(dispatcher) {} + dispatcher_(dispatcher), + active_connection_ids_({connection_id}) {} + + void AddNewConnectionId(QuicConnectionId id) { + dispatcher_->OnNewConnectionIdSent(active_connection_ids_.back(), id); + QuicConnectionPeer::SetServerConnectionId(this, id); + active_connection_ids_.push_back(id); + } + + void RetireConnectionId(QuicConnectionId id) { + auto it = std::find(active_connection_ids_.begin(), + active_connection_ids_.end(), id); + QUICHE_DCHECK(it != active_connection_ids_.end()); + dispatcher_->OnConnectionIdRetired(id); + active_connection_ids_.erase(it); + } + + std::vector<QuicConnectionId> GetActiveServerConnectionIds() const override { + return active_connection_ids_; + } void UnregisterOnConnectionClosed() { QUIC_LOG(ERROR) << "Unregistering " << connection_id(); @@ -194,6 +216,7 @@ class MockServerConnection : public MockQuicConnection { private: QuicDispatcher* dispatcher_; + std::vector<QuicConnectionId> active_connection_ids_; }; class QuicDispatcherTestBase : public QuicTestWithParam<ParsedQuicVersion> { @@ -557,7 +580,7 @@ void QuicDispatcherTestBase::TestTlsMultiPacketClientHello( ProcessReceivedPacket(std::move(packets[0]), client_address, version_, server_connection_id); - EXPECT_EQ(dispatcher_->session_map().size(), 0u) + EXPECT_EQ(dispatcher_->NumSessions(), 0u) << "No session should be created before the rest of the CHLO arrives."; // Processing the second packet should create the new session. @@ -574,7 +597,7 @@ void QuicDispatcherTestBase::TestTlsMultiPacketClientHello( ProcessReceivedPacket(std::move(packets[1]), client_address, version_, server_connection_id); - EXPECT_EQ(dispatcher_->session_map().size(), 1u); + EXPECT_EQ(dispatcher_->NumSessions(), 1u); } TEST_P(QuicDispatcherTestAllVersions, TlsMultiPacketClientHello) { @@ -641,7 +664,7 @@ TEST_P(QuicDispatcherTestAllVersions, LegacyVersionEncapsulation) { ProcessReceivedPacket(packets[0]->Clone(), client_address, version_, server_connection_id); - EXPECT_EQ(dispatcher_->session_map().size(), 1u); + EXPECT_EQ(dispatcher_->NumSessions(), 1u); // Processing the same packet a second time should also be routed by the // dispatcher to the right connection (we expect ProcessUdpPacket to be @@ -777,9 +800,9 @@ TEST_P(QuicDispatcherTestOneVersion, NoVersionNegotiationWithSmallPacket) { std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just // under 1200 bytes after framing, packet, and encryption overhead. - DCHECK_LE(1200u, chlo.length()); + QUICHE_DCHECK_LE(1200u, chlo.length()); std::string truncated_chlo = chlo.substr(0, 1100); - DCHECK_EQ(1100u, truncated_chlo.length()); + QUICHE_DCHECK_EQ(1100u, truncated_chlo.length()); ProcessPacket(client_address, TestConnectionId(1), true, QuicVersionReservedForNegotiation(), truncated_chlo, false, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); @@ -801,9 +824,9 @@ TEST_P(QuicDispatcherTestOneVersion, std::string chlo = SerializeCHLO() + std::string(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just // under 1200 bytes after framing, packet, and encryption overhead. - DCHECK_LE(1200u, chlo.length()); + QUICHE_DCHECK_LE(1200u, chlo.length()); std::string truncated_chlo = chlo.substr(0, 1100); - DCHECK_EQ(1100u, truncated_chlo.length()); + QUICHE_DCHECK_EQ(1100u, truncated_chlo.length()); ProcessPacket(client_address, TestConnectionId(1), true, QuicVersionReservedForNegotiation(), truncated_chlo, true, CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, 1); @@ -1078,8 +1101,6 @@ void QuicDispatcherTestBase:: TestVersionNegotiationForUnknownVersionInvalidShortInitialConnectionId( const QuicConnectionId& server_connection_id, const QuicConnectionId& client_connection_id) { - SetQuicReloadableFlag(quic_send_version_negotiation_for_short_connection_ids, - true); CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); @@ -1149,6 +1170,23 @@ TEST_P(QuicDispatcherTestOneVersion, } TEST_P(QuicDispatcherTestOneVersion, + RejectDeprecatedVersionDraft27WithVersionNegotiation) { + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + CreateTimeWaitListManager(); + char packet[kMinPacketSizeForVersionNegotiation] = { + 0xC0, 0xFF, 0x00, 0x00, 27, /*destination connection ID length*/ 0x08}; + QuicReceivedPacket received_packet(packet, ABSL_ARRAYSIZE(packet), + QuicTime::Zero()); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _)).Times(0); + EXPECT_CALL( + *time_wait_list_manager_, + SendVersionNegotiationPacket(_, _, /*ietf_quic=*/true, + /*use_length_prefix=*/true, _, _, _, _)) + .Times(1); + dispatcher_->ProcessPacket(server_address_, client_address, received_packet); +} + +TEST_P(QuicDispatcherTestOneVersion, RejectDeprecatedVersionDraft25WithVersionNegotiation) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); CreateTimeWaitListManager(); @@ -1166,6 +1204,23 @@ TEST_P(QuicDispatcherTestOneVersion, } TEST_P(QuicDispatcherTestOneVersion, + RejectDeprecatedVersionT050WithVersionNegotiation) { + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + CreateTimeWaitListManager(); + char packet[kMinPacketSizeForVersionNegotiation] = { + 0xC0, 'T', '0', '5', '0', /*destination connection ID length*/ 0x08}; + QuicReceivedPacket received_packet(packet, ABSL_ARRAYSIZE(packet), + QuicTime::Zero()); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _, _)).Times(0); + EXPECT_CALL( + *time_wait_list_manager_, + SendVersionNegotiationPacket(_, _, /*ietf_quic=*/true, + /*use_length_prefix=*/true, _, _, _, _)) + .Times(1); + dispatcher_->ProcessPacket(server_address_, client_address, received_packet); +} + +TEST_P(QuicDispatcherTestOneVersion, RejectDeprecatedVersionQ049WithVersionNegotiation) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); CreateTimeWaitListManager(); @@ -1251,7 +1306,7 @@ TEST_P(QuicDispatcherTestOneVersion, received_packet44); } -static_assert(quic::SupportedVersions().size() == 7u, +static_assert(quic::SupportedVersions().size() == 6u, "Please add new RejectDeprecatedVersion tests above this assert " "when deprecating versions"); @@ -1911,6 +1966,190 @@ TEST_P(QuicDispatcherWriteBlockedListTest, MarkSession1Deleted(); } +class QuicDispatcherSupportMultipleConnectionIdPerConnectionTest + : public QuicDispatcherTestBase { + public: + QuicDispatcherSupportMultipleConnectionIdPerConnectionTest() + : QuicDispatcherTestBase(crypto_test_utils::ProofSourceForTesting()) { + SetQuicRestartFlag(quic_use_reference_counted_sesssion_map, true); + SetQuicRestartFlag(quic_time_wait_list_support_multiple_cid_v2, true); + SetQuicRestartFlag(quic_dispatcher_support_multiple_cid_per_connection_v2, + true); + dispatcher_ = std::make_unique<NiceMock<TestDispatcher>>( + &config_, &crypto_config_, &version_manager_, + mock_helper_.GetRandomGenerator()); + } + void AddConnection1() { + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + EXPECT_CALL(*dispatcher_, + CreateQuicSession(_, _, client_address, Eq(ExpectedAlpn()), _)) + .WillOnce(Return(ByMove(CreateSession( + dispatcher_.get(), config_, TestConnectionId(1), client_address, + &helper_, &alarm_factory_, &crypto_config_, + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)))); + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), + ProcessUdpPacket(_, _, _)) + .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) { + ValidatePacket(TestConnectionId(1), packet); + }))); + EXPECT_CALL(*dispatcher_, + ShouldCreateOrBufferPacketForConnection( + ReceivedPacketInfoConnectionIdEquals(TestConnectionId(1)))); + ProcessFirstFlight(client_address, TestConnectionId(1)); + } + + void AddConnection2() { + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 2); + EXPECT_CALL(*dispatcher_, + CreateQuicSession(_, _, client_address, Eq(ExpectedAlpn()), _)) + .WillOnce(Return(ByMove(CreateSession( + dispatcher_.get(), config_, TestConnectionId(2), client_address, + &helper_, &alarm_factory_, &crypto_config_, + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session2_)))); + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session2_->connection()), + ProcessUdpPacket(_, _, _)) + .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) { + ValidatePacket(TestConnectionId(2), packet); + }))); + EXPECT_CALL(*dispatcher_, + ShouldCreateOrBufferPacketForConnection( + ReceivedPacketInfoConnectionIdEquals(TestConnectionId(2)))); + ProcessFirstFlight(client_address, TestConnectionId(2)); + } + + protected: + MockQuicConnectionHelper helper_; + MockAlarmFactory alarm_factory_; +}; + +INSTANTIATE_TEST_SUITE_P( + QuicDispatcherSupportMultipleConnectionIdPerConnectionTests, + QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + ::testing::Values(CurrentSupportedVersions().front()), + ::testing::PrintToStringParamName()); + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + OnNewConnectionIdSent) { + AddConnection1(); + ASSERT_EQ(dispatcher_->NumSessions(), 1u); + ASSERT_THAT(session1_, testing::NotNull()); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + + { + mock_server_connection1->AddNewConnectionId(TestConnectionId(3)); + EXPECT_EQ(dispatcher_->NumSessions(), 1u); + auto* session = + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(3)); + ASSERT_EQ(session, session1_); + } + + { + mock_server_connection1->AddNewConnectionId(TestConnectionId(4)); + EXPECT_EQ(dispatcher_->NumSessions(), 1u); + auto* session = + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(4)); + ASSERT_EQ(session, session1_); + } + + EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); + // Would timed out unless all sessions have been removed from the session map. + dispatcher_->Shutdown(); +} + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + RetireConnectionIdFromSingleConnection) { + AddConnection1(); + ASSERT_EQ(dispatcher_->NumSessions(), 1u); + ASSERT_THAT(session1_, testing::NotNull()); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + + // Adds 1 new connection id every turn and retires 2 connection ids every + // other turn. + for (int i = 2; i < 10; ++i) { + mock_server_connection1->AddNewConnectionId(TestConnectionId(i)); + ASSERT_EQ( + QuicDispatcherPeer::FindSession(dispatcher_.get(), TestConnectionId(i)), + session1_); + ASSERT_EQ(QuicDispatcherPeer::FindSession(dispatcher_.get(), + TestConnectionId(i - 1)), + session1_); + EXPECT_EQ(dispatcher_->NumSessions(), 1u); + if (i % 2 == 1) { + mock_server_connection1->RetireConnectionId(TestConnectionId(i - 2)); + mock_server_connection1->RetireConnectionId(TestConnectionId(i - 1)); + } + } + + EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); + // Would timed out unless all sessions have been removed from the session map. + dispatcher_->Shutdown(); +} + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + RetireConnectionIdFromMultipleConnections) { + AddConnection1(); + AddConnection2(); + ASSERT_EQ(dispatcher_->NumSessions(), 2u); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + MockServerConnection* mock_server_connection2 = + reinterpret_cast<MockServerConnection*>(connection2()); + + for (int i = 2; i < 10; ++i) { + mock_server_connection1->AddNewConnectionId(TestConnectionId(2 * i - 1)); + mock_server_connection2->AddNewConnectionId(TestConnectionId(2 * i)); + ASSERT_EQ(QuicDispatcherPeer::FindSession(dispatcher_.get(), + TestConnectionId(2 * i - 1)), + session1_); + ASSERT_EQ(QuicDispatcherPeer::FindSession(dispatcher_.get(), + TestConnectionId(2 * i)), + session2_); + EXPECT_EQ(dispatcher_->NumSessions(), 2u); + mock_server_connection1->RetireConnectionId(TestConnectionId(2 * i - 3)); + mock_server_connection2->RetireConnectionId(TestConnectionId(2 * i - 2)); + } + + mock_server_connection1->AddNewConnectionId(TestConnectionId(19)); + mock_server_connection2->AddNewConnectionId(TestConnectionId(20)); + EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); + EXPECT_CALL(*connection2(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); + // Would timed out unless all sessions have been removed from the session map. + dispatcher_->Shutdown(); +} + +TEST_P(QuicDispatcherSupportMultipleConnectionIdPerConnectionTest, + TimeWaitListPoplulateCorrectly) { + QuicTimeWaitListManager* time_wait_list_manager = + QuicDispatcherPeer::GetTimeWaitListManager(dispatcher_.get()); + AddConnection1(); + MockServerConnection* mock_server_connection1 = + reinterpret_cast<MockServerConnection*>(connection1()); + + mock_server_connection1->AddNewConnectionId(TestConnectionId(2)); + mock_server_connection1->AddNewConnectionId(TestConnectionId(3)); + mock_server_connection1->AddNewConnectionId(TestConnectionId(4)); + mock_server_connection1->RetireConnectionId(TestConnectionId(1)); + mock_server_connection1->RetireConnectionId(TestConnectionId(2)); + + EXPECT_CALL(*connection1(), CloseConnection(QUIC_PEER_GOING_AWAY, _, _)); + connection1()->CloseConnection( + QUIC_PEER_GOING_AWAY, "Close for testing", + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + + EXPECT_FALSE( + time_wait_list_manager->IsConnectionIdInTimeWait(TestConnectionId(1))); + EXPECT_FALSE( + time_wait_list_manager->IsConnectionIdInTimeWait(TestConnectionId(2))); + EXPECT_TRUE( + time_wait_list_manager->IsConnectionIdInTimeWait(TestConnectionId(3))); + EXPECT_TRUE( + time_wait_list_manager->IsConnectionIdInTimeWait(TestConnectionId(4))); + + dispatcher_->Shutdown(); +} + class BufferedPacketStoreTest : public QuicDispatcherTestBase { public: BufferedPacketStoreTest() @@ -1977,7 +2216,7 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketBeforeChlo) { ReceivedPacketInfoConnectionIdEquals(conn_id))); // Process non-CHLO packet. ProcessUndecryptableEarlyPacket(conn_id); - EXPECT_EQ(0u, dispatcher_->session_map().size()) + EXPECT_EQ(0u, dispatcher_->NumSessions()) << "No session should be created before CHLO arrives."; // When CHLO arrives, a new session should be created, and all packets @@ -2010,7 +2249,7 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) { ProcessUndecryptableEarlyPacket(conn_id); } - EXPECT_EQ(0u, dispatcher_->session_map().size()) + EXPECT_EQ(0u, dispatcher_->NumSessions()) << "No session should be created before CHLO arrives."; // Pop out the last packet as it is also be dropped by the store. @@ -2152,9 +2391,8 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) { QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); QuicConnectionId conn_id = TestConnectionId(1); - ProcessPacket(client_addr_, conn_id, true, - quiche::QuicheStrCat("data packet ", 2), CONNECTION_ID_PRESENT, - PACKET_4BYTE_PACKET_NUMBER, + ProcessPacket(client_addr_, conn_id, true, absl::StrCat("data packet ", 2), + CONNECTION_ID_PRESENT, PACKET_4BYTE_PACKET_NUMBER, /*packet_number=*/2); mock_helper_.AdvanceTime( |