blob: 6c373736774227b84db9d934879d10d8e42b6e22 [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/errors.h>
#include <lib/fidl/llcpp/message.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();
}
void CompleterBase::EnableNextDispatch() {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
transaction_->EnableNextDispatch();
}
CompleterBase::CompleterBase(CompleterBase&& other) noexcept
: transaction_(other.transaction_),
owned_(other.owned_),
needs_to_reply_(other.needs_to_reply_) {
other.transaction_ = nullptr;
other.owned_ = false;
other.needs_to_reply_ = false;
}
CompleterBase::~CompleterBase() {
ScopedLock lock(lock_);
ZX_ASSERT_MSG(!needs_to_reply_ || (transaction_ && transaction_->IsUnbound()),
"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::Result CompleterBase::SendReply(::fidl::OutgoingMessage* message) {
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::kEncodeError, message->status()});
return fidl::Result(message->status(), message->error());
}
auto status = transaction_->Reply(message);
if (status != ZX_OK) {
transaction_->InternalError({UnbindInfo::kChannelError, status});
return fidl::Result(status, ::fidl::kErrorWriteFailed);
}
return fidl::Result(ZX_OK, nullptr);
}
void CompleterBase::InternalError(UnbindInfo error) {
ScopedLock lock(lock_);
EnsureHasTransaction(&lock);
transaction_->InternalError(error);
// NOTE: The transaction is not dropped as the user has not explicitly Close()d the completer.
// As such, Drop() would panic if invoked here.
}
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