gfe-relnote: In QUIC, add a utility function CopySerializedPacket. Not used yet, not protected. Add bool has_ack_frame_copy to SerializedPacket, indicating whether the serialized packet contains a copy of ack frame. PiperOrigin-RevId: 275908820 Change-Id: I34b156091a9fbaa542bed5951588c43b59de12bb
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc index 216a37b..68a078e 100644 --- a/quic/core/quic_packets.cc +++ b/quic/core/quic_packets.cc
@@ -456,7 +456,8 @@ encryption_level(ENCRYPTION_INITIAL), has_ack(has_ack), has_stop_waiting(has_stop_waiting), - transmission_type(NOT_RETRANSMISSION) {} + transmission_type(NOT_RETRANSMISSION), + has_ack_frame_copy(false) {} SerializedPacket::SerializedPacket(const SerializedPacket& other) = default; @@ -475,20 +476,41 @@ has_stop_waiting(other.has_stop_waiting), transmission_type(other.transmission_type), original_packet_number(other.original_packet_number), - largest_acked(other.largest_acked) { + largest_acked(other.largest_acked), + has_ack_frame_copy(other.has_ack_frame_copy) { retransmittable_frames.swap(other.retransmittable_frames); nonretransmittable_frames.swap(other.nonretransmittable_frames); } SerializedPacket::~SerializedPacket() {} +SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, + QuicBufferAllocator* allocator, + bool copy_buffer) { + SerializedPacket* copy = new SerializedPacket(serialized); + if (copy_buffer) { + copy->encrypted_buffer = CopyBuffer(serialized); + } + // Copy underlying frames. + copy->retransmittable_frames = + CopyQuicFrames(allocator, serialized.retransmittable_frames); + copy->nonretransmittable_frames.clear(); + for (const auto& frame : serialized.nonretransmittable_frames) { + if (frame.type == ACK_FRAME) { + copy->has_ack_frame_copy = true; + } + copy->nonretransmittable_frames.push_back(CopyQuicFrame(allocator, frame)); + } + return copy; +} + void ClearSerializedPacket(SerializedPacket* serialized_packet) { if (!serialized_packet->retransmittable_frames.empty()) { DeleteFrames(&serialized_packet->retransmittable_frames); } for (auto& frame : serialized_packet->nonretransmittable_frames) { - if (frame.type == ACK_FRAME) { - // Ack frame is owned by received_packet_manager. + if (!serialized_packet->has_ack_frame_copy && frame.type == ACK_FRAME) { + // Do not delete ack frame if the packet does not own a copy of it. continue; } DeleteFrame(&frame);
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h index fcb2e56..361cd44 100644 --- a/quic/core/quic_packets.h +++ b/quic/core/quic_packets.h
@@ -379,6 +379,8 @@ QuicPacketNumber packet_number; QuicPacketNumberLength packet_number_length; EncryptionLevel encryption_level; + // TODO(fayang): Remove has_ack and has_stop_waiting when deprecating + // quic_populate_nonretransmittable_frames. bool has_ack; bool has_stop_waiting; TransmissionType transmission_type; @@ -386,8 +388,18 @@ // The largest acked of the AckFrame in this packet if has_ack is true, // 0 otherwise. QuicPacketNumber largest_acked; + // Indicates whether this packet has a copy of ack frame in + // nonretransmittable_frames. + bool has_ack_frame_copy; }; +// Make a copy of |serialized| (including the underlying frames). |copy_buffer| +// indicates whether the encrypted buffer should be copied. +QUIC_EXPORT_PRIVATE SerializedPacket* CopySerializedPacket( + const SerializedPacket& serialized, + QuicBufferAllocator* allocator, + bool copy_buffer); + // Deletes and clears all the frames and the packet from serialized packet. QUIC_EXPORT_PRIVATE void ClearSerializedPacket( SerializedPacket* serialized_packet);
diff --git a/quic/core/quic_packets_test.cc b/quic/core/quic_packets_test.cc index 7ee7797..e080cd8 100644 --- a/quic/core/quic_packets_test.cc +++ b/quic/core/quic_packets_test.cc
@@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -70,6 +71,46 @@ GetClientConnectionIdAsSender(header, Perspective::IS_CLIENT)); } +TEST_F(QuicPacketsTest, CopySerializedPacket) { + std::string buffer(1000, 'a'); + SimpleBufferAllocator allocator; + SerializedPacket packet(QuicPacketNumber(1), PACKET_1BYTE_PACKET_NUMBER, + buffer.data(), buffer.length(), /*has_ack=*/false, + /*has_stop_waiting=*/false); + packet.retransmittable_frames.push_back( + QuicFrame(new QuicWindowUpdateFrame())); + packet.retransmittable_frames.push_back(QuicFrame(QuicStreamFrame())); + + QuicAckFrame ack_frame(InitAckFrame(1)); + packet.nonretransmittable_frames.push_back(QuicFrame(&ack_frame)); + packet.nonretransmittable_frames.push_back(QuicFrame(QuicPaddingFrame(-1))); + + std::unique_ptr<SerializedPacket> copy = QuicWrapUnique<SerializedPacket>( + CopySerializedPacket(packet, &allocator, /*copy_buffer=*/true)); + EXPECT_EQ(quic::QuicPacketNumber(1), copy->packet_number); + EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, copy->packet_number_length); + ASSERT_EQ(2u, copy->retransmittable_frames.size()); + EXPECT_EQ(WINDOW_UPDATE_FRAME, copy->retransmittable_frames[0].type); + EXPECT_EQ(STREAM_FRAME, copy->retransmittable_frames[1].type); + + ASSERT_EQ(2u, copy->nonretransmittable_frames.size()); + EXPECT_EQ(ACK_FRAME, copy->nonretransmittable_frames[0].type); + EXPECT_EQ(PADDING_FRAME, copy->nonretransmittable_frames[1].type); + EXPECT_EQ(1000u, copy->encrypted_length); + test::CompareCharArraysWithHexError( + "encrypted_buffer", copy->encrypted_buffer, copy->encrypted_length, + packet.encrypted_buffer, packet.encrypted_length); + + std::unique_ptr<SerializedPacket> copy2 = QuicWrapUnique<SerializedPacket>( + CopySerializedPacket(packet, &allocator, /*copy_buffer=*/false)); + EXPECT_EQ(packet.encrypted_buffer, copy2->encrypted_buffer); + EXPECT_EQ(1000u, copy2->encrypted_length); + ClearSerializedPacket(&packet); + delete[] copy->encrypted_buffer; + ClearSerializedPacket(copy.get()); + ClearSerializedPacket(copy2.get()); +} + } // namespace } // namespace test } // namespace quic