blob: 4241bd7033b0dc80797b31efd146cb99d072e02b [file] [log] [blame]
// 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.
#ifndef LIB_FIDL_CPP_BINDING_H_
#define LIB_FIDL_CPP_BINDING_H_
#include <lib/async/dispatcher.h>
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/fidl/cpp/interface_ptr.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/fidl/cpp/internal/stub_controller.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <zircon/assert.h>
#include <memory>
#include <utility>
namespace fidl {
// Binds the implementation of |Interface| to a channel.
//
// The |Binding| listens for incoming messages on the channel, decodes them, and
// calls the appropriate method on the bound implementation. If the message
// expects a reply, the |Binding| creates callbacks that encode and send
// reply messages when called.
//
// When the |Binding| object is destroyed, the binding between the channel
// and the interface is torn down and the channel is closed, leaving the
// |Binding| in an unbound state.
//
// The implementation pointer type of the binding is also parameterized,
// allowing the use of smart pointer types such as |std::unique_ptr| to
// reference the implementation.
//
// Example:
//
// #include "foo.fidl.h"
//
// class FooImpl : public Foo {
// public:
// explicit FooImpl(InterfaceRequest<Foo> request)
// : binding_(this, std::move(request)) {}
//
// // Foo implementation here.
//
// private:
// Binding<Foo> binding_;
// };
//
// After the |Binding| has been bound to an implementation, the implementation
// will receive methods calls from the remote endpoint of the channel on the
// async_dispatcher_t to which the |InterfaceRequest| was bound. By default this
// is the thread on which the binding occurred.
//
// See also:
//
// * |InterfacePtr|, which is the client analog of a |Binding|.
// * |EventSender|, which can send messages from multiple threads safely.
template <typename Interface, typename ImplPtr = Interface*>
class Binding final {
private:
template <class T>
struct is_unique_ptr : std::false_type {};
template <class T, class D>
struct is_unique_ptr<std::unique_ptr<T, D>> : std::true_type {};
template <class T>
struct is_shared_ptr : std::false_type {};
template <class T>
struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};
static_assert(std::is_pointer<ImplPtr>::value || is_unique_ptr<ImplPtr>::value ||
is_shared_ptr<ImplPtr>::value,
"Binding only supports ImplPtr which are pointers");
public:
// Constructs an incomplete binding that will use the implementation |impl|.
//
// The binding may be completed with a subsequent call to the |Bind| method.
// Does not take ownership of |impl|, which must outlive the binding.
explicit Binding(ImplPtr impl) : impl_(std::forward<ImplPtr>(impl)), stub_(&*this->impl()) {
controller_.set_stub(&stub_);
stub_.set_sender(&controller_);
}
// Constructs a completed binding of |channel| to implementation |impl|.
//
// Does not take ownership of |impl|, which must outlive the binding.
//
// If the |Binding| cannot be bound to the given |channel| (e.g., because
// the |channel| lacks |ZX_RIGHT_WAIT|), the |Binding| will be constructed
// in an unbound state.
//
// Uses the given async_dispatcher_t (e.g., a message loop) in order to read
// messages from the channel and to monitor the channel for
// |ZX_CHANNEL_PEER_CLOSED|. If |dispatcher| is null, the current thread must
// have a default async_dispatcher_t.
Binding(ImplPtr impl, zx::channel channel, async_dispatcher_t* dispatcher = nullptr)
: Binding(std::forward<ImplPtr>(impl)) {
Bind(std::move(channel), dispatcher);
}
// Constructs a completed binding of |impl| to the channel in |request|.
//
// Does not take ownership of |impl|, which must outlive the binding.
//
// If the |Binding| cannot be bound to the given |channel| (e.g., because
// the |channel| lacks |ZX_RIGHT_WAIT|), the |Binding| will be constructed
// in an unbound state.
//
// Uses the given async_dispatcher_t (e.g., a message loop) in order to read
// messages from the channel and to monitor the channel for
// |ZX_CHANNEL_PEER_CLOSED|. If |dispatcher| is null, the current thread must
// have a default async_dispatcher_t.
Binding(ImplPtr impl, InterfaceRequest<Interface> request,
async_dispatcher_t* dispatcher = nullptr)
: Binding(std::forward<ImplPtr>(impl)) {
Bind(request.TakeChannel(), dispatcher);
}
Binding(const Binding&) = delete;
Binding& operator=(const Binding&) = delete;
// The implementation of this class provides external references to class members via pointers.
// As a result, instances cannot be move-constructed or move-assigned.
Binding(Binding&&) = delete;
Binding& operator=(Binding&&) = delete;
// Completes a binding by creating a new channel, binding one endpoint to
// the previously specified implementation and returning the other endpoint.
//
// If |NewBinding| fails to create the underlying channel, the returned
// |InterfaceHandle| will return false from |is_valid()|.
//
// Uses the given async_dispatcher_t (e.g., a message loop) in order to read
// messages from the channel and to monitor the channel for
// |ZX_CHANNEL_PEER_CLOSED|. If |dispatcher| is null, the current thread must
// have a default async_dispatcher_t.
InterfaceHandle<Interface> NewBinding(async_dispatcher_t* dispatcher = nullptr) {
InterfaceHandle<Interface> client;
Bind(client.NewRequest().TakeChannel(), dispatcher);
return client;
}
// Binds the previously specified implementation to the given |channel|.
//
// If the |Binding| was previously bound to another channel, that channel is
// closed.
//
// Uses the given async_dispatcher_t (e.g., a message loop) in order to read
// messages from the channel and to monitor the channel for
// |ZX_CHANNEL_PEER_CLOSED|. If |dispatcher| is null, the current thread must
// have a default async_dispatcher_t.
//
// Returns an error if the binding was not able to be created (e.g., because
// the |channel| lacks |ZX_RIGHT_WAIT|).
zx_status_t Bind(zx::channel channel, async_dispatcher_t* dispatcher = nullptr) {
return controller_.reader().Bind(std::move(channel), dispatcher);
}
// Binds the previously specified implementation to the given
// |InterfaceRequest|.
//
// If the |Binding| was previously bound to another channel, that channel is
// closed.
//
// Uses the given async_dispatcher_t (e.g., a message loop) in order to read
// messages from the channel and to monitor the channel for
// |ZX_CHANNEL_PEER_CLOSED|. If |dispatcher| is null, the current thread must
// have a default async_dispatcher_t.
//
// Returns an error if the binding was not able to be created (e.g., because
// the |channel| lacks |ZX_RIGHT_WAIT|).
zx_status_t Bind(InterfaceRequest<Interface> request, async_dispatcher_t* dispatcher = nullptr) {
return Bind(request.TakeChannel(), dispatcher);
}
// Unbinds the underlying channel from this binding and returns it so it can
// be used in another context, such as on another thread or with a different
// implementation.
//
// After this function returns, the |Binding| is ready to be bound to another
// channel.
InterfaceRequest<Interface> Unbind() {
return InterfaceRequest<Interface>(controller_.reader().Unbind());
}
// Sends an Epitaph over the bound channel corresponding to the error passed
// as a parameter, closes the channel, and unbinds it. An Epitaph is the last
// message sent over a channel before a close operation; for the purposes of
// this function, it can be thought of as a return code. See the FIDL
// language spec for more information about Epitaphs.
//
// The return value can be any of the return values of zx_channel_write.
zx_status_t Close(zx_status_t epitaph_value) { return controller_.reader().Close(epitaph_value); }
// Blocks the calling thread until either a message arrives on the previously
// bound channel or an error occurs.
//
// Returns an error if waiting for the message, reading the message, or
// processing the message fails. If the error results in the channel being
// closed, the error handler will be called synchronously before this
// method returns.
//
// This method can be called only if this |Binding| is currently bound to a
// channel.
zx_status_t WaitForMessage() {
return controller_.reader().WaitAndDispatchOneMessageUntil(zx::time::infinite());
}
// Whether an error handler has been set.
//
// See |set_error_handler()|.
constexpr bool has_error_handler() const { return controller_.reader().has_error_handler(); }
// Sets an error handler that will be called if an error causes the underlying
// channel to be closed.
//
// If the error is being reported because an error occurred on the local side
// of the channel, the zx_status_t of that error will be passed as the
// parameter to the handler.
//
// For example, the error handler will be called if the remote side of the
// channel sends an invalid message. When the error handler is called, the
// |Binding| will no longer be bound to the channel.
void set_error_handler(fit::function<void(zx_status_t)> error_handler) {
controller_.reader().set_error_handler(std::move(error_handler));
}
// The implementation used by this |Binding| to process incoming messages.
const ImplPtr& impl() const { return impl_; }
// The interface for sending events back to the client.
typename Interface::EventSender_& events() { return stub_; }
// Whether this |Binding| is currently listening to a channel.
bool is_bound() const { return controller_.reader().is_bound(); }
// The underlying channel.
const zx::channel& channel() const { return controller_.reader().channel(); }
// The |async_dispatcher_t| to which this binding is bound, if any.
async_dispatcher_t* dispatcher() const { return controller_.reader().dispatcher(); }
private:
const ImplPtr impl_;
typename Interface::Stub_ stub_;
internal::StubController controller_;
};
} // namespace fidl
#endif // LIB_FIDL_CPP_BINDING_H_