| // Copyright (c) 2012 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_packets.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "absl/strings/escaping.h" | 
 | #include "absl/strings/str_cat.h" | 
 | #include "absl/strings/string_view.h" | 
 | #include "quic/core/quic_connection_id.h" | 
 | #include "quic/core/quic_types.h" | 
 | #include "quic/core/quic_utils.h" | 
 | #include "quic/core/quic_versions.h" | 
 | #include "quic/platform/api/quic_flag_utils.h" | 
 | #include "quic/platform/api/quic_flags.h" | 
 |  | 
 | namespace quic { | 
 |  | 
 | QuicConnectionId GetServerConnectionIdAsRecipient( | 
 |     const QuicPacketHeader& header, | 
 |     Perspective perspective) { | 
 |   if (perspective == Perspective::IS_SERVER) { | 
 |     return header.destination_connection_id; | 
 |   } | 
 |   return header.source_connection_id; | 
 | } | 
 |  | 
 | QuicConnectionId GetClientConnectionIdAsRecipient( | 
 |     const QuicPacketHeader& header, | 
 |     Perspective perspective) { | 
 |   if (perspective == Perspective::IS_CLIENT) { | 
 |     return header.destination_connection_id; | 
 |   } | 
 |   return header.source_connection_id; | 
 | } | 
 |  | 
 | QuicConnectionId GetServerConnectionIdAsSender(const QuicPacketHeader& header, | 
 |                                                Perspective perspective) { | 
 |   if (perspective == Perspective::IS_CLIENT) { | 
 |     return header.destination_connection_id; | 
 |   } | 
 |   return header.source_connection_id; | 
 | } | 
 |  | 
 | QuicConnectionIdIncluded GetServerConnectionIdIncludedAsSender( | 
 |     const QuicPacketHeader& header, | 
 |     Perspective perspective) { | 
 |   if (perspective == Perspective::IS_CLIENT) { | 
 |     return header.destination_connection_id_included; | 
 |   } | 
 |   return header.source_connection_id_included; | 
 | } | 
 |  | 
 | QuicConnectionId GetClientConnectionIdAsSender(const QuicPacketHeader& header, | 
 |                                                Perspective perspective) { | 
 |   if (perspective == Perspective::IS_CLIENT) { | 
 |     return header.source_connection_id; | 
 |   } | 
 |   return header.destination_connection_id; | 
 | } | 
 |  | 
 | QuicConnectionIdIncluded GetClientConnectionIdIncludedAsSender( | 
 |     const QuicPacketHeader& header, | 
 |     Perspective perspective) { | 
 |   if (perspective == Perspective::IS_CLIENT) { | 
 |     return header.source_connection_id_included; | 
 |   } | 
 |   return header.destination_connection_id_included; | 
 | } | 
 |  | 
 | QuicConnectionIdLength GetIncludedConnectionIdLength( | 
 |     QuicConnectionId connection_id, | 
 |     QuicConnectionIdIncluded connection_id_included) { | 
 |   QUICHE_DCHECK(connection_id_included == CONNECTION_ID_PRESENT || | 
 |                 connection_id_included == CONNECTION_ID_ABSENT); | 
 |   return connection_id_included == CONNECTION_ID_PRESENT | 
 |              ? static_cast<QuicConnectionIdLength>(connection_id.length()) | 
 |              : PACKET_0BYTE_CONNECTION_ID; | 
 | } | 
 |  | 
 | QuicConnectionIdLength GetIncludedDestinationConnectionIdLength( | 
 |     const QuicPacketHeader& header) { | 
 |   return GetIncludedConnectionIdLength( | 
 |       header.destination_connection_id, | 
 |       header.destination_connection_id_included); | 
 | } | 
 |  | 
 | QuicConnectionIdLength GetIncludedSourceConnectionIdLength( | 
 |     const QuicPacketHeader& header) { | 
 |   return GetIncludedConnectionIdLength(header.source_connection_id, | 
 |                                        header.source_connection_id_included); | 
 | } | 
 |  | 
 | size_t GetPacketHeaderSize(QuicTransportVersion version, | 
 |                            const QuicPacketHeader& header) { | 
 |   return GetPacketHeaderSize( | 
 |       version, GetIncludedDestinationConnectionIdLength(header), | 
 |       GetIncludedSourceConnectionIdLength(header), header.version_flag, | 
 |       header.nonce != nullptr, header.packet_number_length, | 
 |       header.retry_token_length_length, header.retry_token.length(), | 
 |       header.length_length); | 
 | } | 
 |  | 
 | size_t GetPacketHeaderSize( | 
 |     QuicTransportVersion version, | 
 |     QuicConnectionIdLength destination_connection_id_length, | 
 |     QuicConnectionIdLength source_connection_id_length, | 
 |     bool include_version, | 
 |     bool include_diversification_nonce, | 
 |     QuicPacketNumberLength packet_number_length, | 
 |     QuicVariableLengthIntegerLength retry_token_length_length, | 
 |     QuicByteCount retry_token_length, | 
 |     QuicVariableLengthIntegerLength length_length) { | 
 |   if (VersionHasIetfInvariantHeader(version)) { | 
 |     if (include_version) { | 
 |       // Long header. | 
 |       size_t size = kPacketHeaderTypeSize + kConnectionIdLengthSize + | 
 |                     destination_connection_id_length + | 
 |                     source_connection_id_length + packet_number_length + | 
 |                     kQuicVersionSize; | 
 |       if (include_diversification_nonce) { | 
 |         size += kDiversificationNonceSize; | 
 |       } | 
 |       if (VersionHasLengthPrefixedConnectionIds(version)) { | 
 |         size += kConnectionIdLengthSize; | 
 |       } | 
 |       QUICHE_DCHECK( | 
 |           QuicVersionHasLongHeaderLengths(version) || | 
 |           retry_token_length_length + retry_token_length + length_length == 0); | 
 |       if (QuicVersionHasLongHeaderLengths(version)) { | 
 |         size += retry_token_length_length + retry_token_length + length_length; | 
 |       } | 
 |       return size; | 
 |     } | 
 |     // Short header. | 
 |     return kPacketHeaderTypeSize + destination_connection_id_length + | 
 |            packet_number_length; | 
 |   } | 
 |   // Google QUIC versions <= 43 can only carry one connection ID. | 
 |   QUICHE_DCHECK(destination_connection_id_length == 0 || | 
 |                 source_connection_id_length == 0); | 
 |   return kPublicFlagsSize + destination_connection_id_length + | 
 |          source_connection_id_length + | 
 |          (include_version ? kQuicVersionSize : 0) + packet_number_length + | 
 |          (include_diversification_nonce ? kDiversificationNonceSize : 0); | 
 | } | 
 |  | 
 | size_t GetStartOfEncryptedData(QuicTransportVersion version, | 
 |                                const QuicPacketHeader& header) { | 
 |   return GetPacketHeaderSize(version, header); | 
 | } | 
 |  | 
 | size_t GetStartOfEncryptedData( | 
 |     QuicTransportVersion version, | 
 |     QuicConnectionIdLength destination_connection_id_length, | 
 |     QuicConnectionIdLength source_connection_id_length, | 
 |     bool include_version, | 
 |     bool include_diversification_nonce, | 
 |     QuicPacketNumberLength packet_number_length, | 
 |     QuicVariableLengthIntegerLength retry_token_length_length, | 
 |     QuicByteCount retry_token_length, | 
 |     QuicVariableLengthIntegerLength length_length) { | 
 |   // Encryption starts before private flags. | 
 |   return GetPacketHeaderSize( | 
 |       version, destination_connection_id_length, source_connection_id_length, | 
 |       include_version, include_diversification_nonce, packet_number_length, | 
 |       retry_token_length_length, retry_token_length, length_length); | 
 | } | 
 |  | 
 | QuicPacketHeader::QuicPacketHeader() | 
 |     : destination_connection_id(EmptyQuicConnectionId()), | 
 |       destination_connection_id_included(CONNECTION_ID_PRESENT), | 
 |       source_connection_id(EmptyQuicConnectionId()), | 
 |       source_connection_id_included(CONNECTION_ID_ABSENT), | 
 |       reset_flag(false), | 
 |       version_flag(false), | 
 |       has_possible_stateless_reset_token(false), | 
 |       packet_number_length(PACKET_4BYTE_PACKET_NUMBER), | 
 |       version(UnsupportedQuicVersion()), | 
 |       nonce(nullptr), | 
 |       form(GOOGLE_QUIC_PACKET), | 
 |       long_packet_type(INITIAL), | 
 |       possible_stateless_reset_token({}), | 
 |       retry_token_length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), | 
 |       retry_token(absl::string_view()), | 
 |       length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), | 
 |       remaining_packet_length(0) {} | 
 |  | 
 | QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default; | 
 |  | 
 | QuicPacketHeader::~QuicPacketHeader() {} | 
 |  | 
 | QuicPacketHeader& QuicPacketHeader::operator=(const QuicPacketHeader& other) = | 
 |     default; | 
 |  | 
 | QuicPublicResetPacket::QuicPublicResetPacket() | 
 |     : connection_id(EmptyQuicConnectionId()), nonce_proof(0) {} | 
 |  | 
 | QuicPublicResetPacket::QuicPublicResetPacket(QuicConnectionId connection_id) | 
 |     : connection_id(connection_id), nonce_proof(0) {} | 
 |  | 
 | QuicVersionNegotiationPacket::QuicVersionNegotiationPacket() | 
 |     : connection_id(EmptyQuicConnectionId()) {} | 
 |  | 
 | QuicVersionNegotiationPacket::QuicVersionNegotiationPacket( | 
 |     QuicConnectionId connection_id) | 
 |     : connection_id(connection_id) {} | 
 |  | 
 | QuicVersionNegotiationPacket::QuicVersionNegotiationPacket( | 
 |     const QuicVersionNegotiationPacket& other) = default; | 
 |  | 
 | QuicVersionNegotiationPacket::~QuicVersionNegotiationPacket() {} | 
 |  | 
 | QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket() | 
 |     : stateless_reset_token({}) {} | 
 |  | 
 | QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket( | 
 |     const QuicPacketHeader& header, | 
 |     StatelessResetToken token) | 
 |     : header(header), stateless_reset_token(token) {} | 
 |  | 
 | QuicIetfStatelessResetPacket::QuicIetfStatelessResetPacket( | 
 |     const QuicIetfStatelessResetPacket& other) = default; | 
 |  | 
 | QuicIetfStatelessResetPacket::~QuicIetfStatelessResetPacket() {} | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, const QuicPacketHeader& header) { | 
 |   os << "{ destination_connection_id: " << header.destination_connection_id | 
 |      << " (" | 
 |      << (header.destination_connection_id_included == CONNECTION_ID_PRESENT | 
 |              ? "present" | 
 |              : "absent") | 
 |      << "), source_connection_id: " << header.source_connection_id << " (" | 
 |      << (header.source_connection_id_included == CONNECTION_ID_PRESENT | 
 |              ? "present" | 
 |              : "absent") | 
 |      << "), packet_number_length: " | 
 |      << static_cast<int>(header.packet_number_length) | 
 |      << ", reset_flag: " << header.reset_flag | 
 |      << ", version_flag: " << header.version_flag; | 
 |   if (header.version_flag) { | 
 |     os << ", version: " << ParsedQuicVersionToString(header.version); | 
 |     if (header.long_packet_type != INVALID_PACKET_TYPE) { | 
 |       os << ", long_packet_type: " | 
 |          << QuicUtils::QuicLongHeaderTypetoString(header.long_packet_type); | 
 |     } | 
 |     if (header.retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { | 
 |       os << ", retry_token_length_length: " | 
 |          << static_cast<int>(header.retry_token_length_length); | 
 |     } | 
 |     if (header.retry_token.length() != 0) { | 
 |       os << ", retry_token_length: " << header.retry_token.length(); | 
 |     } | 
 |     if (header.length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { | 
 |       os << ", length_length: " << static_cast<int>(header.length_length); | 
 |     } | 
 |     if (header.remaining_packet_length != 0) { | 
 |       os << ", remaining_packet_length: " << header.remaining_packet_length; | 
 |     } | 
 |   } | 
 |   if (header.nonce != nullptr) { | 
 |     os << ", diversification_nonce: " | 
 |        << absl::BytesToHexString( | 
 |               absl::string_view(header.nonce->data(), header.nonce->size())); | 
 |   } | 
 |   os << ", packet_number: " << header.packet_number << " }\n"; | 
 |   return os; | 
 | } | 
 |  | 
 | QuicData::QuicData(const char* buffer, size_t length) | 
 |     : buffer_(buffer), length_(length), owns_buffer_(false) {} | 
 |  | 
 | QuicData::QuicData(const char* buffer, size_t length, bool owns_buffer) | 
 |     : buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {} | 
 |  | 
 | QuicData::QuicData(absl::string_view packet_data) | 
 |     : buffer_(packet_data.data()), | 
 |       length_(packet_data.length()), | 
 |       owns_buffer_(false) {} | 
 |  | 
 | QuicData::~QuicData() { | 
 |   if (owns_buffer_) { | 
 |     delete[] const_cast<char*>(buffer_); | 
 |   } | 
 | } | 
 |  | 
 | QuicPacket::QuicPacket( | 
 |     char* buffer, | 
 |     size_t length, | 
 |     bool owns_buffer, | 
 |     QuicConnectionIdLength destination_connection_id_length, | 
 |     QuicConnectionIdLength source_connection_id_length, | 
 |     bool includes_version, | 
 |     bool includes_diversification_nonce, | 
 |     QuicPacketNumberLength packet_number_length, | 
 |     QuicVariableLengthIntegerLength retry_token_length_length, | 
 |     QuicByteCount retry_token_length, | 
 |     QuicVariableLengthIntegerLength length_length) | 
 |     : QuicData(buffer, length, owns_buffer), | 
 |       buffer_(buffer), | 
 |       destination_connection_id_length_(destination_connection_id_length), | 
 |       source_connection_id_length_(source_connection_id_length), | 
 |       includes_version_(includes_version), | 
 |       includes_diversification_nonce_(includes_diversification_nonce), | 
 |       packet_number_length_(packet_number_length), | 
 |       retry_token_length_length_(retry_token_length_length), | 
 |       retry_token_length_(retry_token_length), | 
 |       length_length_(length_length) {} | 
 |  | 
 | QuicPacket::QuicPacket(QuicTransportVersion /*version*/, | 
 |                        char* buffer, | 
 |                        size_t length, | 
 |                        bool owns_buffer, | 
 |                        const QuicPacketHeader& header) | 
 |     : QuicPacket(buffer, | 
 |                  length, | 
 |                  owns_buffer, | 
 |                  GetIncludedDestinationConnectionIdLength(header), | 
 |                  GetIncludedSourceConnectionIdLength(header), | 
 |                  header.version_flag, | 
 |                  header.nonce != nullptr, | 
 |                  header.packet_number_length, | 
 |                  header.retry_token_length_length, | 
 |                  header.retry_token.length(), | 
 |                  header.length_length) {} | 
 |  | 
 | QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length) | 
 |     : QuicData(buffer, length) {} | 
 |  | 
 | QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, | 
 |                                          size_t length, | 
 |                                          bool owns_buffer) | 
 |     : QuicData(buffer, length, owns_buffer) {} | 
 |  | 
 | QuicEncryptedPacket::QuicEncryptedPacket(absl::string_view data) | 
 |     : QuicData(data) {} | 
 |  | 
 | std::unique_ptr<QuicEncryptedPacket> QuicEncryptedPacket::Clone() const { | 
 |   char* buffer = new char[this->length()]; | 
 |   memcpy(buffer, this->data(), this->length()); | 
 |   return std::make_unique<QuicEncryptedPacket>(buffer, this->length(), true); | 
 | } | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, const QuicEncryptedPacket& s) { | 
 |   os << s.length() << "-byte data"; | 
 |   return os; | 
 | } | 
 |  | 
 | QuicReceivedPacket::QuicReceivedPacket(const char* buffer, | 
 |                                        size_t length, | 
 |                                        QuicTime receipt_time) | 
 |     : QuicReceivedPacket(buffer, | 
 |                          length, | 
 |                          receipt_time, | 
 |                          false /* owns_buffer */) {} | 
 |  | 
 | QuicReceivedPacket::QuicReceivedPacket(const char* buffer, | 
 |                                        size_t length, | 
 |                                        QuicTime receipt_time, | 
 |                                        bool owns_buffer) | 
 |     : QuicReceivedPacket(buffer, | 
 |                          length, | 
 |                          receipt_time, | 
 |                          owns_buffer, | 
 |                          0 /* ttl */, | 
 |                          true /* ttl_valid */) {} | 
 |  | 
 | QuicReceivedPacket::QuicReceivedPacket(const char* buffer, | 
 |                                        size_t length, | 
 |                                        QuicTime receipt_time, | 
 |                                        bool owns_buffer, | 
 |                                        int ttl, | 
 |                                        bool ttl_valid) | 
 |     : quic::QuicReceivedPacket(buffer, | 
 |                                length, | 
 |                                receipt_time, | 
 |                                owns_buffer, | 
 |                                ttl, | 
 |                                ttl_valid, | 
 |                                nullptr /* packet_headers */, | 
 |                                0 /* headers_length */, | 
 |                                false /* owns_header_buffer */) {} | 
 |  | 
 | QuicReceivedPacket::QuicReceivedPacket(const char* buffer, | 
 |                                        size_t length, | 
 |                                        QuicTime receipt_time, | 
 |                                        bool owns_buffer, | 
 |                                        int ttl, | 
 |                                        bool ttl_valid, | 
 |                                        char* packet_headers, | 
 |                                        size_t headers_length, | 
 |                                        bool owns_header_buffer) | 
 |     : QuicEncryptedPacket(buffer, length, owns_buffer), | 
 |       receipt_time_(receipt_time), | 
 |       ttl_(ttl_valid ? ttl : -1), | 
 |       packet_headers_(packet_headers), | 
 |       headers_length_(headers_length), | 
 |       owns_header_buffer_(owns_header_buffer) {} | 
 |  | 
 | QuicReceivedPacket::~QuicReceivedPacket() { | 
 |   if (owns_header_buffer_) { | 
 |     delete[] static_cast<char*>(packet_headers_); | 
 |   } | 
 | } | 
 |  | 
 | std::unique_ptr<QuicReceivedPacket> QuicReceivedPacket::Clone() const { | 
 |   char* buffer = new char[this->length()]; | 
 |   memcpy(buffer, this->data(), this->length()); | 
 |   if (this->packet_headers()) { | 
 |     char* headers_buffer = new char[this->headers_length()]; | 
 |     memcpy(headers_buffer, this->packet_headers(), this->headers_length()); | 
 |     return std::make_unique<QuicReceivedPacket>( | 
 |         buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0, | 
 |         headers_buffer, this->headers_length(), true); | 
 |   } | 
 |  | 
 |   return std::make_unique<QuicReceivedPacket>( | 
 |       buffer, this->length(), receipt_time(), true, ttl(), ttl() >= 0); | 
 | } | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, const QuicReceivedPacket& s) { | 
 |   os << s.length() << "-byte data"; | 
 |   return os; | 
 | } | 
 |  | 
 | absl::string_view QuicPacket::AssociatedData( | 
 |     QuicTransportVersion version) const { | 
 |   return absl::string_view( | 
 |       data(), | 
 |       GetStartOfEncryptedData(version, destination_connection_id_length_, | 
 |                               source_connection_id_length_, includes_version_, | 
 |                               includes_diversification_nonce_, | 
 |                               packet_number_length_, retry_token_length_length_, | 
 |                               retry_token_length_, length_length_)); | 
 | } | 
 |  | 
 | absl::string_view QuicPacket::Plaintext(QuicTransportVersion version) const { | 
 |   const size_t start_of_encrypted_data = GetStartOfEncryptedData( | 
 |       version, destination_connection_id_length_, source_connection_id_length_, | 
 |       includes_version_, includes_diversification_nonce_, packet_number_length_, | 
 |       retry_token_length_length_, retry_token_length_, length_length_); | 
 |   return absl::string_view(data() + start_of_encrypted_data, | 
 |                            length() - start_of_encrypted_data); | 
 | } | 
 |  | 
 | SerializedPacket::SerializedPacket(QuicPacketNumber packet_number, | 
 |                                    QuicPacketNumberLength packet_number_length, | 
 |                                    const char* encrypted_buffer, | 
 |                                    QuicPacketLength encrypted_length, | 
 |                                    bool has_ack, | 
 |                                    bool has_stop_waiting) | 
 |     : encrypted_buffer(encrypted_buffer), | 
 |       encrypted_length(encrypted_length), | 
 |       has_crypto_handshake(NOT_HANDSHAKE), | 
 |       packet_number(packet_number), | 
 |       packet_number_length(packet_number_length), | 
 |       encryption_level(ENCRYPTION_INITIAL), | 
 |       has_ack(has_ack), | 
 |       has_stop_waiting(has_stop_waiting), | 
 |       transmission_type(NOT_RETRANSMISSION), | 
 |       has_ack_frame_copy(false), | 
 |       has_ack_frequency(false), | 
 |       has_message(false), | 
 |       fate(SEND_TO_WRITER) {} | 
 |  | 
 | SerializedPacket::SerializedPacket(SerializedPacket&& other) | 
 |     : has_crypto_handshake(other.has_crypto_handshake), | 
 |       packet_number(other.packet_number), | 
 |       packet_number_length(other.packet_number_length), | 
 |       encryption_level(other.encryption_level), | 
 |       has_ack(other.has_ack), | 
 |       has_stop_waiting(other.has_stop_waiting), | 
 |       transmission_type(other.transmission_type), | 
 |       largest_acked(other.largest_acked), | 
 |       has_ack_frame_copy(other.has_ack_frame_copy), | 
 |       has_ack_frequency(other.has_ack_frequency), | 
 |       has_message(other.has_message), | 
 |       fate(other.fate), | 
 |       peer_address(other.peer_address) { | 
 |   if (this != &other) { | 
 |     if (release_encrypted_buffer && encrypted_buffer != nullptr) { | 
 |       release_encrypted_buffer(encrypted_buffer); | 
 |     } | 
 |     encrypted_buffer = other.encrypted_buffer; | 
 |     encrypted_length = other.encrypted_length; | 
 |     release_encrypted_buffer = std::move(other.release_encrypted_buffer); | 
 |     other.release_encrypted_buffer = nullptr; | 
 |  | 
 |     retransmittable_frames.swap(other.retransmittable_frames); | 
 |     nonretransmittable_frames.swap(other.nonretransmittable_frames); | 
 |   } | 
 | } | 
 |  | 
 | SerializedPacket::~SerializedPacket() { | 
 |   if (release_encrypted_buffer && encrypted_buffer != nullptr) { | 
 |     release_encrypted_buffer(encrypted_buffer); | 
 |   } | 
 |  | 
 |   if (!retransmittable_frames.empty()) { | 
 |     DeleteFrames(&retransmittable_frames); | 
 |   } | 
 |   for (auto& frame : nonretransmittable_frames) { | 
 |     if (!has_ack_frame_copy && frame.type == ACK_FRAME) { | 
 |       // Do not delete ack frame if the packet does not own a copy of it. | 
 |       continue; | 
 |     } | 
 |     DeleteFrame(&frame); | 
 |   } | 
 | } | 
 |  | 
 | SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, | 
 |                                        QuicBufferAllocator* allocator, | 
 |                                        bool copy_buffer) { | 
 |   SerializedPacket* copy = new SerializedPacket( | 
 |       serialized.packet_number, serialized.packet_number_length, | 
 |       serialized.encrypted_buffer, serialized.encrypted_length, | 
 |       serialized.has_ack, serialized.has_stop_waiting); | 
 |   copy->has_crypto_handshake = serialized.has_crypto_handshake; | 
 |   copy->encryption_level = serialized.encryption_level; | 
 |   copy->transmission_type = serialized.transmission_type; | 
 |   copy->largest_acked = serialized.largest_acked; | 
 |   copy->has_ack_frequency = serialized.has_ack_frequency; | 
 |   copy->has_message = serialized.has_message; | 
 |   copy->fate = serialized.fate; | 
 |   copy->peer_address = serialized.peer_address; | 
 |  | 
 |   if (copy_buffer) { | 
 |     copy->encrypted_buffer = CopyBuffer(serialized); | 
 |     copy->release_encrypted_buffer = [](const char* p) { delete[] p; }; | 
 |   } | 
 |   // Copy underlying frames. | 
 |   copy->retransmittable_frames = | 
 |       CopyQuicFrames(allocator, serialized.retransmittable_frames); | 
 |   QUICHE_DCHECK(copy->nonretransmittable_frames.empty()); | 
 |   for (const auto& frame : serialized.nonretransmittable_frames) { | 
 |     if (frame.type == ACK_FRAME) { | 
 |       copy->has_ack_frame_copy = true; | 
 |     } | 
 |     copy->nonretransmittable_frames.push_back(CopyQuicFrame(allocator, frame)); | 
 |   } | 
 |   return copy; | 
 | } | 
 |  | 
 | char* CopyBuffer(const SerializedPacket& packet) { | 
 |   return CopyBuffer(packet.encrypted_buffer, packet.encrypted_length); | 
 | } | 
 |  | 
 | char* CopyBuffer(const char* encrypted_buffer, | 
 |                  QuicPacketLength encrypted_length) { | 
 |   char* dst_buffer = new char[encrypted_length]; | 
 |   memcpy(dst_buffer, encrypted_buffer, encrypted_length); | 
 |   return dst_buffer; | 
 | } | 
 |  | 
 | ReceivedPacketInfo::ReceivedPacketInfo(const QuicSocketAddress& self_address, | 
 |                                        const QuicSocketAddress& peer_address, | 
 |                                        const QuicReceivedPacket& packet) | 
 |     : self_address(self_address), | 
 |       peer_address(peer_address), | 
 |       packet(packet), | 
 |       form(GOOGLE_QUIC_PACKET), | 
 |       long_packet_type(INVALID_PACKET_TYPE), | 
 |       version_flag(false), | 
 |       use_length_prefix(false), | 
 |       version_label(0), | 
 |       version(ParsedQuicVersion::Unsupported()), | 
 |       destination_connection_id(EmptyQuicConnectionId()), | 
 |       source_connection_id(EmptyQuicConnectionId()) {} | 
 |  | 
 | ReceivedPacketInfo::~ReceivedPacketInfo() {} | 
 |  | 
 | std::string ReceivedPacketInfo::ToString() const { | 
 |   std::string output = | 
 |       absl::StrCat("{ self_address: ", self_address.ToString(), | 
 |                    ", peer_address: ", peer_address.ToString(), | 
 |                    ", packet_length: ", packet.length(), | 
 |                    ", header_format: ", form, ", version_flag: ", version_flag); | 
 |   if (version_flag) { | 
 |     absl::StrAppend(&output, ", version: ", ParsedQuicVersionToString(version)); | 
 |   } | 
 |   absl::StrAppend( | 
 |       &output, | 
 |       ", destination_connection_id: ", destination_connection_id.ToString(), | 
 |       ", source_connection_id: ", source_connection_id.ToString(), " }\n"); | 
 |   return output; | 
 | } | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, | 
 |                          const ReceivedPacketInfo& packet_info) { | 
 |   os << packet_info.ToString(); | 
 |   return os; | 
 | } | 
 |  | 
 | }  // namespace quic |