| // 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 |