| // 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) { |
| 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() { |
| // Avoid reentrancy problems by first copying the handlers map. |
| auto doomed = std::move(handlers_); |
| next_txid_ = 1; |
| doomed.clear(); |
| } |
| |
| } // namespace internal |
| } // namespace fidl |