| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "lib/svc/cpp/service_namespace.h" |
| |
| #include <fcntl.h> |
| #include <fdio/util.h> |
| #include <zircon/device/vfs.h> |
| |
| #include <utility> |
| |
| #include "lib/fsl/tasks/message_loop.h" |
| #include "lib/fxl/files/unique_fd.h" |
| |
| namespace app { |
| |
| ServiceNamespace::ServiceNamespace() |
| : vfs_(fsl::MessageLoop::GetCurrent()->async()), |
| directory_(fbl::AdoptRef(new svcfs::VnodeDir())) {} |
| |
| ServiceNamespace::ServiceNamespace( |
| fidl::InterfaceRequest<app::ServiceProvider> request) |
| : ServiceNamespace() { |
| AddBinding(std::move(request)); |
| } |
| |
| ServiceNamespace::~ServiceNamespace() { |
| directory_->RemoveAllServices(); |
| directory_ = nullptr; |
| } |
| |
| void ServiceNamespace::AddBinding( |
| fidl::InterfaceRequest<app::ServiceProvider> request) { |
| if (request) |
| bindings_.AddBinding(this, std::move(request)); |
| } |
| |
| void ServiceNamespace::Close() { |
| bindings_.CloseAllBindings(); |
| } |
| |
| void ServiceNamespace::AddServiceForName(ServiceConnector connector, |
| const std::string& service_name) { |
| name_to_service_connector_[service_name] = std::move(connector); |
| directory_->AddService(service_name.data(), service_name.length(), this); |
| } |
| |
| void ServiceNamespace::RemoveServiceForName(const std::string& service_name) { |
| auto it = name_to_service_connector_.find(service_name); |
| if (it != name_to_service_connector_.end()) |
| name_to_service_connector_.erase(it); |
| directory_->RemoveService(service_name.data(), service_name.length()); |
| } |
| |
| bool ServiceNamespace::ServeDirectory(zx::channel channel) { |
| return vfs_.ServeDirectory(directory_, std::move(channel)) == ZX_OK; |
| } |
| |
| int ServiceNamespace::OpenAsFileDescriptor() { |
| zx::channel h1, h2; |
| if (zx::channel::create(0, &h1, &h2) < 0) |
| return -1; |
| if (!ServeDirectory(std::move(h1))) |
| return -1; |
| fdio_t* io = fdio_remote_create(h2.release(), ZX_HANDLE_INVALID); |
| if (!io) |
| return -1; |
| return fdio_bind_to_fd(io, -1, 0); |
| } |
| |
| bool ServiceNamespace::MountAtPath(const char* path) { |
| zx::channel h1, h2; |
| if (zx::channel::create(0, &h1, &h2) < 0) |
| return false; |
| |
| if (!ServeDirectory(std::move(h1))) |
| return false; |
| |
| fxl::UniqueFD fd(open(path, O_DIRECTORY | O_RDWR)); |
| if (fd.get() < 0) |
| return false; |
| |
| zx_handle_t h = h2.release(); |
| return ioctl_vfs_mount_fs(fd.get(), &h) >= 0; |
| } |
| |
| void ServiceNamespace::Connect(const char* name, |
| size_t len, |
| zx::channel channel) { |
| ConnectCommon(std::string(name, len), std::move(channel)); |
| } |
| |
| void ServiceNamespace::ConnectToService(const fidl::String& service_name, |
| zx::channel channel) { |
| ConnectCommon(service_name, std::move(channel)); |
| } |
| |
| void ServiceNamespace::ConnectCommon(const std::string& service_name, |
| zx::channel channel) { |
| auto it = name_to_service_connector_.find(service_name); |
| if (it != name_to_service_connector_.end()) |
| it->second(std::move(channel)); |
| } |
| |
| } // namespace app |