普通文本  |  98行  |  2.6 KB

// Copyright 2018 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 "lib/fidl/cpp/internal/proxy_controller.h"

#include <utility>

#include "lib/fidl/cpp/internal/logging.h"

namespace fidl {
namespace internal {
namespace {

constexpr uint32_t kUserspaceTxidMask = 0x7FFFFFFF;

}  // namespace

ProxyController::ProxyController() : reader_(this), next_txid_(1) {}

ProxyController::~ProxyController() = default;

ProxyController::ProxyController(ProxyController&& other)
    : reader_(this),
      handlers_(std::move(other.handlers_)),
      next_txid_(other.next_txid_) {
  reader_.TakeChannelAndErrorHandlerFrom(&other.reader());
  other.Reset();
}

ProxyController& ProxyController::operator=(ProxyController&& other) {
  if (this != &other) {
    reader_.TakeChannelAndErrorHandlerFrom(&other.reader());
    handlers_ = std::move(other.handlers_);
    next_txid_ = other.next_txid_;
    other.Reset();
  }
  return *this;
}

zx_status_t ProxyController::Send(
    const fidl_type_t* type, Message message,
    std::unique_ptr<MessageHandler> response_handler) {
  zx_txid_t txid = 0;
  if (response_handler) {
    txid = next_txid_++ & kUserspaceTxidMask;
    while (!txid || handlers_.find(txid) != handlers_.end())
      txid = next_txid_++ & kUserspaceTxidMask;
    message.set_txid(txid);
  }
  const char* error_msg = nullptr;
  zx_status_t status = message.Validate(type, &error_msg);
  if (status != ZX_OK) {
    FIDL_REPORT_ENCODING_ERROR(message, type, error_msg);
    return status;
  }
  status = message.Write(reader_.channel().get(), 0);
  if (status != ZX_OK) {
    FIDL_REPORT_CHANNEL_WRITING_ERROR(message, type, status);
    return status;
  }
  if (response_handler)
    handlers_.emplace(txid, std::move(response_handler));
  return ZX_OK;
}

void ProxyController::Reset() {
  reader_.Reset();
  ClearPendingHandlers();
}

zx_status_t ProxyController::OnMessage(Message message) {
  if (!message.has_header())
    return ZX_ERR_INVALID_ARGS;
  zx_txid_t txid = message.txid();
  if (!txid) {
    if (!proxy_)
      return ZX_ERR_NOT_SUPPORTED;
    return proxy_->Dispatch_(std::move(message));
  }
  auto it = handlers_.find(txid);
  if (it == handlers_.end())
    return ZX_ERR_NOT_FOUND;
  std::unique_ptr<MessageHandler> handler = std::move(it->second);
  handlers_.erase(it);
  return handler->OnMessage(std::move(message));
}

void ProxyController::OnChannelGone() { ClearPendingHandlers(); }

void ProxyController::ClearPendingHandlers() {
  handlers_.clear();
  next_txid_ = 1;
}

}  // namespace internal
}  // namespace fidl