// 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/qbone/qbone_session_base.h"

#include <netinet/icmp6.h>
#include <netinet/ip6.h>

#include <utility>

#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_exported_stats.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/qbone/platform/icmp_packet.h"
#include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"

namespace quic {

QboneSessionBase::QboneSessionBase(
    QuicConnection* connection,
    Visitor* owner,
    const QuicConfig& config,
    const ParsedQuicVersionVector& supported_versions,
    QbonePacketWriter* writer)
    : QuicSession(connection,
                  owner,
                  config,
                  supported_versions,
                  /*num_expected_unidirectional_static_streams = */ 0) {
  set_writer(writer);
  const uint32_t max_streams =
      (std::numeric_limits<uint32_t>::max() / kMaxAvailableStreamsMultiplier) -
      1;
  this->config()->SetMaxBidirectionalStreamsToSend(max_streams);
  if (VersionHasIetfQuicFrames(transport_version())) {
    this->config()->SetMaxUnidirectionalStreamsToSend(max_streams);
  }
}

QboneSessionBase::~QboneSessionBase() {
  // Clear out the streams before leaving this destructor to avoid calling
  // QuicSession::UnregisterStreamPriority
  stream_map().clear();
  closed_streams()->clear();
}

void QboneSessionBase::Initialize() {
  crypto_stream_ = CreateCryptoStream();
  QuicSession::Initialize();
}

const QuicCryptoStream* QboneSessionBase::GetCryptoStream() const {
  return crypto_stream_.get();
}

QuicCryptoStream* QboneSessionBase::GetMutableCryptoStream() {
  return crypto_stream_.get();
}

void QboneSessionBase::OnMessageReceived(quiche::QuicheStringPiece message) {
  ++num_message_packets_;
  ProcessPacketFromPeer(message);
}

QuicStream* QboneSessionBase::CreateIncomingStream(QuicStreamId id) {
  QUIC_NOTREACHED();
  return nullptr;
}

QuicStream* QboneSessionBase::CreateIncomingStream(PendingStream* /*pending*/) {
  QUIC_NOTREACHED();
  return nullptr;
}

bool QboneSessionBase::ShouldKeepConnectionAlive() const {
  // QBONE connections stay alive until they're explicitly closed.
  return true;
}

void QboneSessionBase::SendPacketToPeer(quiche::QuicheStringPiece packet) {
  if (crypto_stream_ == nullptr) {
    QUIC_BUG << "Attempting to send packet before encryption established";
    return;
  }

  QuicUniqueBufferPtr buffer = MakeUniqueBuffer(
      connection()->helper()->GetStreamSendBufferAllocator(), packet.size());
  memcpy(buffer.get(), packet.data(), packet.size());
  QuicMemSlice slice(std::move(buffer), packet.size());
  switch (SendMessage(QuicMemSliceSpan(&slice), /*flush=*/true).status) {
    case MESSAGE_STATUS_SUCCESS:
      break;
    case MESSAGE_STATUS_TOO_LARGE: {
      if (packet.size() < sizeof(ip6_hdr)) {
        QUIC_BUG << "Dropped malformed packet: IPv6 header too short";
        break;
      }
      auto* header = reinterpret_cast<const ip6_hdr*>(packet.begin());
      icmp6_hdr icmp_header{};
      icmp_header.icmp6_type = ICMP6_PACKET_TOO_BIG;
      icmp_header.icmp6_mtu =
          connection()->GetGuaranteedLargestMessagePayload();

      CreateIcmpPacket(header->ip6_dst, header->ip6_src, icmp_header, packet,
                       [this](quiche::QuicheStringPiece icmp_packet) {
                         writer_->WritePacketToNetwork(icmp_packet.data(),
                                                       icmp_packet.size());
                       });
      break;
    }
    case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
      QUIC_BUG << "MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED";
      break;
    case MESSAGE_STATUS_UNSUPPORTED:
      QUIC_BUG << "MESSAGE_STATUS_UNSUPPORTED";
      break;
    case MESSAGE_STATUS_BLOCKED:
      QUIC_BUG << "MESSAGE_STATUS_BLOCKED";
      break;
    case MESSAGE_STATUS_INTERNAL_ERROR:
      QUIC_BUG << "MESSAGE_STATUS_INTERNAL_ERROR";
      break;
  }
}

uint64_t QboneSessionBase::GetNumEphemeralPackets() const {
  return num_ephemeral_packets_;
}

uint64_t QboneSessionBase::GetNumMessagePackets() const {
  return num_message_packets_;
}

void QboneSessionBase::set_writer(QbonePacketWriter* writer) {
  writer_ = writer;
  testing::testvalue::Adjust("quic_QbonePacketWriter", &writer_);
}

}  // namespace quic
