1use anyhow::Context as _;
13use fidl_fuchsia_posix_socket::{self as fposix_socket, OptionalUint32};
14use fuchsia_component::server::{ServiceFs, ServiceFsDir};
15use fuchsia_inspect::health::Reporter;
16use fuchsia_inspect_derive::{Inspect, WithInspect as _};
17use futures::StreamExt as _;
18use futures::channel::mpsc;
19use futures::lock::Mutex;
20use log::{error, info};
21use std::sync::Arc;
22use {
23 fidl_fuchsia_net as fnet, fidl_fuchsia_net_policy_socketproxy as fnp_socketproxy,
24 fuchsia_async as fasync,
25};
26
27mod dns_watcher;
28pub mod registry;
29mod socket_provider;
30
31pub use registry::{NetworkConversionError, NetworkExt, NetworkRegistryError};
32
33#[derive(Copy, Clone, Debug)]
34struct SocketMarks {
35 mark_1: OptionalUint32,
36 mark_2: OptionalUint32,
37}
38
39impl From<SocketMarks> for fnet::Marks {
40 fn from(SocketMarks { mark_1, mark_2 }: SocketMarks) -> Self {
41 let into_option_u32 = |opt| match opt {
42 OptionalUint32::Unset(fposix_socket::Empty) => None,
43 OptionalUint32::Value(val) => Some(val),
44 };
45 Self {
46 mark_1: into_option_u32(mark_1),
47 mark_2: into_option_u32(mark_2),
48 __source_breaking: fidl::marker::SourceBreaking,
49 }
50 }
51}
52
53impl SocketMarks {
54 fn has_value(&self) -> bool {
55 match (self.mark_1, self.mark_2) {
56 (OptionalUint32::Value(_), _) => true,
57 (_, OptionalUint32::Value(_)) => true,
58 _ => false,
59 }
60 }
61
62 fn set_mark(&mut self, domain: fnet::MarkDomain, value: Option<u32>) {
63 let value = match value {
64 Some(value) => fposix_socket::OptionalUint32::Value(value),
65 None => fposix_socket::OptionalUint32::Unset(fposix_socket::Empty),
66 };
67
68 match domain {
69 fnet::MarkDomain::Mark1 => self.mark_1 = value,
70 fnet::MarkDomain::Mark2 => self.mark_2 = value,
71 }
72 }
73}
74
75impl Default for SocketMarks {
76 fn default() -> Self {
77 Self {
78 mark_1: OptionalUint32::Unset(fposix_socket::Empty),
79 mark_2: OptionalUint32::Unset(fposix_socket::Empty),
80 }
81 }
82}
83
84#[derive(Inspect)]
85struct SocketProxy {
86 registry: registry::Registry,
87 dns_watcher: dns_watcher::DnsServerWatcher,
88 socket_provider: socket_provider::SocketProvider,
89}
90
91impl SocketProxy {
92 fn new(
93 forwarder_tx: mpsc::Sender<crate::registry::NetworkRegistryRequest>,
94 ) -> Result<Self, anyhow::Error> {
95 let mark = Arc::new(Mutex::new(SocketMarks::default()));
96 let (dns_tx, dns_rx) = mpsc::channel(10);
99 Ok(Self {
100 registry: registry::Registry::new(mark.clone(), dns_tx, forwarder_tx)
101 .context("while creating registry")?,
102 dns_watcher: dns_watcher::DnsServerWatcher::new(Arc::new(Mutex::new(dns_rx))),
103 socket_provider: socket_provider::SocketProvider::new(mark),
104 })
105 }
106}
107
108enum IncomingService {
109 DnsServerWatcher(fnp_socketproxy::DnsServerWatcherRequestStream),
110 FuchsiaNetworks(fnp_socketproxy::FuchsiaNetworksRequestStream),
111 StarnixNetworks(fnp_socketproxy::StarnixNetworksRequestStream),
112 PosixSocket(fidl_fuchsia_posix_socket::ProviderRequestStream),
113 PosixSocketRaw(fidl_fuchsia_posix_socket_raw::ProviderRequestStream),
114}
115
116pub async fn run() -> Result<(), anyhow::Error> {
118 fuchsia_inspect::component::health().set_starting_up();
119
120 let inspector = fuchsia_inspect::component::inspector();
121 let _inspect_server_task =
122 inspect_runtime::publish(inspector, inspect_runtime::PublishOptions::default());
123
124 let (forwarder_tx, forwarder_rx) = mpsc::channel(50);
128 let mut request_forwarder = registry::RequestForwarder::new(forwarder_rx)?;
129 let proxy = Arc::new(SocketProxy::new(forwarder_tx)?.with_inspect(inspector.root(), "root")?);
130
131 let mut fs = ServiceFs::new_local();
132 let _: &mut ServiceFsDir<'_, _> = fs
133 .dir("svc")
134 .add_fidl_service(IncomingService::StarnixNetworks)
135 .add_fidl_service(IncomingService::FuchsiaNetworks)
136 .add_fidl_service(IncomingService::DnsServerWatcher)
137 .add_fidl_service(IncomingService::PosixSocket)
138 .add_fidl_service(IncomingService::PosixSocketRaw);
139
140 let _: &mut ServiceFs<_> = fs.take_and_serve_directory_handle()?;
141
142 fuchsia_inspect::component::health().set_ok();
143
144 let service_fut = fs.for_each_concurrent(100, move |service| {
145 let proxy = Arc::clone(&proxy);
146 async move {
147 match service {
148 IncomingService::StarnixNetworks(stream) => {
149 proxy.registry.run_starnix(stream).await
150 }
151 IncomingService::FuchsiaNetworks(stream) => {
152 proxy.registry.run_fuchsia(stream).await
153 }
154 IncomingService::DnsServerWatcher(stream) => proxy.dns_watcher.run(stream).await,
155 IncomingService::PosixSocket(stream) => proxy.socket_provider.run(stream).await,
156 IncomingService::PosixSocketRaw(stream) => {
157 proxy.socket_provider.run_raw(stream).await
158 }
159 }
160 .unwrap_or_else(|e| error!("{e:?}"))
161 }
162 });
163
164 let scope = fasync::Scope::new();
165
166 let _ = scope.spawn_local(async move {
167 let res = request_forwarder.run().await;
168 info!("RequestForwarder future has terminated: {res:?}");
169 });
170
171 let _ = scope.spawn_local(async move {
172 service_fut.await;
173 error!("The main services future has terminated. It should never terminate");
174 fasync::Scope::current().abort().await;
176 });
177
178 scope.join().await;
179
180 Ok(())
181}