blob: b51f48c1150f845e44877167c29dc032cb78cb38 [file] [log] [blame]
// Copyright 2022 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 <fidl/fuchsia.posix.socket.packet/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/namespace.h>
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/service/llcpp/service.h>
#include <lib/vfs/cpp/composed_service_dir.h>
#include <lib/zx/channel.h>
#include <zircon/assert.h>
#include <zircon/status.h>
#include <filesystem>
namespace {
constexpr char kServiceDirectory[] = "/svc";
constexpr char kNetstackExposeDir[] =
"/hub-v2/children/core/children/network/children/netstack/exec/expose";
constexpr const char* kPacketSocketProviderName =
fidl::DiscoverableProtocolName<fuchsia_posix_socket_packet::Provider>;
} // namespace
// Attempts to make a packet socket provider available to this program if not
// already available.
//
// The packet socket provider exposed by the core realm's netstack is used if it
// is available.
__attribute__((constructor)) void init_packet_socket_provider() {
if (std::filesystem::exists(std::filesystem::path(kServiceDirectory) /
kPacketSocketProviderName)) {
// Packet socket provider is already available.
return;
}
zx::status netstack_expose_dir = service::OpenServiceRoot(kNetstackExposeDir);
switch (zx_status_t status = netstack_expose_dir.status_value(); status) {
case ZX_OK:
break;
case ZX_ERR_NOT_FOUND:
// Most likely in the non-root realm.
return;
default:
ZX_PANIC("Failed to open netstack expose directory at %s: %s", kNetstackExposeDir,
zx_status_get_string(status));
}
static vfs::ComposedServiceDir composed_svc_dir;
// Our composed service directory should be a superset of the default service
// directory.
{
zx::status result = service::OpenServiceRoot();
ZX_ASSERT_MSG(result.is_ok(), "Failed to open root service directory: %s",
result.status_string());
// TODO(https://fxbug.dev/72980): Avoid this type-unsafe conversion.
composed_svc_dir.set_fallback(
fidl::InterfaceHandle<fuchsia::io::Directory>(result->TakeChannel()));
}
// Add the packet socket provider service to our composed service directory
// by reaching into netstack's exposed directory via hub(-v2).
//
// https://fuchsia.dev/fuchsia-src/concepts/components/v2/hub?hl=en
composed_svc_dir.AddService(
kPacketSocketProviderName,
std::make_unique<vfs::Service>(
[netstack_expose_dir = std::move(netstack_expose_dir.value())](
zx::channel request, async_dispatcher_t* dispatcher) mutable {
zx::status result = service::ConnectAt(
netstack_expose_dir.borrow(),
fidl::ServerEnd<fuchsia_posix_socket_packet::Provider>(std::move(request)));
ZX_ASSERT_MSG(result.is_ok(), "Failed to connect to packet socker provider: %s",
result.status_string());
}));
static async::Loop composed_svc_dir_loop(&kAsyncLoopConfigNoAttachToCurrentThread);
// Replace the default service directory with our composed service directory
// to make packet socket provider available to the program and start serving
// requests to the composed service directory.
{
zx_status_t status;
zx::channel client, server;
ZX_ASSERT_MSG((status = zx::channel::create(0, &client, &server)) == ZX_OK,
"Failed to create channels: %s", zx_status_get_string(status));
// TODO(https://fxbug.dev/77059): Drop writable right.
ZX_ASSERT_MSG(
(status = composed_svc_dir.Serve(
fuchsia::io::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::RIGHT_WRITABLE |
fuchsia::io::OpenFlags::DIRECTORY,
std::move(server), composed_svc_dir_loop.dispatcher())) == ZX_OK,
"Failed to start serving requsts for composed service directory: %s",
zx_status_get_string(status));
fdio_ns_t* ns;
ZX_ASSERT_MSG((status = fdio_ns_get_installed(&ns)) == ZX_OK,
"Failed to get installed namespace: %s", zx_status_get_string(status));
ZX_ASSERT_MSG((status = fdio_ns_unbind(ns, kServiceDirectory)) == ZX_OK,
"Failed to unbind svc: %s", zx_status_get_string(status));
ZX_ASSERT_MSG((status = fdio_ns_bind(ns, kServiceDirectory, client.release())) == ZX_OK,
"Failed to bind svc: %s", zx_status_get_string(status));
}
zx_status_t status;
ZX_ASSERT_MSG((status = composed_svc_dir_loop.StartThread()) == ZX_OK,
"Failed to start async loop thread: %s", zx_status_get_string(status));
}