Add VersionNegotiationProbeEndToEnd test This CL introduces SavingWriter, a subclass of QuicPacketWriterWrapper that saves all the packets instead of sending them. It uses it to test that a packet generated by QuicFramer::WriteClientVersionNegotiationProbePacket does generate a response and that the response can be correctly parsed by QuicFramer::ParseServerVersionNegotiationProbeResponse. This CL also fixes a typo in a log statement. gfe-relnote: n/a, log-only and test-only change. PiperOrigin-RevId: 263387682 Change-Id: I2dd2eccd5db973b93f0aa8e56c155b47e9b50855
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index 7b09617..bd30333 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -1064,6 +1064,121 @@ dispatcher_->ProcessPacket(server_address_, client_address, *received_packet); } +// Testing packet writer that saves all packets instead of sending them. +// Useful for tests that need access to sent packets. +class SavingWriter : public QuicPacketWriterWrapper { + public: + bool IsWriteBlocked() const override { return false; } + + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& /*self_client_address*/, + const QuicSocketAddress& /*peer_client_address*/, + PerPacketOptions* /*options*/) override { + packets_.push_back( + QuicEncryptedPacket(buffer, buf_len, /*owns_buffer=*/false).Clone()); + return WriteResult(WRITE_STATUS_OK, buf_len); + } + + std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() { + return &packets_; + } + + private: + std::vector<std::unique_ptr<QuicEncryptedPacket>> packets_; +}; + +TEST_F(QuicDispatcherTest, VersionNegotiationProbeEndToEndOld) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, false); + SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true); + + SavingWriter* saving_writer = new SavingWriter(); + // dispatcher_ takes ownership of saving_writer. + QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); + + QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager( + saving_writer, dispatcher_.get(), mock_helper_.GetClock(), + &mock_alarm_factory_); + // dispatcher_ takes ownership of time_wait_list_manager. + QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(), + time_wait_list_manager); + char packet[1200] = {}; + char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( + packet, sizeof(packet), destination_connection_id_bytes, + sizeof(destination_connection_id_bytes))); + QuicEncryptedPacket encrypted(packet, sizeof(packet), false); + std::unique_ptr<QuicReceivedPacket> received_packet( + ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now())); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); + + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + dispatcher_->ProcessPacket(server_address_, client_address, *received_packet); + ASSERT_EQ(1u, saving_writer->packets()->size()); + + char source_connection_id_bytes[255] = {}; + uint8_t source_connection_id_length = 0; + std::string detailed_error = "foobar"; + EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse( + (*(saving_writer->packets()))[0]->data(), + (*(saving_writer->packets()))[0]->length(), source_connection_id_bytes, + &source_connection_id_length, &detailed_error)); + EXPECT_EQ("", detailed_error); + + // The source connection ID of the probe response should match the + // destination connection ID of the probe request. + test::CompareCharArraysWithHexError( + "parsed probe", source_connection_id_bytes, source_connection_id_length, + destination_connection_id_bytes, sizeof(destination_connection_id_bytes)); +} + +TEST_F(QuicDispatcherTest, VersionNegotiationProbeEndToEnd) { + SetQuicFlag(FLAGS_quic_prober_uses_length_prefixed_connection_ids, true); + SetQuicReloadableFlag(quic_use_parse_public_header, true); + SetQuicReloadableFlag(quic_use_length_prefix_from_packet_info, true); + + SavingWriter* saving_writer = new SavingWriter(); + // dispatcher_ takes ownership of saving_writer. + QuicDispatcherPeer::UseWriter(dispatcher_.get(), saving_writer); + + QuicTimeWaitListManager* time_wait_list_manager = new QuicTimeWaitListManager( + saving_writer, dispatcher_.get(), mock_helper_.GetClock(), + &mock_alarm_factory_); + // dispatcher_ takes ownership of time_wait_list_manager. + QuicDispatcherPeer::SetTimeWaitListManager(dispatcher_.get(), + time_wait_list_manager); + char packet[1200] = {}; + char destination_connection_id_bytes[] = {0x56, 0x4e, 0x20, 0x70, + 0x6c, 0x7a, 0x20, 0x21}; + EXPECT_TRUE(QuicFramer::WriteClientVersionNegotiationProbePacket( + packet, sizeof(packet), destination_connection_id_bytes, + sizeof(destination_connection_id_bytes))); + QuicEncryptedPacket encrypted(packet, sizeof(packet), false); + std::unique_ptr<QuicReceivedPacket> received_packet( + ConstructReceivedPacket(encrypted, mock_helper_.GetClock()->Now())); + EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); + + QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); + dispatcher_->ProcessPacket(server_address_, client_address, *received_packet); + ASSERT_EQ(1u, saving_writer->packets()->size()); + + char source_connection_id_bytes[255] = {}; + uint8_t source_connection_id_length = 0; + std::string detailed_error = "foobar"; + EXPECT_TRUE(QuicFramer::ParseServerVersionNegotiationProbeResponse( + (*(saving_writer->packets()))[0]->data(), + (*(saving_writer->packets()))[0]->length(), source_connection_id_bytes, + &source_connection_id_length, &detailed_error)); + EXPECT_EQ("", detailed_error); + + // The source connection ID of the probe response should match the + // destination connection ID of the probe request. + test::CompareCharArraysWithHexError( + "parsed probe", source_connection_id_bytes, source_connection_id_length, + destination_connection_id_bytes, sizeof(destination_connection_id_bytes)); +} + // Verify the stopgap test: Packets with truncated connection IDs should be // dropped. class QuicDispatcherTestStrayPacketConnectionId : public QuicDispatcherTest {};
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc index a0e7cfb..f4a4f89 100644 --- a/quic/core/quic_time_wait_list_manager.cc +++ b/quic/core/quic_time_wait_list_manager.cc
@@ -215,10 +215,10 @@ QuicFramer::BuildVersionNegotiationPacket( server_connection_id, client_connection_id, ietf_quic, use_length_prefix, supported_versions); - QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet: {" + QUIC_DVLOG(2) << "Dispatcher sending version negotiation packet {" << ParsedQuicVersionVectorToString(supported_versions) << "}, " - << (ietf_quic ? "" : "!") - << "ietf_quic:" << (use_length_prefix ? "" : "!") + << (ietf_quic ? "" : "!") << "ietf_quic, " + << (use_length_prefix ? "" : "!") << "use_length_prefix:" << std::endl << QuicTextUtils::HexDump(QuicStringPiece( version_packet->data(), version_packet->length()));