blob: 72edd283cc3d8a7fc07300c4fd8115cf977e1478 [file] [log] [blame]
// Copyright 2020 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.
#ifndef LIB_FIDL_LLCPP_CLIENT_H_
#define LIB_FIDL_LLCPP_CLIENT_H_
#include <lib/fidl/llcpp/client_base.h>
namespace fidl {
// This class wraps the LLCPP thread-safe client. It provides methods for binding a channel's
// client end to a dispatcher, unbinding the channel, and recovering the channel. Generated FIDL
// APIs are accessed by 'dereferencing' the Client.
//
// This class itself is NOT thread-safe. The user is responsible for ensuring that Bind() is
// serialized with respect to other calls on Client APIs. Also, Bind() must have been called before
// any calls are made to other APIs.
// NOTE: Using the constructor overloads automatically satisfies the latter condition.
template <typename Protocol>
class Client final {
public:
// Create uninitialized Client.
Client() = default;
// Create initialized Client which manages the binding of the client end of a channel to a
// dispatcher.
Client(zx::channel client_end, async_dispatcher_t* dispatcher,
typename Protocol::AsyncEventHandlers handlers = {}) {
auto status = Bind(std::move(client_end), dispatcher, std::move(handlers));
ZX_ASSERT_MSG(status == ZX_OK, "%s: Failed Bind() with status %d.", __func__, status);
}
Client(zx::channel client_end, async_dispatcher_t* dispatcher, OnClientUnboundFn on_unbound,
typename Protocol::AsyncEventHandlers handlers = {}) {
auto status = Bind(std::move(client_end), dispatcher, std::move(on_unbound),
std::move(handlers));
ZX_ASSERT_MSG(status == ZX_OK, "%s: Failed Bind() with status %d.", __func__, status);
}
// Trigger unbinding, which will cause any strong references to the ClientBase to be released.
~Client() { if (client_) client_->Unbind(); }
// Move-only.
Client(const Client& other) = delete;
Client& operator=(const Client& other) = delete;
Client(Client&& other) = default;
Client& operator=(Client&& other) = default;
// Bind the channel to the dispatcher. If Client is already initialized, destroys the previous
// binding, releasing its channel.
zx_status_t Bind(zx::channel client_end, async_dispatcher_t* dispatcher,
OnClientUnboundFn on_unbound,
typename Protocol::AsyncEventHandlers handlers = {}) {
if (client_) client_->Unbind();
client_.reset(static_cast<internal::ClientBase*>(
new typename Protocol::ClientImpl(std::move(handlers))));
return client_->Bind(client_, std::move(client_end), dispatcher, std::move(on_unbound));
}
zx_status_t Bind(zx::channel client_end, async_dispatcher_t* dispatcher,
typename Protocol::AsyncEventHandlers handlers = {}) {
return Bind(std::move(client_end), dispatcher, [](UnbindInfo) {}, std::move(handlers));
}
// Unbind the channel from the dispatcher. May be called from any thread. If provided, the
// OnClientUnboundFn is invoked asynchronously on a dispatcher thread.
// NOTE: Bind() must have been called before this.
// WARNING: While it is safe to invoke Unbind() from any thread, it is unsafe to wait on the
// OnClientUnboundFn from a dispatcher thread, as that will likely deadlock.
void Unbind() {
ZX_ASSERT(client_);
client_->Unbind();
}
// Returns the underlying channel. Unbinds from the dispatcher if required.
// NOTE: Bind() must have been called before this.
// WARNING: This is a blocking call. It waits for completion of dispatcher unbind and of any
// channel operations, including synchronous calls which may block indefinitely.
zx::channel WaitForChannel() {
ZX_ASSERT(client_);
return client_->WaitForChannel();
}
// Return the Client interface for making outgoing FIDL calls. If the client has been unbound,
// calls on the interface return error with status ZX_ERR_CANCELED.
typename Protocol::ClientImpl* get() const {
return static_cast<typename Protocol::ClientImpl*>(client_.get());
}
typename Protocol::ClientImpl* operator->() const { return get(); }
typename Protocol::ClientImpl& operator*() const { return *get(); }
private:
std::shared_ptr<internal::ClientBase> client_;
};
} // namespace fidl
#endif // LIB_FIDL_LLCPP_CLIENT_H_