| // Copyright 2019 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_ASYNC_CPP_BIND_H_ |
| #define LIB_FIDL_ASYNC_CPP_BIND_H_ |
| |
| #include <lib/async/wait.h> |
| #include <lib/fidl-async/bind.h> |
| #include <lib/fidl-async/cpp/channel_transaction.h> |
| #include <lib/fidl/llcpp/transaction.h> |
| #include <lib/fit/function.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/fidl.h> |
| |
| namespace fidl { |
| |
| template <typename Interface> |
| using OnChannelClosedFn = fit::callback<void(Interface*)>; |
| |
| namespace internal { |
| |
| using TypeErasedDispatchFn = bool (*)(void*, fidl_msg_t*, ::fidl::Transaction*); |
| |
| using TypeErasedOnChannelClosedFn = fit::callback<void(void*)>; |
| |
| zx_status_t TypeErasedBind(async_dispatcher_t* dispatcher, zx::channel channel, void* impl, |
| TypeErasedDispatchFn dispatch_fn, |
| TypeErasedOnChannelClosedFn on_channel_closed_fn); |
| |
| class SimpleBinding : private async_wait_t { |
| public: |
| SimpleBinding(async_dispatcher_t* dispatcher, zx::channel channel, void* impl, |
| TypeErasedDispatchFn dispatch_fn, TypeErasedOnChannelClosedFn on_channel_closed_fn); |
| |
| ~SimpleBinding(); |
| |
| static void MessageHandler(async_dispatcher_t* dispatcher, async_wait_t* wait, zx_status_t status, |
| const zx_packet_signal_t* signal); |
| |
| private: |
| friend fidl::internal::ChannelTransaction; |
| friend zx_status_t BeginWait(std::unique_ptr<SimpleBinding>* unique_binding); |
| |
| zx::unowned_channel channel() const { return zx::unowned_channel(async_wait_t::object); } |
| |
| async_dispatcher_t* dispatcher_; |
| void* interface_; |
| TypeErasedDispatchFn dispatch_fn_; |
| TypeErasedOnChannelClosedFn on_channel_closed_fn_; |
| }; |
| |
| // Attempts to attach the binding onto the async dispatcher. |
| // Upon success, the binding ownership is transferred to the async dispatcher. |
| // Upon failure, the binding ownership stays in the |unique_ptr|. |
| // Returns the status of |async_begin_wait|. |
| zx_status_t BeginWait(std::unique_ptr<SimpleBinding>* unique_binding); |
| |
| } // namespace internal |
| |
| // Binds an implementation of a low-level C++ server interface to |channel| using |dispatcher|. |
| // |
| // This function adds an |async_wait_t| to the given |dispatcher| that waits |
| // asynchronously for new messages to arrive on |channel|. When a message |
| // arrives, the dispatch function corresponding to the interface is called |
| // on one of the threads associated with the |dispatcher|. |
| // |
| // Typically, the dispatch function is generated by the low-level C++ backend |
| // for FIDL interfaces. These dispatch functions decode the |fidl_msg_t| and |
| // call into the implementation of the FIDL interface, via its C++ vtable. |
| // |
| // When an error occurs in the server implementation as part of handling the message, it may call |
| // |Close(error)| on the completer to indicate the error condition to the dispatcher. |
| // The dispatcher will send an epitaph with this error code before closing the channel. |
| // |
| // Returns whether |fidl::Bind| was able to begin waiting on the given |channel|. |
| // Upon any error, |channel| is closed and the binding is terminated. |
| // |
| // The |dispatcher| takes ownership of the channel. Shutting down the |dispatcher| |
| // results in |channel| being closed. |
| // |
| // It is safe to shutdown the dispatcher at any time. |
| // |
| // It is unsafe to destroy the dispatcher from within a dispatch function. |
| // It is unsafe to destroy the dispatcher while any fidl::Transaction objects are alive. |
| template <typename Interface> |
| zx_status_t Bind(async_dispatcher_t* dispatcher, zx::channel channel, Interface* impl) { |
| return internal::TypeErasedBind(dispatcher, std::move(channel), impl, |
| &Interface::_Outer::TypeErasedDispatch, nullptr); |
| } |
| |
| // As above, but will invoke |on_channel_close_fn| on |impl| when either end of the channel |
| // is closed. |
| template <typename Interface> |
| zx_status_t Bind(async_dispatcher_t* dispatcher, zx::channel channel, Interface* impl, |
| OnChannelClosedFn<Interface> on_channel_close_fn) { |
| return internal::TypeErasedBind(dispatcher, std::move(channel), impl, |
| &Interface::_Outer::TypeErasedDispatch, |
| [fn = std::move(on_channel_close_fn)](void* impl) mutable { |
| fn(static_cast<Interface*>(impl)); |
| }); |
| } |
| |
| // As above, but will destroy |impl| when either end of the channel is closed. |
| template <typename Interface> |
| zx_status_t Bind(async_dispatcher_t* dispatcher, zx::channel channel, |
| std::unique_ptr<Interface> impl) { |
| OnChannelClosedFn<Interface> fn = [](Interface* impl) { delete impl; }; |
| return Bind(dispatcher, std::move(channel), impl.release(), std::move(fn)); |
| } |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_ASYNC_CPP_BIND_H_ |