// Copyright 2021 The Fuchsia 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 "node.h"

#include <lib/zx/channel.h>
#include <zircon/types.h>

#include "koid_util.h"
#include "logical_buffer_collection.h"

namespace sysmem_service {

using Error = fuchsia_sysmem2::Error;

// This is to avoid potentially unbounded debug_client_info.name size.
const size_t kMaxDebugNameSize = 4 * 1024;

Node::Node(fbl::RefPtr<LogicalBufferCollection> logical_buffer_collection,
           NodeProperties* node_properties, zx::unowned_channel server_end)
    : logical_buffer_collection_(std::move(logical_buffer_collection)),
      node_properties_(node_properties),
      server_end_(std::move(server_end)) {
  ZX_DEBUG_ASSERT(node_properties_);
  if (*server_end_) {
    zx_koid_t server_koid;
    zx_koid_t client_koid;
    zx_status_t status =
        get_handle_koids(*server_end_, &server_koid, &client_koid, ZX_OBJ_TYPE_CHANNEL);
    if (status != ZX_OK) {
      create_status_ = status;
      return;
    }
    client_koid_ = client_koid;
    server_koid_ = server_koid;
  }
  create_status_ = ZX_OK;
}

zx_status_t Node::create_status() const {
  ZX_DEBUG_ASSERT(*server_end_ || orphaned_node());
  create_status_was_checked_ = true;
  return create_status_;
}

Node::~Node() {
  ZX_DEBUG_ASSERT(create_status_was_checked_);
  // Ok to untrack zx_koid_t{}; also ok to untrack same zx_koid_t again.
}

void Node::Bind(NodeServerEnd server_end) {
  zx_info_handle_basic_t info;
  zx_status_t status = GetUnownedChannel(server_end)
                           ->get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
  if (status == ZX_OK) {
    inspect_node_.CreateUint("channel_koid", info.koid, &properties_);
  }
  auto error_handler_wrapper = [this, this_ref = fbl::RefPtr<Node>(this)](fidl::UnbindInfo info) {
    if (error_handler_) {
      zx_status_t status = info.status();
      if (async_failure_result_.has_value() && info.reason() == fidl::Reason::kClose) {
        // On kClose the error is always ZX_OK, so report the real error to
        // LogicalBufferCollection if the close was caused by FailAsync or FailSync.
        status = *async_failure_result_;
      }
      error_handler_(status);
    }
  };
  // We need to keep a refptr to this class, since the unbind happens asynchronously and can run
  // after the parent closes a handle to this class.
  switch (server_end.index()) {
    case kVersionIndexV1:
      BindInternalV1(std::move(std::get<kVersionIndexV1>(server_end)),
                     std::move(error_handler_wrapper));
      break;
    case kVersionIndexV2:
      BindInternalV2(std::move(std::get<kVersionIndexV2>(server_end)),
                     std::move(error_handler_wrapper));
      break;
    case kVersionIndexCombinedV1AndV2:
      BindInternalCombinedV1AndV2(std::move(std::get<kVersionIndexCombinedV1AndV2>(server_end)),
                                  std::move(error_handler_wrapper));
      break;
  }
}

void Node::SetErrorHandler(fit::function<void(zx_status_t)> error_handler) {
  // OrphanedNode deletes SetErrorHandler(), but also make sure OrphanedNode::SetErrorHandler()
  // isn't happening via a cast of an OrphanedNode* to Node* first.
  ZX_DEBUG_ASSERT(!orphaned_node());
  error_handler_ = std::move(error_handler);
}

void Node::Fail(Error error) { CloseChannel(error); }

void Node::SetDebugClientInfoInternal(ClientDebugInfo debug_info) {
  if (!node_properties().client_debug_info().name.empty()) {
    debug_info.name = debug_info.name + " (was " + node_properties().client_debug_info().name + ")";
    if (debug_info.name.size() > kMaxDebugNameSize) {
      debug_info.name.resize(kMaxDebugNameSize);
    }
  }
  node_properties().client_debug_info() = std::move(debug_info);
  debug_id_property_ =
      inspect_node_.CreateUint("debug_id", node_properties().client_debug_info().id);
  debug_name_property_ =
      inspect_node_.CreateString("debug_name", node_properties().client_debug_info().name);
  if (was_unfound_node()) {
    // Output the debug info now that we have it, since eg. we previously said bad things about this
    // token's server_koid not being found when it should have been, but at that time we didn't have
    // the debug info.
    //
    // This is not a failure here, but the message provides debug info for a failure that previously
    // occurred.
    logical_buffer_collection().LogClientError(FROM_HERE, &node_properties(),
                                               "Got debug info for node %ld", server_koid_);
  }
}

LogicalBufferCollection& Node::logical_buffer_collection() const {
  return *logical_buffer_collection_;
}

fbl::RefPtr<LogicalBufferCollection> Node::shared_logical_buffer_collection() {
  return logical_buffer_collection_;
}

NodeProperties& Node::node_properties() const {
  ZX_ASSERT(node_properties_);
  return *node_properties_;
}

zx::unowned_channel Node::channel() const {
  ZX_ASSERT(is_currently_connected());
  return zx::unowned_channel(server_end_);
}

bool Node::is_done() const {
  ZX_DEBUG_ASSERT(!orphaned_node());
  return is_done_;
}

bool Node::has_client_koid() const {
  return create_status_ == ZX_OK && client_koid_ != zx_koid_t{};
}

zx_koid_t Node::client_koid() const {
  ZX_ASSERT(create_status_ == ZX_OK && client_koid_ != zx_koid_t{});
  return client_koid_;
}

bool Node::has_server_koid() const {
  return create_status_ == ZX_OK && server_koid_ != ZX_KOID_INVALID;
}

zx_koid_t Node::server_koid() const {
  ZX_ASSERT(create_status_ == ZX_OK && server_koid_ != ZX_KOID_INVALID);
  return server_koid_;
}

Sysmem* Node::parent_sysmem() const { return logical_buffer_collection_->parent_sysmem(); }

void Node::CloseChannel(Error error) {
  // This essentially converts the OnUnboundFn semantic of getting called regardless of channel-fail
  // vs. server-driven-fail into the more typical semantic where error_handler_ only gets called
  // on channel-fail but not on server-driven-fail.
  error_handler_ = {};
  zx_status_t epitaph = sysmem::V1CopyFromV2Error(error);
  // Passing an epitaph here specifies the epitaph for sysmem(1), but sysmem2 always sends
  // ZX_ERR_INTERNAL as the epitaph.
  CloseServerBinding(epitaph);
}

}  // namespace sysmem_service
