blob: bea125aa6a3e02b62fe41a3ad723746e4effb1b8 [file] [log] [blame]
// Copyright 2019 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/llcpp/async_binding.h>
#include <lib/fidl/llcpp/async_transaction.h>
#include <lib/fidl/llcpp/message.h>
#include <lib/fidl/llcpp/server.h>
#include <zircon/assert.h>
namespace fidl {
namespace internal {
//
// Synchronous transaction methods
//
std::optional<DispatchError> SyncTransaction::Dispatch(
fidl::IncomingMessage&& msg, internal::MessageStorageViewBase* storage_view) {
ZX_ASSERT(binding_);
binding_->interface()->dispatch_message(std::move(msg), this, storage_view);
return error_;
}
zx_status_t SyncTransaction::Reply(fidl::OutgoingMessage* message, WriteOptions write_options) {
ZX_ASSERT(txid_ != 0);
auto txid = txid_;
txid_ = 0;
ZX_ASSERT(binding_);
message->set_txid(txid);
message->Write(binding_->transport(), std::move(write_options));
return message->status();
}
void SyncTransaction::EnableNextDispatch() {
if (!binding_)
return;
// Only allow one |EnableNextDispatch| call per transaction instance.
if (binding_lifetime_extender_)
return;
// Keeping another strong reference to the binding ensures that binding
// teardown will not complete until this |SyncTransaction| destructs, i.e.
// until the server method handler returns.
binding_lifetime_extender_ = binding_->shared_from_this();
if (binding_->CheckForTeardownAndBeginNextWait() == ZX_OK) {
*next_wait_begun_early_ = true;
} else {
// Propagate a placeholder error, such that the message handler will
// terminate dispatch right after the processing of this transaction.
error_ = DispatchError{UnbindInfo::Unbind(), ErrorOrigin::kReceive};
}
}
void SyncTransaction::Close(zx_status_t epitaph) {
if (!binding_)
return;
binding_ = nullptr;
// If |EnableNextDispatch| was called, the dispatcher will not monitor
// our |unbind_info_|; we should asynchronously request teardown.
if (binding_lifetime_extender_) {
binding_lifetime_extender_->Close(std::move(binding_lifetime_extender_), epitaph);
return;
}
error_ = DispatchError{UnbindInfo::Close(epitaph), ErrorOrigin::kReceive};
}
void SyncTransaction::InternalError(UnbindInfo error, ErrorOrigin origin) {
if (!binding_)
return;
binding_ = nullptr;
// If |EnableNextDispatch| was called, the dispatcher will not monitor
// our |unbind_info_|; we should asynchronously request teardown.
if (binding_lifetime_extender_) {
binding_lifetime_extender_->HandleError(std::move(binding_lifetime_extender_),
DispatchError{error, origin});
return;
}
error_ = DispatchError{error, origin};
}
std::unique_ptr<Transaction> SyncTransaction::TakeOwnership() {
ZX_ASSERT(binding_);
auto transaction = std::make_unique<AsyncTransaction>(std::move(*this));
binding_ = nullptr;
return transaction;
}
bool SyncTransaction::DidOrGoingToUnbind() {
ZX_ASSERT(binding_);
return binding_->IsDestructionImminent();
}
//
// Asynchronous transaction methods
//
zx_status_t AsyncTransaction::Reply(fidl::OutgoingMessage* message, WriteOptions write_options) {
ZX_ASSERT(txid_ != 0);
auto txid = txid_;
txid_ = 0;
std::shared_ptr<AsyncServerBinding> binding = binding_.lock();
if (!binding)
return ZX_ERR_CANCELED;
message->set_txid(txid);
message->Write(binding->transport(), std::move(write_options));
return message->status();
}
void AsyncTransaction::EnableNextDispatch() {
// Unreachable. Async completers don't expose |EnableNextDispatch|.
__builtin_abort();
}
void AsyncTransaction::Close(zx_status_t epitaph) {
if (auto binding = binding_.lock()) {
binding->Close(std::move(binding), epitaph);
}
}
void AsyncTransaction::InternalError(UnbindInfo error, ErrorOrigin origin) {
if (auto binding = binding_.lock()) {
binding->HandleError(std::move(binding), {error, origin});
}
}
std::unique_ptr<Transaction> AsyncTransaction::TakeOwnership() {
// Unreachable. Async completers don't expose |ToAsync|.
__builtin_abort();
}
bool AsyncTransaction::DidOrGoingToUnbind() {
if (auto binding = binding_.lock()) {
return binding->IsDestructionImminent();
}
return true;
}
} // namespace internal
} // namespace fidl