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