Log QUIC_BUG if initial header changed between initial serialization and re-serialization. PiperOrigin-RevId: 503268541
diff --git a/quiche/quic/core/quic_packet_creator.cc b/quiche/quic/core/quic_packet_creator.cc index 566944c..2a0974f 100644 --- a/quiche/quic/core/quic_packet_creator.cc +++ b/quiche/quic/core/quic_packet_creator.cc
@@ -507,6 +507,7 @@ packet_.largest_acked.Clear(); needs_full_padding_ = false; packet_.bytes_not_retransmitted.reset(); + packet_.initial_header.reset(); } size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( @@ -560,6 +561,15 @@ /*allow_padding=*/false)) { return 0; } + if (!packet.initial_header.has_value() || + !packet_.initial_header.has_value()) { + QUIC_BUG(missing initial packet header) + << "initial serialized packet does not have header populated"; + } else if (packet.initial_header.value() != packet_.initial_header.value()) { + QUIC_BUG(initial packet header changed before reserialization) + << ENDPOINT << "original header: " << packet.initial_header.value() + << ", new header: " << packet_.initial_header.value(); + } const size_t encrypted_length = packet_.encrypted_length; // Clear frames in packet_. No need to DeleteFrames since frames are owned by // initial_packet. @@ -826,6 +836,9 @@ QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); + if (packet_.encryption_level == ENCRYPTION_INITIAL) { + packet_.initial_header = header; + } if (delegate_ != nullptr) { packet_.fate = delegate_->GetSerializedPacketFate( /*is_mtu_discovery=*/QuicUtils::ContainsFrameType(queued_frames_,
diff --git a/quiche/quic/core/quic_packets.cc b/quiche/quic/core/quic_packets.cc index d884adf..746737b 100644 --- a/quiche/quic/core/quic_packets.cc +++ b/quiche/quic/core/quic_packets.cc
@@ -169,6 +169,7 @@ version_flag(false), has_possible_stateless_reset_token(false), packet_number_length(PACKET_4BYTE_PACKET_NUMBER), + type_byte(0), version(UnsupportedQuicVersion()), nonce(nullptr), form(GOOGLE_QUIC_PACKET), @@ -447,7 +448,8 @@ has_message(other.has_message), fate(other.fate), peer_address(other.peer_address), - bytes_not_retransmitted(other.bytes_not_retransmitted) { + bytes_not_retransmitted(other.bytes_not_retransmitted), + initial_header(other.initial_header) { if (this != &other) { if (release_encrypted_buffer && encrypted_buffer != nullptr) { release_encrypted_buffer(encrypted_buffer); @@ -495,6 +497,7 @@ copy->fate = serialized.fate; copy->peer_address = serialized.peer_address; copy->bytes_not_retransmitted = serialized.bytes_not_retransmitted; + copy->initial_header = serialized.initial_header; if (copy_buffer) { copy->encrypted_buffer = CopyBuffer(serialized); @@ -563,4 +566,34 @@ return os; } +bool QuicPacketHeader::operator==(const QuicPacketHeader& other) const { + return destination_connection_id == other.destination_connection_id && + destination_connection_id_included == + other.destination_connection_id_included && + source_connection_id == other.source_connection_id && + source_connection_id_included == other.source_connection_id_included && + reset_flag == other.reset_flag && version_flag == other.version_flag && + has_possible_stateless_reset_token == + other.has_possible_stateless_reset_token && + packet_number_length == other.packet_number_length && + type_byte == other.type_byte && version == other.version && + nonce == other.nonce && + ((!packet_number.IsInitialized() && + !other.packet_number.IsInitialized()) || + (packet_number.IsInitialized() && + other.packet_number.IsInitialized() && + packet_number == other.packet_number)) && + form == other.form && long_packet_type == other.long_packet_type && + possible_stateless_reset_token == + other.possible_stateless_reset_token && + retry_token_length_length == other.retry_token_length_length && + retry_token == other.retry_token && + length_length == other.length_length && + remaining_packet_length == other.remaining_packet_length; +} + +bool QuicPacketHeader::operator!=(const QuicPacketHeader& other) const { + return !operator==(other); +} + } // namespace quic
diff --git a/quiche/quic/core/quic_packets.h b/quiche/quic/core/quic_packets.h index a1c743a..c26a88a 100644 --- a/quiche/quic/core/quic_packets.h +++ b/quiche/quic/core/quic_packets.h
@@ -157,6 +157,9 @@ // 0-RTT and Handshake packets. Also includes the length of the // diversification nonce in server to client 0-RTT packets. QuicByteCount remaining_packet_length; + + bool operator==(const QuicPacketHeader& other) const; + bool operator!=(const QuicPacketHeader& other) const; }; struct QUIC_EXPORT_PRIVATE QuicPublicResetPacket { @@ -388,6 +391,9 @@ // populated for packets with "mixed frames": at least one frame of a // retransmission type and at least one frame of NOT_RETRANSMISSION type. absl::optional<QuicByteCount> bytes_not_retransmitted; + // Only populated if encryption_level is ENCRYPTION_INITIAL. + // TODO(b/265777524): remove this. + absl::optional<QuicPacketHeader> initial_header; }; // Make a copy of |serialized| (including the underlying frames). |copy_buffer|
diff --git a/quiche/quic/core/quic_packets_test.cc b/quiche/quic/core/quic_packets_test.cc index f0a7e7f..4e6598d 100644 --- a/quiche/quic/core/quic_packets_test.cc +++ b/quiche/quic/core/quic_packets_test.cc
@@ -72,6 +72,14 @@ GetClientConnectionIdAsSender(header, Perspective::IS_CLIENT)); } +TEST_F(QuicPacketsTest, CopyQuicPacketHeader) { + QuicPacketHeader header; + QuicPacketHeader header2 = CreateFakePacketHeader(); + EXPECT_NE(header, header2); + QuicPacketHeader header3(header2); + EXPECT_EQ(header2, header3); +} + TEST_F(QuicPacketsTest, CopySerializedPacket) { std::string buffer(1000, 'a'); quiche::SimpleBufferAllocator allocator;