blob: 9afc50c41c112817ca0a49f3882e5f93d30c0823 [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/message.h>
#include <lib/fidl/llcpp/status.h>
#include <lib/fidl/llcpp/transaction.h>
namespace fidl {
CompleterBase& CompleterBase::operator=(CompleterBase&& other) noexcept {
if (this != &other) {
DropTransaction();
transaction_ = other.transaction_;
owned_ = other.owned_;
needs_to_reply_ = other.needs_to_reply_;
other.transaction_ = nullptr;
other.owned_ = false;
other.needs_to_reply_ = false;
}
return *this;
}
void CompleterBase::Close(zx_status_t status) {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
transaction_->Close(status);
DropTransaction();
}
bool CompleterBase::is_reply_needed() const {
ScopedLock lock(lock_);
if (!needs_to_reply_)
return false;
if (!transaction_ || transaction_->DidOrGoingToUnbind())
return false;
return true;
}
void CompleterBase::EnableNextDispatch() {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
transaction_->EnableNextDispatch();
}
CompleterBase::CompleterBase(CompleterBase&& other) noexcept
: transaction_(other.transaction_),
reply_result_(other.reply_result_),
owned_(other.owned_),
needs_to_reply_(other.needs_to_reply_) {
other.transaction_ = nullptr;
other.reply_result_.reset();
other.owned_ = false;
other.needs_to_reply_ = false;
}
CompleterBase::~CompleterBase() {
ZX_ASSERT_MSG(!is_reply_needed(), "Completer expected a Reply to be sent.");
DropTransaction();
}
std::unique_ptr<Transaction> CompleterBase::TakeOwnership() {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
std::unique_ptr<Transaction> clone = transaction_->TakeOwnership();
DropTransaction();
return clone;
}
fidl::Status CompleterBase::result_of_reply() const {
if (!reply_result_.has_value()) {
ZX_PANIC("Did not make a reply on this completer.");
}
return reply_result_.value();
}
void CompleterBase::SendReply(::fidl::OutgoingMessage* message,
internal::OutgoingTransportContext transport_context) {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
if (unlikely(!needs_to_reply_)) {
lock.release(); // Avoid crashing on death tests.
ZX_PANIC("Repeated or unexpected Reply.");
}
// At this point we are either replying or calling InternalError, so no need for
// further replies.
needs_to_reply_ = false;
if (!message->ok()) {
transaction_->InternalError(fidl::UnbindInfo{*message}, fidl::ErrorOrigin::kSend);
reply_result_.emplace(*message);
return;
}
fidl::WriteOptions write_options = {
.outgoing_transport_context = std::move(transport_context),
};
zx_status_t status = transaction_->Reply(message, std::move(write_options));
if (status != ZX_OK) {
auto error = fidl::Status::TransportError(status);
transaction_->InternalError(fidl::UnbindInfo{error}, fidl::ErrorOrigin::kSend);
reply_result_.emplace(error);
return;
}
reply_result_.emplace(fidl::Status::Ok());
}
void CompleterBase::EnsureHasTransaction(ScopedLock* lock) {
if (unlikely(!transaction_)) {
lock->release(); // Avoid crashing on death tests.
ZX_PANIC("ToAsync() was already called.");
}
}
void CompleterBase::DropTransaction() {
if (owned_) {
owned_ = false;
delete transaction_;
}
transaction_ = nullptr;
needs_to_reply_ = false;
}
} // namespace fidl