| // 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_SYNCHRONOUS_INTERFACE_PTR_H_ |
| #define LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_ |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "lib/fidl/cpp/interface_handle.h" |
| |
| namespace fidl { |
| |
| // A synchronous client interface to a remote implementation of |Interface|. |
| // |
| // An |SynchronousInterfacePtr| 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 method has a reply (including |
| // any empty reply), the client blocks and waits for the remote endpoint to |
| // reply. |
| // |
| // You need to bind the |SynchronousInterfacePtr| before calling any |Interface| |
| // methods. There are a number of ways to bind the |SynchronousInterfacePtr|. |
| // See |NewRequest|, |Bind|, and the |BindSync| method on |InterfaceHandle|. |
| // |
| // This class is thread-compatible. Once bound, the |SynchronousInterfacePtr| |
| // can be used from multiple threads simultaneously. However, the |
| // |SynchronousInterfacePtr| does not attempt to synchronize mutating operatios, |
| // such as |Bind| or |Unbind|. |
| // |
| // |SynchronousInterfacePtr| does not require a |async_dispatcher_t| |
| // implementation and does not bind to the default |async_dispatcher_t*| for the |
| // current thread, unlike |InterfacePtr|. |
| // |
| // See also: |
| // |
| // * |Binding|, which is the server analog of an |SynchronousInterfacePtr|. |
| // * |InterfacePtr|, which is an asynchronous interface to a remote |
| // implementation. |
| template <typename Interface> |
| class SynchronousInterfacePtr final { |
| public: |
| using InterfaceSync = typename Interface::Sync_; |
| |
| // Creates an unbound |SynchronousInterfacePtr|. |
| SynchronousInterfacePtr() {} |
| SynchronousInterfacePtr(std::nullptr_t) {} |
| |
| SynchronousInterfacePtr(const SynchronousInterfacePtr& other) = delete; |
| SynchronousInterfacePtr& operator=(const SynchronousInterfacePtr& other) = delete; |
| |
| SynchronousInterfacePtr(SynchronousInterfacePtr&& other) = default; |
| SynchronousInterfacePtr& operator=(SynchronousInterfacePtr&& other) = default; |
| |
| // Bind the |SynchronousInterfacePtr| 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 |
| // |SynchronousInterfacePtr|. However, methods that have replies will block |
| // until the remote implementation binds the |InterfaceRequest| and replies. |
| // |
| // # 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. |
| // TableSyncPtr table; |
| // database->OpenTable(table.NewRequest()); |
| // |
| // The client can call methods on |table| immediately. Messages that have |
| // replies will block until the Database implementation binds a Table |
| // implementation and replies. |
| InterfaceRequest<Interface> NewRequest() { |
| zx::channel h1; |
| zx::channel h2; |
| if (zx::channel::create(0, &h1, &h2) != ZX_OK) |
| return nullptr; |
| Bind(std::move(h1)); |
| return InterfaceRequest<Interface>(std::move(h2)); |
| } |
| |
| // Binds the |SynchronousInterfacePtr| to the given |channel|. |
| // |
| // The |SynchronousInterfacePtr| 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 |SynchronousInterfacePtr| was prevously bound to another channel, |
| // that channel is closed. If the |channel| is invalid, then this method will |
| // effectively unbind the |SynchronousInterfacePtr|. A more direct way to have |
| // that effect is to call |Unbind|. |
| // |
| // Does not require the current thread to have a default async_dispatcher_t. |
| void Bind(zx::channel channel) { |
| if (!channel) { |
| proxy_.reset(); |
| return; |
| } |
| proxy_.reset(new typename InterfaceSync::Proxy_(std::move(channel))); |
| } |
| |
| // Binds the |SynchronousInterfacePtr| to the given |InterfaceHandle|. |
| // |
| // The |SynchronousInterfacePtr| 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 |SynchronousInterfacePtr| was prevously bound to another channel, |
| // that channel is closed. If the |InterfaceHandle| is invalid, then this |
| // method will effectively unbind the |SynchronousInterfacePtr|. A more direct |
| // way to have that effect is to call |Unbind|. |
| // |
| // Does not require the current thread to have a default async_dispatcher_t. |
| void Bind(InterfaceHandle<Interface> handle) { return Bind(handle.TakeChannel()); } |
| |
| // Unbinds the underlying channel from the |SynchronousInterfacePtr|. |
| // |
| // The underlying channel is returned as an |InterfaceHandle|, which is safe |
| // to transport to another thread or process. |
| // |
| // After this method returns, a subsequent call to |Bind| is required before |
| // calling any additional |Interface| methods. |
| InterfaceHandle<Interface> Unbind() { |
| InterfaceHandle<Interface> handle(proxy_->proxy_.TakeChannel()); |
| proxy_.reset(); |
| return handle; |
| } |
| |
| // Whether this |SynchronousInterfacePtr| is currently bound to a channel. |
| // |
| // If the |SynchronousInterfacePtr| is bound to a channel, calls to |
| // |Interface| methods are proxied to the remote endpoint of the channel. |
| // |
| // See also: |
| // |
| // * |Bind|, which binds a channel to this |SynchronousInterfacePtr|. |
| // * |Unbind|, which unbinds a channel from this |SynchronousInterfacePtr|. |
| bool is_bound() const { return static_cast<bool>(proxy_); } |
| |
| // Whether this |SynchronousInterfacePtr| is currently bound to a channel. |
| // |
| // See |is_bound| for details. |
| explicit operator bool() const { return is_bound(); } |
| |
| // The |Interface| proxy associated with this |SynchronousInterfacePtr|. |
| // |
| // When this |SynchronousInterfacePtr| is bound, method calls on this |
| // |Interface| will be proxied to the remote endpoint of the connection. |
| // Methods that expect replies will block until the |
| // |SynchronousInterfacePtr| either receives a reply to that transaction. |
| // |
| // When this |SynchronousInterfacePtr| is not bound, this method returns |
| // nullptr. |
| // |
| // The returned |Interface| is thread-compatible and can be used from any |
| // thread. |
| InterfaceSync* get() const { return proxy_.get(); } |
| InterfaceSync* operator->() const { return get(); } |
| InterfaceSync& operator*() const { return *get(); } |
| |
| // The underlying channel, or null channel if not currently bound. |
| zx::unowned_channel unowned_channel() const { |
| return proxy_ ? zx::unowned_channel(proxy_->proxy_.channel()) : zx::unowned_channel(); |
| } |
| |
| private: |
| std::unique_ptr<typename InterfaceSync::Proxy_> proxy_; |
| }; |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_ |