blob: dd9951b0c5ce68df6d7acdfade042f1b0d33ade0 [file] [log] [blame]
// Copyright 2017 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.
#include "lib/svc/cpp/service_provider_bridge.h"
#include <fcntl.h>
#include <fs/service.h>
#include <lib/async/default.h>
#include <lib/fdio/util.h>
#include <zircon/device/vfs.h>
#include <utility>
namespace component {
ServiceProviderBridge::ServiceProviderBridge()
: vfs_(async_get_default_dispatcher()), weak_factory_(this) {
directory_ =
fbl::AdoptRef(new ServiceProviderDir(weak_factory_.GetWeakPtr()));
}
ServiceProviderBridge::~ServiceProviderBridge() = default;
void ServiceProviderBridge::AddBinding(
fidl::InterfaceRequest<ServiceProvider> request) {
bindings_.AddBinding(this, std::move(request));
}
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> ServiceProviderBridge::AddBinding() {
return bindings_.AddBinding(this);
}
void ServiceProviderBridge::AddServiceForName(ServiceConnector connector,
const std::string& service_name) {
name_to_service_connector_[service_name] = std::move(connector);
}
bool ServiceProviderBridge::ServeDirectory(zx::channel channel) {
return vfs_.ServeDirectory(directory_, std::move(channel)) == ZX_OK;
}
zx::channel ServiceProviderBridge::OpenAsDirectory() {
zx::channel h1, h2;
if (zx::channel::create(0, &h1, &h2) < 0)
return zx::channel();
if (!ServeDirectory(std::move(h1)))
return zx::channel();
return h2;
}
int ServiceProviderBridge::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);
}
void ServiceProviderBridge::ConnectToService(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));
else if (backend_)
backend_->ConnectToService(service_name, std::move(channel));
else if (backing_dir_)
fdio_service_connect_at(backing_dir_.get(), service_name.c_str(),
channel.release());
}
ServiceProviderBridge::ServiceProviderDir::ServiceProviderDir(
fxl::WeakPtr<ServiceProviderBridge> bridge)
: bridge_(std::move(bridge)) {}
ServiceProviderBridge::ServiceProviderDir::~ServiceProviderDir() = default;
zx_status_t ServiceProviderBridge::ServiceProviderDir::Lookup(
fbl::RefPtr<fs::Vnode>* out, fbl::StringPiece name) {
*out = fbl::AdoptRef(new fs::Service(
[bridge = bridge_,
name = std::string(name.data(), name.length())](zx::channel channel) {
if (bridge) {
bridge->ConnectToService(name, std::move(channel));
return ZX_OK;
}
return ZX_ERR_NOT_FOUND;
}));
return ZX_OK;
}
zx_status_t ServiceProviderBridge::ServiceProviderDir::Getattr(vnattr_t* attr) {
memset(attr, 0, sizeof(vnattr_t));
attr->mode = V_TYPE_DIR | V_IRUSR;
attr->nlink = 1;
return ZX_OK;
}
} // namespace component