// 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
|