gfe-relnote: Add QuicCoalescedPacket class. Not used in prod, not protected.

PiperOrigin-RevId: 276269515
Change-Id: I66c08eedac83bf190f871be093bfea9ec99967c9
diff --git a/quic/core/quic_coalesced_packet.cc b/quic/core/quic_coalesced_packet.cc
new file mode 100644
index 0000000..62eee42
--- /dev/null
+++ b/quic/core/quic_coalesced_packet.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/quic_coalesced_packet.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+
+namespace quic {
+
+QuicCoalescedPacket::QuicCoalescedPacket()
+    : length_(0), max_packet_length_(0) {}
+
+QuicCoalescedPacket::~QuicCoalescedPacket() {
+  Clear();
+}
+
+bool QuicCoalescedPacket::MaybeCoalescePacket(
+    const SerializedPacket& packet,
+    const QuicSocketAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    QuicBufferAllocator* allocator,
+    QuicPacketLength current_max_packet_length) {
+  if (packet.encrypted_length == 0) {
+    QUIC_BUG << "Trying to coalesce an empty packet";
+    return true;
+  }
+  if (length_ == 0) {
+#ifndef NDEBUG
+    for (const auto& buffer : encrypted_buffers_) {
+      DCHECK(buffer.empty());
+    }
+#endif
+    DCHECK(initial_packet_ == nullptr);
+    // This is the first packet, set max_packet_length and self/peer
+    // addresses.
+    max_packet_length_ = current_max_packet_length;
+    self_address_ = self_address;
+    peer_address_ = peer_address;
+  } else {
+    if (self_address_ != self_address || peer_address_ != peer_address) {
+      // Do not coalesce packet with different self/peer addresses.
+      QUIC_DLOG(INFO)
+          << "Cannot coalesce packet because self/peer address changed";
+      return false;
+    }
+    if (max_packet_length_ != current_max_packet_length) {
+      QUIC_DLOG(INFO)
+          << "Do not try to coalesce packet when max packet length changed.";
+      return false;
+    }
+    if (!encrypted_buffers_[packet.encryption_level].empty() ||
+        (packet.encryption_level == ENCRYPTION_INITIAL &&
+         initial_packet_ != nullptr)) {
+      // Do not coalesce packets of the same encryption level.
+      return false;
+    }
+  }
+
+  if (packet.encryption_level == ENCRYPTION_INITIAL) {
+    for (const auto& frame : packet.nonretransmittable_frames) {
+      if (frame.type == PADDING_FRAME) {
+        QUIC_BUG << "ENCRYPTION_INITIAL packet should not contain padding "
+                    "frame if trying to send coalesced packet";
+        return false;
+      }
+    }
+  }
+  if (length_ + packet.encrypted_length > max_packet_length_) {
+    // Packet does not fit.
+    return false;
+  }
+
+  length_ += packet.encrypted_length;
+  if (packet.encryption_level == ENCRYPTION_INITIAL) {
+    // Save a copy of ENCRYPTION_INITIAL packet (excluding encrypted buffer, as
+    // the packet will be re-serialized later).
+    initial_packet_ = QuicWrapUnique<SerializedPacket>(
+        CopySerializedPacket(packet, allocator, /*copy_buffer=*/false));
+    return true;
+  }
+  // Copy encrypted buffer of packets with other encryption levels.
+  encrypted_buffers_[packet.encryption_level] =
+      std::string(packet.encrypted_buffer, packet.encrypted_length);
+  return true;
+}
+
+void QuicCoalescedPacket::Clear() {
+  self_address_ = QuicSocketAddress();
+  peer_address_ = QuicSocketAddress();
+  length_ = 0;
+  max_packet_length_ = 0;
+  for (auto& packet : encrypted_buffers_) {
+    packet.clear();
+  }
+  if (initial_packet_ != nullptr) {
+    ClearSerializedPacket(initial_packet_.get());
+  }
+  initial_packet_ = nullptr;
+}
+
+}  // namespace quic