// Copyright 2014 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 "extensions/browser/api/cast_channel/logger.h"

#include <stdint.h>

#include <string>
#include <utility>

#include "base/strings/string_util.h"
#include "base/time/clock.h"
#include "extensions/browser/api/cast_channel/cast_auth_util.h"
#include "extensions/browser/api/cast_channel/cast_socket.h"
#include "extensions/browser/api/cast_channel/logger_util.h"
#include "net/base/net_errors.h"
#include "third_party/zlib/zlib.h"

namespace extensions {
namespace api {
namespace cast_channel {

using net::IPEndPoint;
using proto::AggregatedSocketEvent;
using proto::EventType;
using proto::Log;
using proto::SocketEvent;

namespace {

const char* kInternalNamespacePrefix = "com.google.cast";

proto::ChallengeReplyErrorType ChallegeReplyErrorToProto(
    AuthResult::ErrorType error_type) {
  switch (error_type) {
    case AuthResult::ERROR_NONE:
      return proto::CHALLENGE_REPLY_ERROR_NONE;
    case AuthResult::ERROR_PEER_CERT_EMPTY:
      return proto::CHALLENGE_REPLY_ERROR_PEER_CERT_EMPTY;
    case AuthResult::ERROR_WRONG_PAYLOAD_TYPE:
      return proto::CHALLENGE_REPLY_ERROR_WRONG_PAYLOAD_TYPE;
    case AuthResult::ERROR_NO_PAYLOAD:
      return proto::CHALLENGE_REPLY_ERROR_NO_PAYLOAD;
    case AuthResult::ERROR_PAYLOAD_PARSING_FAILED:
      return proto::CHALLENGE_REPLY_ERROR_PAYLOAD_PARSING_FAILED;
    case AuthResult::ERROR_MESSAGE_ERROR:
      return proto::CHALLENGE_REPLY_ERROR_MESSAGE_ERROR;
    case AuthResult::ERROR_NO_RESPONSE:
      return proto::CHALLENGE_REPLY_ERROR_NO_RESPONSE;
    case AuthResult::ERROR_FINGERPRINT_NOT_FOUND:
      return proto::CHALLENGE_REPLY_ERROR_FINGERPRINT_NOT_FOUND;
    case AuthResult::ERROR_CERT_PARSING_FAILED:
      return proto::CHALLENGE_REPLY_ERROR_CERT_PARSING_FAILED;
    case AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA:
      return proto::CHALLENGE_REPLY_ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
    case AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY:
      return proto::CHALLENGE_REPLY_ERROR_CANNOT_EXTRACT_PUBLIC_KEY;
    case AuthResult::ERROR_SIGNED_BLOBS_MISMATCH:
      return proto::CHALLENGE_REPLY_ERROR_SIGNED_BLOBS_MISMATCH;
    default:
      NOTREACHED();
      return proto::CHALLENGE_REPLY_ERROR_NONE;
  }
}

std::unique_ptr<char[]> Compress(const std::string& input, size_t* length) {
  *length = 0;
  z_stream stream = {0};
  int result = deflateInit2(&stream,
                            Z_DEFAULT_COMPRESSION,
                            Z_DEFLATED,
                            // 16 is added to produce a gzip header + trailer.
                            MAX_WBITS + 16,
                            8,  // memLevel = 8 is default.
                            Z_DEFAULT_STRATEGY);
  DCHECK_EQ(Z_OK, result);

  size_t out_size = deflateBound(&stream, input.size());
  std::unique_ptr<char[]> out(new char[out_size]);

  stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(input.data()));
  stream.avail_in = input.size();
  stream.next_out = reinterpret_cast<uint8_t*>(out.get());
  stream.avail_out = out_size;

  // Do a one-shot compression. This will return Z_STREAM_END only if |output|
  // is large enough to hold all compressed data.
  result = deflate(&stream, Z_FINISH);

  bool success = (result == Z_STREAM_END);

  if (!success)
    VLOG(2) << "deflate() failed. Result: " << result;

  result = deflateEnd(&stream);
  DCHECK(result == Z_OK || result == Z_DATA_ERROR);

  if (success)
    *length = out_size - stream.avail_out;

  return out;
}

// Propagate any error fields set in |event| to |last_errors|.  If any error
// field in |event| is set, then also set |last_errors->event_type|.
void MaybeSetLastErrors(const SocketEvent& event, LastErrors* last_errors) {
  if (event.has_net_return_value() &&
      event.net_return_value() < net::ERR_IO_PENDING) {
    last_errors->net_return_value = event.net_return_value();
    last_errors->event_type = event.type();
  }
  if (event.has_challenge_reply_error_type()) {
    last_errors->challenge_reply_error_type =
        event.challenge_reply_error_type();
    last_errors->event_type = event.type();
  }
}

}  // namespace

Logger::AggregatedSocketEventLog::AggregatedSocketEventLog() {
}

Logger::AggregatedSocketEventLog::~AggregatedSocketEventLog() {
}

Logger::Logger(std::unique_ptr<base::Clock> clock, base::Time unix_epoch_time)
    : clock_(std::move(clock)), unix_epoch_time_(unix_epoch_time) {
  DCHECK(clock_);

  // Logger may not be necessarily be created on the IO thread, but logging
  // happens exclusively there.
  thread_checker_.DetachFromThread();
}

Logger::~Logger() {
}

void Logger::LogNewSocketEvent(const CastSocket& cast_socket) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::CAST_SOCKET_CREATED);
  AggregatedSocketEvent& aggregated_socket_event =
      LogSocketEvent(cast_socket.id(), event);

  const net::IPAddress& ip = cast_socket.ip_endpoint().address();
  DCHECK(ip.IsValid());
  aggregated_socket_event.set_endpoint_id(ip.bytes().back());
  aggregated_socket_event.set_channel_auth_type(cast_socket.channel_auth() ==
                                                        CHANNEL_AUTH_TYPE_SSL
                                                    ? proto::SSL
                                                    : proto::SSL_VERIFIED);
}

void Logger::LogSocketEvent(int channel_id, EventType event_type) {
  DCHECK(thread_checker_.CalledOnValidThread());

  LogSocketEventWithDetails(channel_id, event_type, std::string());
}

void Logger::LogSocketEventWithDetails(int channel_id,
                                       EventType event_type,
                                       const std::string& details) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(event_type);
  if (!details.empty())
    event.set_details(details);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketEventWithRv(int channel_id,
                                  EventType event_type,
                                  int rv) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(event_type);
  event.set_net_return_value(rv);

  AggregatedSocketEvent& aggregated_socket_event =
      LogSocketEvent(channel_id, event);

  if ((event_type == proto::SOCKET_READ || event_type == proto::SOCKET_WRITE) &&
      rv > 0) {
    if (event_type == proto::SOCKET_READ) {
      aggregated_socket_event.set_bytes_read(
          aggregated_socket_event.bytes_read() + rv);
    } else {
      aggregated_socket_event.set_bytes_written(
          aggregated_socket_event.bytes_written() + rv);
    }
  }
}

void Logger::LogSocketReadyState(int channel_id, proto::ReadyState new_state) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::READY_STATE_CHANGED);
  event.set_ready_state(new_state);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketConnectState(int channel_id,
                                   proto::ConnectionState new_state) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::CONNECTION_STATE_CHANGED);
  event.set_connection_state(new_state);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketReadState(int channel_id, proto::ReadState new_state) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::READ_STATE_CHANGED);
  event.set_read_state(new_state);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketWriteState(int channel_id, proto::WriteState new_state) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::WRITE_STATE_CHANGED);
  event.set_write_state(new_state);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketErrorState(int channel_id, proto::ErrorState new_state) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::ERROR_STATE_CHANGED);
  event.set_error_state(new_state);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketEventForMessage(int channel_id,
                                      EventType event_type,
                                      const std::string& message_namespace,
                                      const std::string& details) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(event_type);
  if (base::StartsWith(message_namespace, kInternalNamespacePrefix,
                       base::CompareCase::INSENSITIVE_ASCII))
    event.set_message_namespace(message_namespace);
  event.set_details(details);

  LogSocketEvent(channel_id, event);
}

void Logger::LogSocketChallengeReplyEvent(int channel_id,
                                          const AuthResult& auth_result) {
  DCHECK(thread_checker_.CalledOnValidThread());

  SocketEvent event = CreateEvent(proto::AUTH_CHALLENGE_REPLY);
  event.set_challenge_reply_error_type(
      ChallegeReplyErrorToProto(auth_result.error_type));

  LogSocketEvent(channel_id, event);
}

SocketEvent Logger::CreateEvent(EventType event_type) {
  SocketEvent event;
  event.set_type(event_type);
  event.set_timestamp_micros(
      (clock_->Now() - unix_epoch_time_).InMicroseconds());
  return event;
}

AggregatedSocketEvent& Logger::LogSocketEvent(int channel_id,
                                              const SocketEvent& socket_event) {
  AggregatedSocketEventLogMap::iterator it =
      aggregated_socket_events_.find(channel_id);
  if (it == aggregated_socket_events_.end()) {
    if (aggregated_socket_events_.size() >= kMaxSocketsToLog) {
      AggregatedSocketEventLogMap::iterator erase_it =
          aggregated_socket_events_.begin();

      log_.set_num_evicted_aggregated_socket_events(
          log_.num_evicted_aggregated_socket_events() + 1);
      log_.set_num_evicted_socket_events(
          log_.num_evicted_socket_events() +
          erase_it->second->socket_events.size());

      aggregated_socket_events_.erase(erase_it);
    }

    it = aggregated_socket_events_
             .insert(std::make_pair(
                 channel_id, base::MakeUnique<AggregatedSocketEventLog>()))
             .first;
    it->second->aggregated_socket_event.set_id(channel_id);
  }

  std::deque<proto::SocketEvent>& socket_events = it->second->socket_events;
  if (socket_events.size() >= kMaxEventsPerSocket) {
    socket_events.pop_front();
    log_.set_num_evicted_socket_events(log_.num_evicted_socket_events() + 1);
  }
  socket_events.push_back(socket_event);

  MaybeSetLastErrors(socket_event, &(it->second->last_errors));

  return it->second->aggregated_socket_event;
}

std::unique_ptr<char[]> Logger::GetLogs(size_t* length) const {
  *length = 0;

  Log log;
  // Copy "global" values from |log_|. Don't use |log_| directly since this
  // function is const.
  log.CopyFrom(log_);

  for (AggregatedSocketEventLogMap::const_iterator it =
           aggregated_socket_events_.begin();
       it != aggregated_socket_events_.end();
       ++it) {
    AggregatedSocketEvent* new_aggregated_socket_event =
        log.add_aggregated_socket_event();
    new_aggregated_socket_event->CopyFrom(it->second->aggregated_socket_event);

    const std::deque<SocketEvent>& socket_events = it->second->socket_events;
    for (std::deque<SocketEvent>::const_iterator socket_event_it =
             socket_events.begin();
         socket_event_it != socket_events.end();
         ++socket_event_it) {
      SocketEvent* socket_event =
          new_aggregated_socket_event->add_socket_event();
      socket_event->CopyFrom(*socket_event_it);
    }
  }

  std::string serialized;
  if (!log.SerializeToString(&serialized)) {
    VLOG(2) << "Failed to serialized proto to string.";
    return std::unique_ptr<char[]>();
  }

  return Compress(serialized, length);
}

void Logger::Reset() {
  aggregated_socket_events_.clear();
  log_.Clear();
}

LastErrors Logger::GetLastErrors(int channel_id) const {
  AggregatedSocketEventLogMap::const_iterator it =
      aggregated_socket_events_.find(channel_id);
  if (it != aggregated_socket_events_.end()) {
    return it->second->last_errors;
  } else {
    return LastErrors();
  }
}

}  // namespace cast_channel
}  // namespace api
}  // namespace extensions
