| // 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_LLCPP_SERVER_H_ |
| #define LIB_FIDL_LLCPP_SERVER_H_ |
| |
| #include <lib/fidl/llcpp/async_binding.h> |
| |
| namespace fidl { |
| |
| // Forward declarations. |
| template <typename Protocol> |
| class ServerBindingRef; |
| |
| template <typename Interface> |
| fit::result<ServerBindingRef<typename Interface::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, Interface* impl); |
| template <typename Interface> |
| fit::result<ServerBindingRef<typename Interface::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, Interface* impl, |
| OnUnboundFn<Interface> on_unbound); |
| template <typename Interface> |
| fit::result<ServerBindingRef<typename Interface::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, std::unique_ptr<Interface> impl); |
| |
| namespace internal { |
| |
| // The interface for dispatching incoming FIDL messages. The code generator |
| // will provide conforming implementations for relevant FIDL protocols. |
| class IncomingMessageDispatcher { |
| public: |
| virtual ~IncomingMessageDispatcher() = default; |
| |
| // Dispatches an incoming message to one of the handlers functions in the |
| // protocol. If there is no matching handler, closes all the handles in |
| // |msg| and closes the channel with a |ZX_ERR_NOT_SUPPORTED| epitaph, before |
| // returning false. The message should then be discarded. |
| // |
| // Note that the |dispatch_message| name avoids conflicts with FIDL method |
| // names which would appear on the subclasses. |
| // |
| // Always consumes the handles in |msg|. |
| virtual ::fidl::DispatchResult dispatch_message(fidl_incoming_msg_t* msg, |
| ::fidl::Transaction* txn) = 0; |
| }; |
| |
| template <typename Protocol> |
| fit::result<ServerBindingRef<Protocol>, zx_status_t> BindServerImpl( |
| async_dispatcher_t* dispatcher, zx::channel channel, IncomingMessageDispatcher* interface, |
| AnyOnUnboundFn on_unbound); |
| |
| // Defines an incoming method entry. Used by a server to dispatch an incoming message. |
| struct MethodEntry { |
| // The ordinal of the method handled by the entry. |
| uint64_t ordinal; |
| // The coding table of the method (used to decode the message). |
| const fidl_type_t* type; |
| // The function which handles the decoded message. |
| void (*dispatch)(void* interface, void* bytes, ::fidl::Transaction* txn); |
| }; |
| |
| // The compiler generates an array of MethodEntry for each protocol. |
| // The TryDispatch method for each protocol calls this function using the generated entries, which |
| // searches through the array using the method ordinal to find the corresponding dispatch function. |
| ::fidl::DispatchResult TryDispatch(void* impl, fidl_incoming_msg_t* msg, ::fidl::Transaction* txn, |
| MethodEntry* begin, MethodEntry* end); |
| |
| } // namespace internal |
| |
| // This class manages a server connection and its binding to an |
| // async_dispatcher_t* (which may be multi-threaded). See the detailed |
| // documentation on the |BindServer()| APIs below. |
| template <typename Protocol> |
| class ServerBindingRef { |
| public: |
| ~ServerBindingRef() = default; |
| |
| ServerBindingRef(ServerBindingRef&&) = default; |
| ServerBindingRef& operator=(ServerBindingRef&&) = default; |
| |
| ServerBindingRef(const ServerBindingRef&) = default; |
| ServerBindingRef& operator=(const ServerBindingRef&) = default; |
| |
| // Triggers an asynchronous unbind operation. If specified, |on_unbound| will be invoked on a |
| // dispatcher thread, passing in the channel and the unbind reason. On return, the dispatcher |
| // will no longer have any wait associated with the channel (though handling of any already |
| // in-flight transactions will continue). |
| // |
| // This may be called from any thread. |
| // |
| // WARNING: While it is safe to invoke Unbind() from any thread, it is unsafe to wait on the |
| // OnUnboundFn from a dispatcher thread, as that will likely deadlock. |
| void Unbind() { |
| if (auto binding = event_sender_.binding_.lock()) |
| binding->Unbind(std::move(binding)); |
| } |
| |
| // Triggers an asynchronous unbind operation. Eventually, the epitaph will be sent over the |
| // channel which will be subsequently closed. If specified, |on_unbound| will be invoked giving |
| // the unbind reason as an argument. |
| // |
| // This may be called from any thread. |
| void Close(zx_status_t epitaph) { |
| if (auto binding = event_sender_.binding_.lock()) |
| binding->Close(std::move(binding), epitaph); |
| } |
| |
| // Return the interface for sending FIDL events. If the server has been unbound, calls on the |
| // interface return error with status ZX_ERR_CANCELED. |
| const typename Protocol::WeakEventSender* get() const { return &event_sender_; } |
| const typename Protocol::WeakEventSender* operator->() const { return &event_sender_; } |
| const typename Protocol::WeakEventSender& operator*() const { return event_sender_; } |
| |
| private: |
| friend fit::result<ServerBindingRef<Protocol>, zx_status_t> internal::BindServerImpl<Protocol>( |
| async_dispatcher_t* dispatcher, zx::channel channel, |
| internal::IncomingMessageDispatcher* interface, internal::AnyOnUnboundFn on_unbound); |
| |
| explicit ServerBindingRef(std::weak_ptr<internal::AsyncServerBinding<Protocol>> internal_binding) |
| : event_sender_(std::move(internal_binding)) {} |
| |
| typename Protocol::WeakEventSender event_sender_; |
| }; |
| |
| // Binds an implementation of a low-level C++ server interface to |channel| using a potentially |
| // multi-threaded |dispatcher|. This implementation allows for multiple in-flight synchronously or |
| // asynchronously handled transactions. |
| // |
| // This function adds an asynchronous wait to the given |dispatcher| for new messages to arrive on |
| // |channel|. When a message arrives, the dispatch function corresponding to the interface is called |
| // on one of the |dispatcher| threads. |
| // |
| // Typically, the dispatch function is generated by the low-level C++ backend for FIDL interfaces. |
| // These dispatch functions decode the |fidl_incoming_msg_t| and call into the implementation of the |
| // FIDL interface, via its C++ vtable. |
| // |
| // Creation: |
| // - Upon success |BindServer| creates a binding that owns |channel|. In this case, the binding is |
| // initially kept alive even if the returned fit::result with a |ServerBindingRef| is ignored. |
| // - |ServerBindingRef| is a reference to the binding, it does not hold the binding. To unbind the |
| // binding, see Unbind below. |
| // - Upon any error creating the binding, |BindServer| returns a fit::error and |channel| is closed. |
| // |
| // Destruction: |
| // - If the returned |ServerBindingRef| is ignored or dropped some time during the server operation, |
| // then if some error occurs (see below) the binding will be automatically destroyed. |
| // - If the returned |ServerBindingRef| is kept but an error occurs (see below), the binding will be |
| // destroyed, though calls may still be made on the |ServerBindingRef|. |
| // - On an error, |channel| is unbound from the dispatcher, i.e. no dispatcher threads will interact |
| // with it. Calls on inflight |Transaction|s will have no effect. If |on_unbound| is not |
| // specified, the |channel| is closed. If specified, |on_unbound| is then executed on a |
| // |dispatcher| thread allowing the user to process the error. |on_unbound| includes the server |
| // end of the channel as a parameter, if ignored the channel will be closed at the end of |
| // |on_unbound|'s scope. |
| // |
| // Unbind: |
| // - The |ServerBindingRef| can be used to explicitly |Unbind| the binding and retrieve the |
| // |channel| endpoint. |
| // - |Unbind| is non-blocking with respect to user code paths, i.e. if it blocks, it does so on |
| // deterministic internal code paths. As such, the user may safely synchronize around an |Unbind| |
| // call. |
| // - In order to reclaim the |channel|, the user must specify an |on_unbound| hook. This will be |
| // invoked after the |channel| has been unbound from the |dispatcher|. The |channel| will be given |
| // as an argument to the hook. |
| // - If the user shuts down the |dispatcher| prior to the |on_unbound| hook running, it may be |
| // dropped instead. |
| // |
| // Close: |
| // - |Close| is similar to |Unbind| except that it causes an epitaph message to be sent on the |
| // |channel|. |
| // - If specified, the |on_unbound| hook will execute after the epitaph has been sent and like in |
| // |Unbind| the |channel| will be given as an argument to the hook and if unused it will be closed |
| // at the end of the hook scope. |
| // |
| // Error conditions: |
| // - When an error occurs in the server implementation as part of handling a message, it may call |
| // |Close| on the completer to indicate the error condition. |
| // - If the client end of the channel gets closed (PEER_CLOSED). |
| // - If an error occurs in the binding itself, e.g. a channel write fails. |
| // |
| // Ordering: |
| // - By default, the message dispatch function for a binding will only ever be invoked by a single |
| // |dispatcher| thread at a time. |
| // - To enable more concurrency, the user may invoke |EnableNextDispatch| on the |
| // |fidl::Completer<T>::Sync| from the dispatch function. This will resume the async wait on the |
| // |dispatcher| before the dispatch function returns, allowing other |dispatcher| threads to |
| // handle messages for the same binding. |
| // NOTE: If a particular user does not care about ordering, they may invoke |EnableNextDispatch| |
| // immediately in the message handler. However, this functionality could instead be provided as a |
| // default configuration. If you have such a usecase, please contact madhaviyengar@ or yifeit@. |
| // |
| // The following |BindServer()| APIs infer the protocol type based on the server implementation |
| // which must publicly inherit from the appropriate |<Protocol_Name>::Interface| class. |
| template <typename ServerImpl> |
| fit::result<ServerBindingRef<typename ServerImpl::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, ServerImpl* impl) { |
| return internal::BindServerImpl<typename ServerImpl::_EnclosingProtocol>( |
| dispatcher, std::move(channel), impl, nullptr); |
| } |
| |
| // As above, but will invoke |on_unbound| on |impl| when the channel is being unbound, either due to |
| // error or an explicit |Close| or |Unbind|. |
| // |
| // NOTE: |on_unbound| will generally be executed from a |dispatcher| thread. However, on |
| // |dispatcher| shutdown, any active bindings will be unbound, thus it may also be executed on the |
| // thread invoking shutdown. The user must ensure that shutdown is never invoked while holding locks |
| // which |on_unbound| may also take. |
| template <typename ServerImpl> |
| fit::result<ServerBindingRef<typename ServerImpl::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, ServerImpl* impl, |
| OnUnboundFn<ServerImpl> on_unbound) { |
| return internal::BindServerImpl<typename ServerImpl::_EnclosingProtocol>( |
| dispatcher, std::move(channel), impl, |
| [fn = std::move(on_unbound)](internal::IncomingMessageDispatcher* any_interface, |
| UnbindInfo info, zx::channel channel) mutable { |
| // Note: this cast may change the value of the pointer, due to how C++ |
| // implements classes with virtual tables. |
| auto* impl = static_cast<ServerImpl*>(any_interface); |
| fn(impl, info, std::move(channel)); |
| }); |
| } |
| |
| // Similar to the first variant, however, the user gives the binding ownership of the server |
| // implementation. In order to destroy the implementation on unbind, the unique_ptr is passed to a |
| // hook which will be automatically invoked during unbinding. |
| // |
| // NOTE: The same restriction on |on_unbound| in the previous variant applies to ~Interface(). |
| template <typename ServerImpl> |
| fit::result<ServerBindingRef<typename ServerImpl::_EnclosingProtocol>, zx_status_t> BindServer( |
| async_dispatcher_t* dispatcher, zx::channel channel, std::unique_ptr<ServerImpl> impl) { |
| ServerImpl* impl_raw = impl.get(); |
| return internal::BindServerImpl<typename ServerImpl::_EnclosingProtocol>( |
| dispatcher, std::move(channel), impl_raw, |
| [impl = std::move(impl)](internal::IncomingMessageDispatcher* interface, UnbindInfo info, |
| zx::channel channel) {}); |
| } |
| |
| namespace internal { |
| |
| // Binds an implementation of some FIDL server protocol |interface| to |channel|. |
| // |
| // |interface| should be a pointer to some |FidlProtocol::Interface| class. |
| // |
| // |dispatch_fn| looks up an incoming FIDL message in the associated protocol |
| // and possibly invokes a handler on |interface|, which will be provided as |
| // the first argument. |
| // |
| // |on_unbound| will be called with |interface| if |on_unbound| is specified. |
| // The public |fidl::BindServer| functions should translate |interface| back to |
| // the user pointer type, possibly at an offset, before invoking the |
| // user-provided on-unbound handler. |
| template <typename Protocol> |
| fit::result<ServerBindingRef<Protocol>, zx_status_t> BindServerImpl( |
| async_dispatcher_t* dispatcher, zx::channel channel, IncomingMessageDispatcher* interface, |
| internal::AnyOnUnboundFn on_unbound) { |
| auto internal_binding = internal::AsyncServerBinding<Protocol>::Create( |
| dispatcher, std::move(channel), interface, std::move(on_unbound)); |
| auto status = internal_binding->BeginWait(); |
| if (status == ZX_OK) { |
| return fit::ok(fidl::ServerBindingRef<Protocol>(std::move(internal_binding))); |
| } else { |
| return fit::error(status); |
| } |
| } |
| |
| } // namespace internal |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_LLCPP_SERVER_H_ |