blob: bec764c0cb5825a08060cdf0a588838a3a8129f1 [file] [log] [blame]
// 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