| // 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_HANDLE_H_ | |
| #define LIB_FIDL_CPP_INTERFACE_HANDLE_H_ | |
| #include <lib/zx/channel.h> | |
| #include <zircon/assert.h> | |
| #include <cstddef> | |
| #include <utility> | |
| #include "lib/fidl/cpp/clone.h" | |
| #include "lib/fidl/cpp/coding_traits.h" | |
| #include "lib/fidl/cpp/interface_request.h" | |
| namespace fidl { | |
| class Builder; | |
| template <typename Interface> | |
| class InterfacePtr; | |
| template <typename Interface> | |
| class SynchronousInterfacePtr; | |
| // The client endpoint of a FIDL channel. | |
| // | |
| // The remote end of the channel expects this end of the channel to speak the | |
| // protocol associated with |Interface|. This type is the dual of | |
| // |InterfaceRequest|. | |
| // | |
| // Unlike an |InterfacePtr|, an |InterfaceHandle| does not have thread affinity | |
| // and can therefore be transferred to another thread or another process. To | |
| // create an |InterfacePtr| to send messages on this channel, call the |Bind()| | |
| // method, either on the |InterfaceHandle| or the |InterfacePtr| object. | |
| // | |
| // See also: | |
| // | |
| // * |InterfaceRequest|, which is the server analog of an |InterfaceHandle|. | |
| template <typename Interface> | |
| class InterfaceHandle final { | |
| public: | |
| // Creates an |InterfaceHandle| whose underlying channel is invalid. | |
| InterfaceHandle() = default; | |
| // Creates an |InterfaceHandle| that wraps the given |channel|. | |
| explicit InterfaceHandle(zx::channel channel) : channel_(std::move(channel)) {} | |
| InterfaceHandle(const InterfaceHandle& other) = delete; | |
| InterfaceHandle& operator=(const InterfaceHandle& other) = delete; | |
| InterfaceHandle(InterfaceHandle&& other) : channel_(std::move(other.channel_)) {} | |
| InterfaceHandle& operator=(InterfaceHandle&& other) { | |
| channel_ = std::move(other.channel_); | |
| return *this; | |
| } | |
| // Implicit conversion from nullptr to an |InterfaceHandle| without a valid | |
| // |channel|. | |
| InterfaceHandle(std::nullptr_t) {} | |
| // Implicit conversion from |InterfacePtr| unbinds the channel from the | |
| // |InterfacePtr|. | |
| // | |
| // This requires the caller to provide an rvalue reference, as the caller's | |
| // InterfacePtr is effectively moved out of. | |
| // | |
| // Making this constructor templated ensures that it is not type-instantiated | |
| // unless it is used, making the InterfacePtr<->InterfaceHandle codependency | |
| // less fragile. | |
| // | |
| // The std::enable_if_t avoids creation of unintended implicit type | |
| // conversions (especially from anything else that has an "Unbind()"), | |
| // presumably due to InterfacePtrType being inferred to be something other | |
| // than InterfacePtr<Interface>. However, if a caller is trying to use a type | |
| // that's only incorrect due to not being an rvalue reference, we do permit | |
| // this constructor to be selected, but then static_assert() with a message | |
| // suggesting std::move(). | |
| template <typename InterfacePtrType = InterfacePtr<Interface>, | |
| typename std::enable_if_t< | |
| std::is_same<InterfacePtr<Interface>, | |
| typename std::remove_reference<InterfacePtrType>::type>::value || | |
| std::is_same<SynchronousInterfacePtr<Interface>, | |
| typename std::remove_reference<InterfacePtrType>::type>::value, | |
| int> | |
| zero_not_used = 0> | |
| InterfaceHandle(InterfacePtrType&& ptr) { | |
| static_assert(std::is_same<InterfacePtr<Interface>&&, decltype(ptr)>::value || | |
| std::is_same<SynchronousInterfacePtr<Interface>&&, decltype(ptr)>::value, | |
| "Implicit conversion from InterfacePtr<> (or " | |
| "SynchronousInterfacePtr<>) to InterfaceHandle<> requires an rvalue " | |
| "reference. Maybe there's a missing std::move(), or consider " | |
| "using/providing an InterfaceHandle<> directly instead (particularly " | |
| "if the usage prior to this conversion doesn't need to send or receive " | |
| "messages)."); | |
| *this = ptr.Unbind(); | |
| } | |
| // Creates a new channel, retains one endpoint in this |InterfaceHandle| and | |
| // returns the other as an |InterfaceRequest|. | |
| // | |
| // Typically, the returned |InterfaceRequest| is passed to another process, | |
| // which will implement the server endpoint for the |Interface| protocol. | |
| // | |
| // If |NewRequest| fails to create the underlying channel, the returned | |
| // |InterfaceRequest| will return false from |is_valid()|. | |
| InterfaceRequest<Interface> NewRequest() { | |
| zx::channel h1, h2; | |
| if (zx::channel::create(0, &h1, &h2) != ZX_OK) | |
| return nullptr; | |
| channel_ = std::move(h1); | |
| return InterfaceRequest<Interface>(std::move(h2)); | |
| } | |
| // Creates an |InterfacePtr| bound to the channel in this |InterfaceHandle|. | |
| // | |
| // This function transfers ownership of the underlying channel to the | |
| // returned |InterfacePtr|, which means the |is_valid()| method will return | |
| // false after this method returns. | |
| // | |
| // Requires the current thread to have a default 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|. | |
| // | |
| // Making this method templated ensures that it is not type-instantiated | |
| // unless it is used, making the InterfacePtr<->InterfaceHandle codependency | |
| // less fragile. | |
| template <typename InterfacePtr = InterfacePtr<Interface>> | |
| inline InterfacePtr Bind() { | |
| InterfacePtr ptr; | |
| ptr.Bind(std::move(channel_)); | |
| return ptr; | |
| } | |
| template <typename SyncInterfacePtr = SynchronousInterfacePtr<Interface>> | |
| inline SyncInterfacePtr BindSync() { | |
| SyncInterfacePtr ptr; | |
| ptr.Bind(std::move(channel_)); | |
| return ptr; | |
| } | |
| // Whether the underlying channel is valid. | |
| bool is_valid() const { return !!channel_; } | |
| explicit operator bool() const { return is_valid(); } | |
| // Transfers ownership of the underlying channel to the caller. | |
| zx::channel TakeChannel() { return std::move(channel_); } | |
| // The underlying channel. | |
| const zx::channel& channel() const { return channel_; } | |
| void set_channel(zx::channel channel) { channel_ = std::move(channel); } | |
| void Encode(Encoder* encoder, size_t offset) { encoder->EncodeHandle(&channel_, offset); } | |
| static void Decode(Decoder* decoder, InterfaceHandle<Interface>* value, size_t offset) { | |
| decoder->DecodeHandle(&value->channel_, offset); | |
| } | |
| private: | |
| zx::channel channel_; | |
| }; | |
| // Equality. | |
| template <typename T> | |
| struct Equality<InterfaceHandle<T>> { | |
| bool operator()(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) const { | |
| return lhs.channel() == rhs.channel(); | |
| } | |
| }; | |
| template <typename T> | |
| struct CodingTraits<InterfaceHandle<T>> | |
| : public EncodableCodingTraits<InterfaceHandle<T>, sizeof(zx_handle_t)> {}; | |
| template <typename T> | |
| inline zx_status_t Clone(const InterfaceHandle<T>& value, InterfaceHandle<T>* result) { | |
| if (!value) { | |
| *result = InterfaceHandle<T>(); | |
| return ZX_OK; | |
| } | |
| return ZX_ERR_ACCESS_DENIED; | |
| } | |
| } // namespace fidl | |
| #endif // LIB_FIDL_CPP_INTERFACE_HANDLE_H_ |