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