// 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 "net/quic/quic_protocol.h"

#include "base/stl_util.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"

using base::StringPiece;
using std::map;
using std::numeric_limits;
using std::ostream;
using std::string;

namespace net {

const char* const kFinalOffsetHeaderKey = ":final-offset";

size_t GetPacketHeaderSize(const QuicPacketHeader& header) {
  return GetPacketHeaderSize(header.public_header.connection_id_length,
                             header.public_header.version_flag,
                             header.public_header.multipath_flag,
                             header.public_header.packet_number_length);
}

size_t GetPacketHeaderSize(QuicConnectionIdLength connection_id_length,
                           bool include_version,
                           bool include_path_id,
                           QuicPacketNumberLength packet_number_length) {
  return kPublicFlagsSize + connection_id_length +
         (include_version ? kQuicVersionSize : 0) +
         (include_path_id ? kQuicPathIdSize : 0) + packet_number_length +
         kPrivateFlagsSize;
}

size_t GetStartOfEncryptedData(const QuicPacketHeader& header) {
  return GetPacketHeaderSize(header) - kPrivateFlagsSize;
}

size_t GetStartOfEncryptedData(QuicConnectionIdLength connection_id_length,
                               bool include_version,
                               bool include_path_id,
                               QuicPacketNumberLength packet_number_length) {
  // Encryption starts before private flags.
  return GetPacketHeaderSize(connection_id_length, include_version,
                             include_path_id, packet_number_length) -
         kPrivateFlagsSize;
}

QuicPacketPublicHeader::QuicPacketPublicHeader()
    : connection_id(0),
      connection_id_length(PACKET_8BYTE_CONNECTION_ID),
      multipath_flag(false),
      reset_flag(false),
      version_flag(false),
      packet_number_length(PACKET_6BYTE_PACKET_NUMBER) {}

QuicPacketPublicHeader::QuicPacketPublicHeader(
    const QuicPacketPublicHeader& other)
    : connection_id(other.connection_id),
      connection_id_length(other.connection_id_length),
      multipath_flag(other.multipath_flag),
      reset_flag(other.reset_flag),
      version_flag(other.version_flag),
      packet_number_length(other.packet_number_length),
      versions(other.versions) {}

QuicPacketPublicHeader::~QuicPacketPublicHeader() {}

QuicPacketHeader::QuicPacketHeader()
    : packet_number(0),
      path_id(kDefaultPathId),
      entropy_flag(false),
      entropy_hash(0),
      fec_flag(false),
      is_in_fec_group(NOT_IN_FEC_GROUP),
      fec_group(0) {}

QuicPacketHeader::QuicPacketHeader(const QuicPacketPublicHeader& header)
    : public_header(header),
      packet_number(0),
      path_id(kDefaultPathId),
      entropy_flag(false),
      entropy_hash(0),
      fec_flag(false),
      is_in_fec_group(NOT_IN_FEC_GROUP),
      fec_group(0) {}

QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default;

QuicPublicResetPacket::QuicPublicResetPacket()
    : nonce_proof(0), rejected_packet_number(0) {}

QuicPublicResetPacket::QuicPublicResetPacket(
    const QuicPacketPublicHeader& header)
    : public_header(header), nonce_proof(0), rejected_packet_number(0) {}

QuicBufferAllocator::~QuicBufferAllocator() = default;

void StreamBufferDeleter::operator()(char* buffer) const {
  if (allocator_ != nullptr && buffer != nullptr) {
    allocator_->Delete(buffer);
  }
}

UniqueStreamBuffer NewStreamBuffer(QuicBufferAllocator* allocator,
                                   size_t size) {
  return UniqueStreamBuffer(allocator->New(size),
                            StreamBufferDeleter(allocator));
}

QuicStreamFrame::QuicStreamFrame()
    : QuicStreamFrame(0, false, 0, nullptr, 0, nullptr) {}

QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                 bool fin,
                                 QuicStreamOffset offset,
                                 StringPiece data)
    : QuicStreamFrame(stream_id,
                      fin,
                      offset,
                      data.data(),
                      data.length(),
                      nullptr) {}

QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                 bool fin,
                                 QuicStreamOffset offset,
                                 QuicPacketLength frame_length,
                                 UniqueStreamBuffer buffer)
    : QuicStreamFrame(stream_id,
                      fin,
                      offset,
                      nullptr,
                      frame_length,
                      std::move(buffer)) {
  DCHECK(this->buffer != nullptr);
  DCHECK_EQ(frame_buffer, this->buffer.get());
}

QuicStreamFrame::QuicStreamFrame(QuicStreamId stream_id,
                                 bool fin,
                                 QuicStreamOffset offset,
                                 const char* frame_buffer,
                                 QuicPacketLength frame_length,
                                 UniqueStreamBuffer buffer)
    : stream_id(stream_id),
      fin(fin),
      frame_length(frame_length),
      frame_buffer(frame_buffer),
      offset(offset),
      buffer(std::move(buffer)) {
  if (this->buffer != nullptr) {
    DCHECK(frame_buffer == nullptr);
    this->frame_buffer = this->buffer.get();
  }
}

QuicStreamFrame::~QuicStreamFrame() {}

uint32_t MakeQuicTag(char a, char b, char c, char d) {
  return static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 |
         static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24;
}

bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag) {
  return std::find(tag_vector.begin(), tag_vector.end(), tag) !=
         tag_vector.end();
}

QuicVersionVector QuicSupportedVersions() {
  QuicVersionVector supported_versions;
  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
    supported_versions.push_back(kSupportedQuicVersions[i]);
  }
  return supported_versions;
}

QuicTag QuicVersionToQuicTag(const QuicVersion version) {
  switch (version) {
    case QUIC_VERSION_25:
      return MakeQuicTag('Q', '0', '2', '5');
    case QUIC_VERSION_26:
      return MakeQuicTag('Q', '0', '2', '6');
    case QUIC_VERSION_27:
      return MakeQuicTag('Q', '0', '2', '7');
    case QUIC_VERSION_28:
      return MakeQuicTag('Q', '0', '2', '8');
    case QUIC_VERSION_29:
      return MakeQuicTag('Q', '0', '2', '9');
    case QUIC_VERSION_30:
      return MakeQuicTag('Q', '0', '3', '0');
    case QUIC_VERSION_31:
      return MakeQuicTag('Q', '0', '3', '1');
    case QUIC_VERSION_32:
      return MakeQuicTag('Q', '0', '3', '2');
    default:
      // This shold be an ERROR because we should never attempt to convert an
      // invalid QuicVersion to be written to the wire.
      LOG(ERROR) << "Unsupported QuicVersion: " << version;
      return 0;
  }
}

QuicVersion QuicTagToQuicVersion(const QuicTag version_tag) {
  for (size_t i = 0; i < arraysize(kSupportedQuicVersions); ++i) {
    if (version_tag == QuicVersionToQuicTag(kSupportedQuicVersions[i])) {
      return kSupportedQuicVersions[i];
    }
  }
  // Reading from the client so this should not be considered an ERROR.
  DVLOG(1) << "Unsupported QuicTag version: "
           << QuicUtils::TagToString(version_tag);
  return QUIC_VERSION_UNSUPPORTED;
}

#define RETURN_STRING_LITERAL(x) \
  case x:                        \
    return #x

string QuicVersionToString(const QuicVersion version) {
  switch (version) {
    RETURN_STRING_LITERAL(QUIC_VERSION_25);
    RETURN_STRING_LITERAL(QUIC_VERSION_26);
    RETURN_STRING_LITERAL(QUIC_VERSION_27);
    RETURN_STRING_LITERAL(QUIC_VERSION_28);
    RETURN_STRING_LITERAL(QUIC_VERSION_29);
    RETURN_STRING_LITERAL(QUIC_VERSION_30);
    RETURN_STRING_LITERAL(QUIC_VERSION_31);
    RETURN_STRING_LITERAL(QUIC_VERSION_32);
    default:
      return "QUIC_VERSION_UNSUPPORTED";
  }
}

string QuicVersionVectorToString(const QuicVersionVector& versions) {
  string result = "";
  for (size_t i = 0; i < versions.size(); ++i) {
    if (i != 0) {
      result.append(",");
    }
    result.append(QuicVersionToString(versions[i]));
  }
  return result;
}

ostream& operator<<(ostream& os, const Perspective& s) {
  if (s == Perspective::IS_SERVER) {
    os << "IS_SERVER";
  } else {
    os << "IS_CLIENT";
  }
  return os;
}

ostream& operator<<(ostream& os, const QuicPacketHeader& header) {
  os << "{ connection_id: " << header.public_header.connection_id
     << ", connection_id_length:" << header.public_header.connection_id_length
     << ", packet_number_length:" << header.public_header.packet_number_length
     << ", multipath_flag: " << header.public_header.multipath_flag
     << ", reset_flag: " << header.public_header.reset_flag
     << ", version_flag: " << header.public_header.version_flag;
  if (header.public_header.version_flag) {
    os << " version: ";
    for (size_t i = 0; i < header.public_header.versions.size(); ++i) {
      os << header.public_header.versions[i] << " ";
    }
  }
  os << ", fec_flag: " << header.fec_flag
     << ", entropy_flag: " << header.entropy_flag
     << ", entropy hash: " << static_cast<int>(header.entropy_hash)
     << ", path_id: " << header.path_id
     << ", packet_number: " << header.packet_number
     << ", is_in_fec_group:" << header.is_in_fec_group
     << ", fec_group: " << header.fec_group << "}\n";
  return os;
}

bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
                      QuicPacketNumber packet_number) {
  return packet_number > ack_frame.largest_observed ||
         ack_frame.missing_packets.Contains(packet_number);
}

QuicStopWaitingFrame::QuicStopWaitingFrame()
    : path_id(kDefaultPathId), entropy_hash(0), least_unacked(0) {}

QuicStopWaitingFrame::~QuicStopWaitingFrame() {}

QuicAckFrame::QuicAckFrame()
    : path_id(kDefaultPathId),
      entropy_hash(0),
      is_truncated(false),
      largest_observed(0),
      ack_delay_time(QuicTime::Delta::Infinite()) {}

QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default;

QuicAckFrame::~QuicAckFrame() {}

QuicRstStreamErrorCode AdjustErrorForVersion(QuicRstStreamErrorCode error_code,
                                             QuicVersion /*version*/) {
  return error_code;
}

QuicRstStreamFrame::QuicRstStreamFrame()
    : stream_id(0), error_code(QUIC_STREAM_NO_ERROR), byte_offset(0) {}

QuicRstStreamFrame::QuicRstStreamFrame(QuicStreamId stream_id,
                                       QuicRstStreamErrorCode error_code,
                                       QuicStreamOffset bytes_written)
    : stream_id(stream_id), error_code(error_code), byte_offset(bytes_written) {
  DCHECK_LE(error_code, numeric_limits<uint8_t>::max());
}

QuicConnectionCloseFrame::QuicConnectionCloseFrame()
    : error_code(QUIC_NO_ERROR) {}

QuicFrame::QuicFrame() {}

QuicFrame::QuicFrame(QuicPaddingFrame padding_frame)
    : type(PADDING_FRAME), padding_frame(padding_frame) {}

QuicFrame::QuicFrame(QuicStreamFrame* stream_frame)
    : type(STREAM_FRAME), stream_frame(stream_frame) {}

QuicFrame::QuicFrame(QuicAckFrame* frame) : type(ACK_FRAME), ack_frame(frame) {}

QuicFrame::QuicFrame(QuicMtuDiscoveryFrame frame)
    : type(MTU_DISCOVERY_FRAME), mtu_discovery_frame(frame) {}

QuicFrame::QuicFrame(QuicStopWaitingFrame* frame)
    : type(STOP_WAITING_FRAME), stop_waiting_frame(frame) {}

QuicFrame::QuicFrame(QuicPingFrame frame)
    : type(PING_FRAME), ping_frame(frame) {}

QuicFrame::QuicFrame(QuicRstStreamFrame* frame)
    : type(RST_STREAM_FRAME), rst_stream_frame(frame) {}

QuicFrame::QuicFrame(QuicConnectionCloseFrame* frame)
    : type(CONNECTION_CLOSE_FRAME), connection_close_frame(frame) {}

QuicFrame::QuicFrame(QuicGoAwayFrame* frame)
    : type(GOAWAY_FRAME), goaway_frame(frame) {}

QuicFrame::QuicFrame(QuicWindowUpdateFrame* frame)
    : type(WINDOW_UPDATE_FRAME), window_update_frame(frame) {}

QuicFrame::QuicFrame(QuicBlockedFrame* frame)
    : type(BLOCKED_FRAME), blocked_frame(frame) {}

QuicFrame::QuicFrame(QuicPathCloseFrame* frame)
    : type(PATH_CLOSE_FRAME), path_close_frame(frame) {}

ostream& operator<<(ostream& os, const QuicStopWaitingFrame& sent_info) {
  os << "entropy_hash: " << static_cast<int>(sent_info.entropy_hash)
     << " least_unacked: " << sent_info.least_unacked << "\n";
  return os;
}

PacketNumberQueue::const_iterator::const_iterator(
    IntervalSet<QuicPacketNumber>::const_iterator interval_set_iter,
    QuicPacketNumber first,
    QuicPacketNumber last)
    : interval_set_iter_(std::move(interval_set_iter)),
      current_(first),
      last_(last) {}

PacketNumberQueue::const_iterator::const_iterator(const const_iterator& other) =
    default;
// TODO(rtenneti): on windows RValue reference gives errors.
// PacketNumberQueue::const_iterator::const_iterator(const_iterator&& other) =
//    default;
PacketNumberQueue::const_iterator::~const_iterator() {}

PacketNumberQueue::const_iterator& PacketNumberQueue::const_iterator::operator=(
    const const_iterator& other) = default;
// TODO(rtenneti): on windows RValue reference gives errors.
// PacketNumberQueue::const_iterator&
// PacketNumberQueue::const_iterator::operator=(
//    const_iterator&& other) = default;

bool PacketNumberQueue::const_iterator::operator!=(
    const const_iterator& other) const {
  return current_ != other.current_;
}

bool PacketNumberQueue::const_iterator::operator==(
    const const_iterator& other) const {
  return current_ == other.current_;
}

PacketNumberQueue::const_iterator::value_type
    PacketNumberQueue::const_iterator::operator*() const {
  return current_;
}

PacketNumberQueue::const_iterator& PacketNumberQueue::const_iterator::
operator++() {
  ++current_;
  if (current_ < last_) {
    if (current_ >= interval_set_iter_->max()) {
      ++interval_set_iter_;
      current_ = interval_set_iter_->min();
    }
  } else {
    current_ = last_;
  }
  return *this;
}

PacketNumberQueue::const_iterator PacketNumberQueue::const_iterator::operator++(
    int /* postincrement */) {
  PacketNumberQueue::const_iterator preincrement(*this);
  operator++();
  return preincrement;
}

PacketNumberQueue::PacketNumberQueue() = default;
PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default;
// TODO(rtenneti): on windows RValue reference gives errors.
// PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default;
PacketNumberQueue::~PacketNumberQueue() {}

PacketNumberQueue& PacketNumberQueue::operator=(
    const PacketNumberQueue& other) = default;
// TODO(rtenneti): on windows RValue reference gives errors.
// PacketNumberQueue& PacketNumberQueue::operator=(PacketNumberQueue&& other) =
//    default;

void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
  packet_number_intervals_.Add(packet_number, packet_number + 1);
}

void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
  packet_number_intervals_.Add(lower, higher);
}

void PacketNumberQueue::Remove(QuicPacketNumber packet_number) {
  packet_number_intervals_.Difference(packet_number, packet_number + 1);
}

bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
  if (Empty()) {
    return false;
  }
  const QuicPacketNumber old_min = Min();
  packet_number_intervals_.Difference(0, higher);
  return Empty() || old_min != Min();
}

bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
  return packet_number_intervals_.Contains(packet_number);
}

bool PacketNumberQueue::Empty() const {
  return packet_number_intervals_.Empty();
}

QuicPacketNumber PacketNumberQueue::Min() const {
  DCHECK(!Empty());
  return packet_number_intervals_.begin()->min();
}

QuicPacketNumber PacketNumberQueue::Max() const {
  DCHECK(!Empty());
  return packet_number_intervals_.rbegin()->max() - 1;
}

size_t PacketNumberQueue::NumPacketsSlow() const {
  size_t num_packets = 0;
  for (const auto& interval : packet_number_intervals_) {
    num_packets += interval.Length();
  }
  return num_packets;
}

PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
  QuicPacketNumber first;
  QuicPacketNumber last;
  if (packet_number_intervals_.Empty()) {
    first = 0;
    last = 0;
  } else {
    first = packet_number_intervals_.begin()->min();
    last = packet_number_intervals_.rbegin()->max();
  }
  return const_iterator(packet_number_intervals_.begin(), first, last);
}

PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
  QuicPacketNumber last = packet_number_intervals_.Empty()
                              ? 0
                              : packet_number_intervals_.rbegin()->max();
  return const_iterator(packet_number_intervals_.end(), last, last);
}

PacketNumberQueue::const_iterator PacketNumberQueue::lower_bound(
    QuicPacketNumber packet_number) const {
  QuicPacketNumber first;
  QuicPacketNumber last;
  if (packet_number_intervals_.Empty()) {
    first = 0;
    last = 0;
    return const_iterator(packet_number_intervals_.begin(), first, last);
  }
  if (!packet_number_intervals_.Contains(packet_number)) {
    return end();
  }
  IntervalSet<QuicPacketNumber>::const_iterator it =
      packet_number_intervals_.Find(packet_number);
  first = packet_number;
  last = packet_number_intervals_.rbegin()->max();
  return const_iterator(it, first, last);
}

ostream& operator<<(ostream& os, const PacketNumberQueue& q) {
  for (QuicPacketNumber packet_number : q) {
    os << packet_number << " ";
  }
  return os;
}

ostream& operator<<(ostream& os, const QuicAckFrame& ack_frame) {
  os << "entropy_hash: " << static_cast<int>(ack_frame.entropy_hash)
     << " largest_observed: " << ack_frame.largest_observed
     << " ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds()
     << " missing_packets: [ " << ack_frame.missing_packets
     << " ] is_truncated: " << ack_frame.is_truncated
     << " received_packets: [ ";
  for (const std::pair<QuicPacketNumber, QuicTime>& p :
       ack_frame.received_packet_times) {
    os << p.first << " at " << p.second.ToDebuggingValue() << " ";
  }
  os << " ]\n";
  return os;
}

ostream& operator<<(ostream& os, const QuicFrame& frame) {
  switch (frame.type) {
    case PADDING_FRAME: {
      os << "type { PADDING_FRAME } ";
      break;
    }
    case RST_STREAM_FRAME: {
      os << "type { RST_STREAM_FRAME } " << *(frame.rst_stream_frame);
      break;
    }
    case CONNECTION_CLOSE_FRAME: {
      os << "type { CONNECTION_CLOSE_FRAME } "
         << *(frame.connection_close_frame);
      break;
    }
    case GOAWAY_FRAME: {
      os << "type { GOAWAY_FRAME } " << *(frame.goaway_frame);
      break;
    }
    case WINDOW_UPDATE_FRAME: {
      os << "type { WINDOW_UPDATE_FRAME } " << *(frame.window_update_frame);
      break;
    }
    case BLOCKED_FRAME: {
      os << "type { BLOCKED_FRAME } " << *(frame.blocked_frame);
      break;
    }
    case STREAM_FRAME: {
      os << "type { STREAM_FRAME } " << *(frame.stream_frame);
      break;
    }
    case ACK_FRAME: {
      os << "type { ACK_FRAME } " << *(frame.ack_frame);
      break;
    }
    case STOP_WAITING_FRAME: {
      os << "type { STOP_WAITING_FRAME } " << *(frame.stop_waiting_frame);
      break;
    }
    case PING_FRAME: {
      os << "type { PING_FRAME } ";
      break;
    }
    case MTU_DISCOVERY_FRAME: {
      os << "type { MTU_DISCOVERY_FRAME } ";
      break;
    }
    case PATH_CLOSE_FRAME: {
      os << "type { PATH_CLOSE_FRAME } " << *(frame.path_close_frame);
      break;
    }
    default: {
      LOG(ERROR) << "Unknown frame type: " << frame.type;
      break;
    }
  }
  return os;
}

ostream& operator<<(ostream& os, const QuicRstStreamFrame& rst_frame) {
  os << "stream_id { " << rst_frame.stream_id << " } "
     << "error_code { " << rst_frame.error_code << " }\n";
  return os;
}

ostream& operator<<(ostream& os,
                    const QuicConnectionCloseFrame& connection_close_frame) {
  os << "error_code { " << connection_close_frame.error_code << " } "
     << "error_details { " << connection_close_frame.error_details << " }\n";
  return os;
}

ostream& operator<<(ostream& os, const QuicGoAwayFrame& goaway_frame) {
  os << "error_code { " << goaway_frame.error_code << " } "
     << "last_good_stream_id { " << goaway_frame.last_good_stream_id << " } "
     << "reason_phrase { " << goaway_frame.reason_phrase << " }\n";
  return os;
}

ostream& operator<<(ostream& os,
                    const QuicWindowUpdateFrame& window_update_frame) {
  os << "stream_id { " << window_update_frame.stream_id << " } "
     << "byte_offset { " << window_update_frame.byte_offset << " }\n";
  return os;
}

ostream& operator<<(ostream& os, const QuicBlockedFrame& blocked_frame) {
  os << "stream_id { " << blocked_frame.stream_id << " }\n";
  return os;
}

ostream& operator<<(ostream& os, const QuicPathCloseFrame& path_close_frame) {
  os << "path_id { " << path_close_frame.path_id << " }\n";
  return os;
}

ostream& operator<<(ostream& os, const QuicStreamFrame& stream_frame) {
  os << "stream_id { " << stream_frame.stream_id << " } "
     << "fin { " << stream_frame.fin << " } "
     << "offset { " << stream_frame.offset << " } "
     << "length { " << stream_frame.frame_length << " }\n";
  return os;
}

QuicGoAwayFrame::QuicGoAwayFrame()
    : error_code(QUIC_NO_ERROR), last_good_stream_id(0) {}

QuicGoAwayFrame::QuicGoAwayFrame(QuicErrorCode error_code,
                                 QuicStreamId last_good_stream_id,
                                 const string& reason)
    : error_code(error_code),
      last_good_stream_id(last_good_stream_id),
      reason_phrase(reason) {
  DCHECK_LE(error_code, numeric_limits<uint8_t>::max());
}

QuicData::QuicData(const char* buffer, size_t length)
    : buffer_(buffer), length_(length), owns_buffer_(false) {}

QuicData::QuicData(char* buffer, size_t length, bool owns_buffer)
    : buffer_(buffer), length_(length), owns_buffer_(owns_buffer) {}

QuicData::~QuicData() {
  if (owns_buffer_) {
    delete[] const_cast<char*>(buffer_);
  }
}

QuicWindowUpdateFrame::QuicWindowUpdateFrame(QuicStreamId stream_id,
                                             QuicStreamOffset byte_offset)
    : stream_id(stream_id), byte_offset(byte_offset) {}

QuicBlockedFrame::QuicBlockedFrame(QuicStreamId stream_id)
    : stream_id(stream_id) {}

QuicPathCloseFrame::QuicPathCloseFrame(QuicPathId path_id) : path_id(path_id) {}

QuicPacket::QuicPacket(char* buffer,
                       size_t length,
                       bool owns_buffer,
                       QuicConnectionIdLength connection_id_length,
                       bool includes_version,
                       bool includes_path_id,
                       QuicPacketNumberLength packet_number_length)
    : QuicData(buffer, length, owns_buffer),
      buffer_(buffer),
      connection_id_length_(connection_id_length),
      includes_version_(includes_version),
      includes_path_id_(includes_path_id),
      packet_number_length_(packet_number_length) {}

QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length)
    : QuicData(buffer, length) {}

QuicEncryptedPacket::QuicEncryptedPacket(char* buffer,
                                         size_t length,
                                         bool owns_buffer)
    : QuicData(buffer, length, owns_buffer) {}

QuicEncryptedPacket* QuicEncryptedPacket::Clone() const {
  char* buffer = new char[this->length()];
  memcpy(buffer, this->data(), this->length());
  return new QuicEncryptedPacket(buffer, this->length(), true);
}

ostream& operator<<(ostream& os, const QuicEncryptedPacket& s) {
  os << s.length() << "-byte data";
  return os;
}

QuicReceivedPacket::QuicReceivedPacket(const char* buffer,
                                       size_t length,
                                       QuicTime receipt_time)
    : QuicEncryptedPacket(buffer, length), receipt_time_(receipt_time) {}

QuicReceivedPacket::QuicReceivedPacket(char* buffer,
                                       size_t length,
                                       QuicTime receipt_time,
                                       bool owns_buffer)
    : QuicEncryptedPacket(buffer, length, owns_buffer),
      receipt_time_(receipt_time) {}

QuicReceivedPacket* QuicReceivedPacket::Clone() const {
  char* buffer = new char[this->length()];
  memcpy(buffer, this->data(), this->length());
  return new QuicReceivedPacket(buffer, this->length(), receipt_time(), true);
}

ostream& operator<<(ostream& os, const QuicReceivedPacket& s) {
  os << s.length() << "-byte data";
  return os;
}

StringPiece QuicPacket::AssociatedData() const {
  return StringPiece(data(), GetStartOfEncryptedData(
                                 connection_id_length_, includes_version_,
                                 includes_path_id_, packet_number_length_));
}

StringPiece QuicPacket::Plaintext() const {
  const size_t start_of_encrypted_data =
      GetStartOfEncryptedData(connection_id_length_, includes_version_,
                              includes_path_id_, packet_number_length_);
  return StringPiece(data() + start_of_encrypted_data,
                     length() - start_of_encrypted_data);
}

AckListenerWrapper::AckListenerWrapper(QuicAckListenerInterface* listener,
                                       QuicPacketLength data_length)
    : ack_listener(listener), length(data_length) {
  DCHECK(listener != nullptr);
}

AckListenerWrapper::AckListenerWrapper(const AckListenerWrapper& other) =
    default;

AckListenerWrapper::~AckListenerWrapper() {}

SerializedPacket::SerializedPacket(QuicPathId path_id,
                                   QuicPacketNumber packet_number,
                                   QuicPacketNumberLength packet_number_length,
                                   const char* encrypted_buffer,
                                   QuicPacketLength encrypted_length,
                                   QuicPacketEntropyHash entropy_hash,
                                   bool has_ack,
                                   bool has_stop_waiting)
    : encrypted_buffer(encrypted_buffer),
      encrypted_length(encrypted_length),
      has_crypto_handshake(NOT_HANDSHAKE),
      needs_padding(false),
      path_id(path_id),
      packet_number(packet_number),
      packet_number_length(packet_number_length),
      encryption_level(ENCRYPTION_NONE),
      entropy_hash(entropy_hash),
      has_ack(has_ack),
      has_stop_waiting(has_stop_waiting),
      original_packet_number(0),
      transmission_type(NOT_RETRANSMISSION) {}

SerializedPacket::SerializedPacket(const SerializedPacket& other) = default;

SerializedPacket::~SerializedPacket() {}

TransmissionInfo::TransmissionInfo()
    : encryption_level(ENCRYPTION_NONE),
      packet_number_length(PACKET_1BYTE_PACKET_NUMBER),
      bytes_sent(0),
      nack_count(0),
      sent_time(QuicTime::Zero()),
      transmission_type(NOT_RETRANSMISSION),
      in_flight(false),
      is_unackable(false),
      has_crypto_handshake(false),
      needs_padding(false),
      retransmission(0) {}

TransmissionInfo::TransmissionInfo(EncryptionLevel level,
                                   QuicPacketNumberLength packet_number_length,
                                   TransmissionType transmission_type,
                                   QuicTime sent_time,
                                   QuicPacketLength bytes_sent,
                                   bool has_crypto_handshake,
                                   bool needs_padding)
    : encryption_level(level),
      packet_number_length(packet_number_length),
      bytes_sent(bytes_sent),
      nack_count(0),
      sent_time(sent_time),
      transmission_type(transmission_type),
      in_flight(false),
      is_unackable(false),
      has_crypto_handshake(has_crypto_handshake),
      needs_padding(needs_padding),
      retransmission(0) {}

TransmissionInfo::TransmissionInfo(const TransmissionInfo& other) = default;

TransmissionInfo::~TransmissionInfo() {}

}  // namespace net
