| // 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_INTERFACE_PTR_H_ |
| #define LIB_FIDL_CPP_INTERFACE_PTR_H_ |
| |
| #include <lib/fit/function.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/assert.h> |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <utility> |
| |
| #include "lib/fidl/cpp/interface_handle.h" |
| #include "lib/fidl/cpp/interface_request.h" |
| #include "lib/fidl/cpp/internal/proxy_controller.h" |
| |
| namespace fidl { |
| |
| // A client interface to a remote implementation of |Interface|. |
| // |
| // An |InterfacePtr| implements |Interface| by proxying calls through a |
| // |channel| to a remote implementation of |Interface|. Method calls on the |
| // |Interface| proxy are encoded and sent through the bound channel to the |
| // remote endpoint, which processes them. If the remote endpoint has not yet |
| // been bound to an implementation, messages sent on the channel are buffered |
| // by the channel, allowing for *pipelined* operation. |
| // |
| // The |InterfacePtr| also keeps state about the connection and about |
| // outstanding request transactions that are expecting replies. When the |
| // |InterfacePtr| receives a reply to an outstanding transaction, the |
| // |InterfacePtr| decodes the reply and calls the appropriate callback on the |
| // thread to which the |InterfacePtr| was bound. |
| // |
| // You need to bind the |InterfacePtr| before calling any |Interface| methods. |
| // There are a number of ways to bind the |InterfacePtr|. See |NewRequest|, |
| // |Bind|, and the |Bind| method on |InterfaceHandle|. |
| // |
| // If the underlying channel experiences an error, the |InterfacePtr| will |
| // unbind from the channel and call its error handler. |
| // |
| // This class is thread-hostile, as is the local proxy it manages. All calls to |
| // this class or the proxy should be from the thread to which the |
| // |InterfacePtr| was bound. If you need to move the proxy to a different |
| // thread, extract the |InterfaceHandle| by calling |Unbind|, and pass the |
| // |InterfaceHandle| to a different thread, which the |InterfaceHandle| can be |
| // bound to an |InterfacePtr| again. This operation destroys the state about |
| // outstanding request transactions that are expecting replies. |
| // |
| // See also: |
| // |
| // * |Binding|, which is the server analog of an |InterfacePtr|. |
| // * |SynchronousInterfacePtr|, which is a synchronous client interface to a |
| // remote implementation. |
| template <typename Interface> |
| class InterfacePtr final { |
| public: |
| using Proxy = typename Interface::Proxy_; |
| |
| // Creates an unbound |InterfacePtr|. |
| InterfacePtr() : impl_(new Impl) {} |
| InterfacePtr(std::nullptr_t) : InterfacePtr() {} |
| |
| InterfacePtr(const InterfacePtr& other) = delete; |
| InterfacePtr& operator=(const InterfacePtr& other) = delete; |
| |
| InterfacePtr(InterfacePtr&& other) : impl_(std::move(other.impl_)) { |
| other.impl_.reset(new Impl); |
| } |
| |
| InterfacePtr& operator=(InterfacePtr&& other) { |
| if (this != &other) { |
| impl_ = std::move(other.impl_); |
| other.impl_.reset(new Impl); |
| } |
| return *this; |
| } |
| |
| // Bind the |InterfacePtr| to one endpoint of a newly created channel and |
| // return the other endpoint as an |InterfaceRequest|. |
| // |
| // Typically, the returned |InterfaceRequest| will be sent to a remote process |
| // to be bound to an implementation of |Interface| using a |Binding| object. |
| // |
| // After calling this method, clients can start calling methods on this |
| // |InterfacePtr|. The methods will write messages into the underlying |
| // channel created by |NewRequest|, where they will be buffered by the |
| // underlying channel until the |InterfaceRequest| is bound to an |
| // implementation of |Interface|, potentially in a remote process. |
| // |
| // Uses the given async_dispatcher_t 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. |
| // |
| // # Example |
| // |
| // Given the following interface: |
| // |
| // interface Database { |
| // OpenTable(request<Table> table); |
| // }; |
| // |
| // The client can use the |NewRequest| method to create the |InterfaceRequest| |
| // object needed by the |OpenTable| method: |
| // |
| // DatabasePtr database = ...; // Connect to database. |
| // TablePtr table; |
| // database->OpenTable(table.NewRequest()); |
| // |
| // The client can call methods on |table| immediately. |
| InterfaceRequest<Interface> NewRequest(async_dispatcher_t* dispatcher = nullptr) { |
| zx::channel h1; |
| zx::channel h2; |
| if (zx::channel::create(0, &h1, &h2) != ZX_OK || Bind(std::move(h1), dispatcher) != ZX_OK) |
| return nullptr; |
| return InterfaceRequest<Interface>(std::move(h2)); |
| } |
| |
| // Binds the |InterfacePtr| to the given |channel|. |
| // |
| // The |InterfacePtr| expects the remote end of the |channel| to speak the |
| // protocol defined by |Interface|. Unlike the |Bind| overload that takes a |
| // |InterfaceHandle| parameter, this |Bind| overload lacks type safety. |
| // |
| // If the |InterfacePtr| was prevously bound to another channel, that channel |
| // is closed. If the |channel| is invalid, then this method will effectively |
| // unbind the |InterfacePtr|. A more direct way to have that effect is to call |
| // |Unbind|. |
| // |
| // Uses the given async_dispatcher_t 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 impl_->controller.reader().Bind(std::move(channel), dispatcher); |
| } |
| |
| // Binds the |InterfacePtr| to the given |InterfaceHandle|. |
| // |
| // The |InterfacePtr| expects the remote end of the |channel| to speak the |
| // protocol defined by |Interface|. Unlike the |Bind| overload that takes a |
| // |channel| parameter, this |Bind| overload provides type safety. |
| // |
| // If the |InterfacePtr| was prevously bound to another channel, that channel |
| // is closed. If the |InterfaceHandle| is invalid, then this method will |
| // effectively unbind the |InterfacePtr|. A more direct way to have that |
| // effect is to call |Unbind|. |
| // |
| // Uses the given async_dispatcher_t 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(InterfaceHandle<Interface> handle, async_dispatcher_t* dispatcher = nullptr) { |
| return Bind(handle.TakeChannel(), dispatcher); |
| } |
| |
| // Unbinds the underlying channel from the |InterfacePtr|. |
| // |
| // The underlying channel is returned as an |InterfaceHandle|, which is safe |
| // to transport to another thread or process. Any callbacks waiting for |
| // replies from the remote endpoint are discarded and any outstanding |
| // transaction state is erased. |
| // |
| // After this method returns, a subsequent call to |Bind| is required before |
| // calling any additional |Interface| methods. |
| InterfaceHandle<Interface> Unbind() { |
| return InterfaceHandle<Interface>(impl_->controller.reader().Unbind()); |
| } |
| |
| // Whether this |InterfacePtr| is currently bound to a channel. |
| // |
| // If the |InterfacePtr| is bound to a channel, the |InterfacePtr| has |
| // affinity for the thread to which it was bound and calls to |Interface| |
| // methods are proxied to the remote endpoint of the channel. |
| // |
| // See also: |
| // |
| // * |Bind|, which binds a channel to this |InterfacePtr|. |
| // * |Unbind|, which unbinds a channel from this |InterfacePtr|. |
| bool is_bound() const { return impl_->controller.reader().is_bound(); } |
| |
| // Whether this |InterfacePtr| is currently bound to a channel. |
| // |
| // See |is_bound| for details. |
| explicit operator bool() const { return is_bound(); } |
| |
| // The |Interface| proxy associated with this |InterfacePtr|. |
| // |
| // When this |InterfacePtr| is bound, method calls on this |Interface| will |
| // be proxied to the remote endpoint of the connection. Methods that expect |
| // replies will retain the supplied callbacks until the |InterfacePtr| either |
| // receives a reply to that transaction or the |InterfacePtr| is unbound from |
| // the channel. |
| // |
| // When this |InterfacePtr| is not bound, calling methods on the returned |
| // |Interface| simply discards the arguments and closes any handles contained |
| // in those arguments. |
| // |
| // The returned |Interface| is thread-hostile and can be used only on the |
| // thread to which the |InterfacePtr| was bound. |
| Interface* get() const { return &impl_->proxy; } |
| Interface* operator->() const { return get(); } |
| Interface& operator*() const { return *get(); } |
| |
| // An object on which to register for FIDL events. |
| // |
| // Arriving events are dispatched to the callbacks stored on this object. |
| // Events for unbound callbacks are ignored. |
| Proxy& events() const { return impl_->proxy; } |
| |
| // 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. |
| // |
| // If an Epitaph was present on the channel, its error value will be passed as |
| // the parameter. See the FIDL language specification for more detail on |
| // Epitaphs. |
| // |
| // 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. |
| // |
| // WARNING: The |error_handler| is often called from the thread to which the |
| // |InterfacePtr| was bound, but the function can also be called from another |
| // thread if the |InterfacePtr| is still bound to the thread when the |
| // |async::Loop| for the thread is shutdown. |
| void set_error_handler(fit::function<void(zx_status_t)> error_handler) { |
| impl_->controller.reader().set_error_handler(std::move(error_handler)); |
| } |
| |
| // The underlying channel. |
| const zx::channel& channel() const { return impl_->controller.reader().channel(); } |
| |
| // The |async_dispatcher_t| to which this interface is bound, if any. |
| async_dispatcher_t* dispatcher() const { return impl_->controller.reader().dispatcher(); } |
| |
| private: |
| struct Impl; |
| |
| std::unique_ptr<Impl> impl_; |
| }; |
| |
| template <typename T> |
| struct InterfacePtr<T>::Impl { |
| Impl() : proxy(&controller) { controller.set_proxy(&proxy); } |
| internal::ProxyController controller; |
| mutable Proxy proxy; |
| }; |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_CPP_INTERFACE_PTR_H_ |