|  | // 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_SYS_CPP_SERVICE_DIRECTORY_H_ | 
|  | #define LIB_SYS_CPP_SERVICE_DIRECTORY_H_ | 
|  |  | 
|  | #include <fuchsia/io/cpp/fidl.h> | 
|  | #include <lib/fidl/cpp/interface_ptr.h> | 
|  | #include <lib/fidl/cpp/interface_request.h> | 
|  | #include <lib/zx/channel.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | namespace sys { | 
|  |  | 
|  | // A directory of services provided by another component. | 
|  | // | 
|  | // These services are typically received by the component through its namespace, | 
|  | // specifically through the "/svc" entry. | 
|  | // | 
|  | // Instances of this class are thread-safe. | 
|  | class ServiceDirectory final { | 
|  | public: | 
|  | // Create an directory of services backed by given |directory|. | 
|  | // | 
|  | // Requests for services are routed to entries in this directory. | 
|  | // | 
|  | // The directory is expected to implement the |fuchsia.io.Directory| protocol. | 
|  | explicit ServiceDirectory(zx::channel directory); | 
|  | explicit ServiceDirectory(fidl::InterfaceHandle<fuchsia::io::Directory> directory); | 
|  |  | 
|  | ~ServiceDirectory(); | 
|  |  | 
|  | // ServiceDirectory objects cannot be copied. | 
|  | ServiceDirectory(const ServiceDirectory&) = delete; | 
|  | ServiceDirectory& operator=(const ServiceDirectory&) = delete; | 
|  |  | 
|  | // ServiceDirectory objects can be moved. | 
|  | ServiceDirectory(ServiceDirectory&& other) : directory_(std::move(other.directory_)) {} | 
|  | ServiceDirectory& operator=(ServiceDirectory&& other) { | 
|  | directory_ = std::move(other.directory_); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | // Create an directory of services from this component's namespace. | 
|  | // | 
|  | // Uses the "/svc" entry in the namespace as the backing directory for the | 
|  | // returned directory of services. | 
|  | // | 
|  | // Rather than creating a new |ServiceDirectory| consider passing |svc()| from | 
|  | // your |ComponentContext| around as that makes your code unit testable and | 
|  | // consumes one less kernel handle. | 
|  | static std::shared_ptr<ServiceDirectory> CreateFromNamespace(); | 
|  |  | 
|  | // Create a directory of services and return a request for an implementation | 
|  | // of the underlying directory in |out_request|. | 
|  | // | 
|  | // Useful when creating components. | 
|  | static std::shared_ptr<ServiceDirectory> CreateWithRequest(zx::channel* out_request); | 
|  | static std::shared_ptr<ServiceDirectory> CreateWithRequest( | 
|  | fidl::InterfaceRequest<fuchsia::io::Directory>* out_request); | 
|  |  | 
|  | // Connect to an interface in the directory. | 
|  | // | 
|  | // The discovery name of the interface is inferred from the C++ type of the | 
|  | // interface. Callers can supply an interface name explicitly to override | 
|  | // the default name. | 
|  | // | 
|  | // This overload for |Connect| discards the status of the underlying | 
|  | // connection operation. Callers that wish to recieve that status should use | 
|  | // one of the other overloads that returns a |zx_status_t|. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // auto controller = directory.Connect<fuchsia::foo::Controller>(); | 
|  | // ``` | 
|  | template <typename Interface> | 
|  | fidl::InterfacePtr<Interface> Connect( | 
|  | const std::string& interface_name = Interface::Name_) const { | 
|  | fidl::InterfacePtr<Interface> result; | 
|  | Connect(result.NewRequest(), interface_name); | 
|  | return std::move(result); | 
|  | } | 
|  |  | 
|  | // Connect to an interface in the directory. | 
|  | // | 
|  | // The discovery name of the interface is inferred from the C++ type of the | 
|  | // interface request. Callers can supply an interface name explicitly to | 
|  | // override the default name. | 
|  | // | 
|  | // Returns whether the request was successfully sent to the remote directory | 
|  | // backing this service bundle. | 
|  | // | 
|  | // # Errors | 
|  | // | 
|  | // ZX_ERR_UNAVAILABLE: The directory backing this service bundle is invalid. | 
|  | // | 
|  | // ZX_ERR_ACCESS_DENIED: This service bundle has insufficient rights to | 
|  | // connect to services. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // fuchsia::foo::ControllerPtr controller; | 
|  | // directory.Connect(controller.NewRequest()); | 
|  | // ``` | 
|  | template <typename Interface> | 
|  | zx_status_t Connect(fidl::InterfaceRequest<Interface> request, | 
|  | const std::string& interface_name = Interface::Name_) const { | 
|  | return Connect(interface_name, request.TakeChannel()); | 
|  | } | 
|  |  | 
|  | // Connect to an interface in the directory. | 
|  | // | 
|  | // The interface name and the channel must be supplied explicitly. | 
|  | // | 
|  | // Returns whether the request was successfully sent to the remote directory | 
|  | // backing this service bundle. | 
|  | // | 
|  | // # Errors | 
|  | // | 
|  | // ZX_ERR_UNAVAILABLE: The directory backing this service bundle is invalid. | 
|  | // | 
|  | // ZX_ERR_ACCESS_DENIED: This service bundle has insufficient rights to | 
|  | // connect to services. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // zx::channel controller, request; | 
|  | // zx_status_t status = zx::channel::create(0, &controller, &request); | 
|  | // if (status != ZX_OK) { | 
|  | //   [...] | 
|  | // } | 
|  | // directory.Connect("fuchsia.foo.Controller", std::move(request)); | 
|  | // ``` | 
|  | zx_status_t Connect(const std::string& interface_name, zx::channel request) const; | 
|  |  | 
|  | // Clone underlying directory channel. | 
|  | // | 
|  | // This overload for |CloneHandle| discards the status of the underlying | 
|  | // operation. Callers that wish to recieve that status should use | 
|  | // other overload that returns a |zx_status_t|. | 
|  | fidl::InterfaceHandle<fuchsia::io::Directory> CloneChannel() const; | 
|  |  | 
|  | // Clone underlying directory channel. | 
|  | // | 
|  | // Returns whether the request was successfully sent to the remote directory | 
|  | // backing this service bundle. | 
|  | // | 
|  | // # Errors | 
|  | // | 
|  | // ZX_ERR_UNAVAILABLE: The directory backing this service bundle is invalid. | 
|  | // | 
|  | // Other transport and application-level errors associated with | 
|  | // |fuchsia.io.Node/Clone|. | 
|  | // | 
|  | // # Example | 
|  | // | 
|  | // ``` | 
|  | // fuchsia::io::DirectoryPtr dir; | 
|  | // directory.CloneHandle(dir.NewRequest()); | 
|  | // ``` | 
|  | zx_status_t CloneChannel(fidl::InterfaceRequest<fuchsia::io::Directory>) const; | 
|  |  | 
|  | private: | 
|  | // The directory to which connection requests are routed. | 
|  | // | 
|  | // Implements |fuchsia.io.Directory| protocol. | 
|  | zx::channel directory_; | 
|  | }; | 
|  |  | 
|  | }  // namespace sys | 
|  |  | 
|  | #endif  // LIB_SYS_CPP_SERVICE_DIRECTORY_H_ |