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;