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