| // 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 "quic/core/quic_coalesced_packet.h" | 
 |  | 
 | #include "absl/memory/memory.h" | 
 | #include "absl/strings/str_cat.h" | 
 | #include "quic/platform/api/quic_bug_tracker.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(quic_bug_10611_1) << "Trying to coalesce an empty packet"; | 
 |     return true; | 
 |   } | 
 |   if (length_ == 0) { | 
 | #ifndef NDEBUG | 
 |     for (const auto& buffer : encrypted_buffers_) { | 
 |       QUICHE_DCHECK(buffer.empty()); | 
 |     } | 
 | #endif | 
 |     QUICHE_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_BUG(quic_bug_10611_2) | 
 |           << "Max packet length changes in the middle of the write path"; | 
 |       return false; | 
 |     } | 
 |     if (ContainsPacketOfEncryptionLevel(packet.encryption_level)) { | 
 |       // Do not coalesce packets of the same encryption level. | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   if (length_ + packet.encrypted_length > max_packet_length_) { | 
 |     // Packet does not fit. | 
 |     return false; | 
 |   } | 
 |   QUIC_DVLOG(1) << "Successfully coalesced packet: encryption_level: " | 
 |                 << packet.encryption_level | 
 |                 << ", encrypted_length: " << packet.encrypted_length | 
 |                 << ", current length: " << length_ | 
 |                 << ", max_packet_length: " << max_packet_length_; | 
 |   if (length_ > 0) { | 
 |     QUIC_CODE_COUNT(QUIC_SUCCESSFULLY_COALESCED_MULTIPLE_PACKETS); | 
 |   } | 
 |   length_ += packet.encrypted_length; | 
 |   transmission_types_[packet.encryption_level] = packet.transmission_type; | 
 |   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_ = absl::WrapUnique<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(); | 
 |   } | 
 |   for (size_t i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { | 
 |     transmission_types_[i] = NOT_RETRANSMISSION; | 
 |   } | 
 |   initial_packet_ = nullptr; | 
 | } | 
 |  | 
 | void QuicCoalescedPacket::NeuterInitialPacket() { | 
 |   if (initial_packet_ == nullptr) { | 
 |     return; | 
 |   } | 
 |   if (length_ < initial_packet_->encrypted_length) { | 
 |     QUIC_BUG(quic_bug_10611_3) | 
 |         << "length_: " << length_ << ", is less than initial packet length: " | 
 |         << initial_packet_->encrypted_length; | 
 |     Clear(); | 
 |     return; | 
 |   } | 
 |   length_ -= initial_packet_->encrypted_length; | 
 |   if (length_ == 0) { | 
 |     Clear(); | 
 |     return; | 
 |   } | 
 |   transmission_types_[ENCRYPTION_INITIAL] = NOT_RETRANSMISSION; | 
 |   initial_packet_ = nullptr; | 
 | } | 
 |  | 
 | bool QuicCoalescedPacket::CopyEncryptedBuffers(char* buffer, | 
 |                                                size_t buffer_len, | 
 |                                                size_t* length_copied) const { | 
 |   *length_copied = 0; | 
 |   for (const auto& packet : encrypted_buffers_) { | 
 |     if (packet.empty()) { | 
 |       continue; | 
 |     } | 
 |     if (packet.length() > buffer_len) { | 
 |       return false; | 
 |     } | 
 |     memcpy(buffer, packet.data(), packet.length()); | 
 |     buffer += packet.length(); | 
 |     buffer_len -= packet.length(); | 
 |     *length_copied += packet.length(); | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | bool QuicCoalescedPacket::ContainsPacketOfEncryptionLevel( | 
 |     EncryptionLevel level) const { | 
 |   return !encrypted_buffers_[level].empty() || | 
 |          (level == ENCRYPTION_INITIAL && initial_packet_ != nullptr); | 
 | } | 
 |  | 
 | TransmissionType QuicCoalescedPacket::TransmissionTypeOfPacket( | 
 |     EncryptionLevel level) const { | 
 |   if (!ContainsPacketOfEncryptionLevel(level)) { | 
 |     QUIC_BUG(quic_bug_10611_4) | 
 |         << "Coalesced packet does not contain packet of encryption level: " | 
 |         << EncryptionLevelToString(level); | 
 |     return NOT_RETRANSMISSION; | 
 |   } | 
 |   return transmission_types_[level]; | 
 | } | 
 |  | 
 | size_t QuicCoalescedPacket::NumberOfPackets() const { | 
 |   size_t num_of_packets = 0; | 
 |   for (int8_t i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { | 
 |     if (ContainsPacketOfEncryptionLevel(static_cast<EncryptionLevel>(i))) { | 
 |       ++num_of_packets; | 
 |     } | 
 |   } | 
 |   return num_of_packets; | 
 | } | 
 |  | 
 | std::string QuicCoalescedPacket::ToString(size_t serialized_length) const { | 
 |   // Total length and padding size. | 
 |   std::string info = absl::StrCat( | 
 |       "total_length: ", serialized_length, | 
 |       " padding_size: ", serialized_length - length_, " packets: {"); | 
 |   // Packets' encryption levels. | 
 |   bool first_packet = true; | 
 |   for (int8_t i = ENCRYPTION_INITIAL; i < NUM_ENCRYPTION_LEVELS; ++i) { | 
 |     if (ContainsPacketOfEncryptionLevel(static_cast<EncryptionLevel>(i))) { | 
 |       absl::StrAppend(&info, first_packet ? "" : ", ", | 
 |                       EncryptionLevelToString(static_cast<EncryptionLevel>(i))); | 
 |       first_packet = false; | 
 |     } | 
 |   } | 
 |   absl::StrAppend(&info, "}"); | 
 |   return info; | 
 | } | 
 |  | 
 | }  // namespace quic |