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