blob: 82703364580c0fd725613f0a4c5e59138a534f9a [file] [log] [blame]
// 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.
#include "sandbox_env.h"
#include <fuchsia/boot/cpp/fidl.h>
#include <fuchsia/netemul/devmgr/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/sys/cpp/service_directory.h>
namespace netemul {
constexpr const char* kDevmgrUrl =
"fuchsia-pkg://fuchsia.com/netemul-sandbox#meta/netemul-devmgr.cmx";
constexpr const char* kNetworkTunUrl = "fuchsia-pkg://fuchsia.com/network-tun#meta/network-tun.cmx";
class ServiceHolder {
public:
ServiceHolder(const char* url, sys::ServiceDirectory* services,
fit::function<void(zx_status_t)> error_callback) {
fidl::InterfacePtr<fuchsia::sys::Launcher> launcher;
services->Connect(launcher.NewRequest());
fuchsia::sys::LaunchInfo info{};
info.url = url;
directory_ = sys::ServiceDirectory::CreateWithRequest(&info.directory_request);
launcher->CreateComponent(std::move(info), ctlr_.NewRequest());
ctlr_.set_error_handler(std::move(error_callback));
}
template <typename T>
void Connect(fidl::InterfaceRequest<T> req) {
directory_->Connect(std::move(req));
}
private:
std::shared_ptr<sys::ServiceDirectory> directory_;
fidl::InterfacePtr<fuchsia::sys::ComponentController> ctlr_;
};
void SandboxEnv::ConnectDevfs(zx::channel req) {
if (!devfs_) {
ZX_ASSERT(env_services_);
// Create devfs holder lazily.
devfs_ = std::make_unique<ServiceHolder>(kDevmgrUrl, env_services_.get(), [this](zx_status_t) {
if (events_.devfs_terminated) {
events_.devfs_terminated();
}
devfs_ = nullptr;
});
}
devfs_->Connect(fidl::InterfaceRequest<fuchsia::netemul::devmgr::IsolatedDevmgr>(std::move(req)));
}
void SandboxEnv::ConnectNetworkTun(fidl::InterfaceRequest<fuchsia::net::tun::Control> req) {
if (!network_tun_) {
ZX_ASSERT(env_services_);
// Create network_tun holder lazily.
network_tun_ =
std::make_unique<ServiceHolder>(kNetworkTunUrl, env_services_.get(), [this](zx_status_t) {
if (events_.network_tun_terminated) {
events_.network_tun_terminated();
}
network_tun_ = nullptr;
});
}
network_tun_->Connect(std::move(req));
}
void SandboxEnv::ConnectToReadOnlyLog(fidl::InterfaceRequest<fuchsia::boot::ReadOnlyLog> req) {
env_services_->Connect(std::move(req));
}
SandboxEnv::SandboxEnv(std::shared_ptr<sys::ServiceDirectory> env_services,
SandboxEnv::Events events)
: env_services_(std::move(env_services)), events_(std::move(events)) {
net_context_.SetNetworkTunHandler(fit::bind_member(this, &SandboxEnv::ConnectNetworkTun));
}
void SandboxEnv::set_devfs_enabled(bool enabled) {
if (enabled) {
net_context_.SetDevfsHandler([this](zx::channel req) { ConnectDevfs(std::move(req)); });
} else {
// prevent users from toggling enabling/disabling this if devfs
// was already created. It'd make for very confusing use cases.
ZX_ASSERT(!devfs_);
net_context_.SetDevfsHandler(nullptr);
}
}
SandboxEnv::~SandboxEnv() = default;
} // namespace netemul