|  | // 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 |