| // 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 prevously 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 prevously 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_ |