Skip to main content

socket_proxy_testing/
lib.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use assert_matches::assert_matches;
6use fidl_fuchsia_net::IpAddress;
7use fidl_fuchsia_net_policy_socketproxy::{
8    FuchsiaNetworkInfo, FuchsiaNetworksProxy, FuchsiaNetworksRequest, FuchsiaNetworksRequestStream,
9    Network, NetworkDnsServers, NetworkInfo, NetworkRegistryAddResult, NetworkRegistryRemoveResult,
10    NetworkRegistrySetDefaultResult, NetworkRegistryUpdateResult, StarnixNetworkInfo,
11    StarnixNetworksProxy,
12};
13use fidl_fuchsia_posix_socket::OptionalUint32;
14use futures::{FutureExt as _, StreamExt as _};
15use socket_proxy::NetworkRegistryError;
16use std::future::Future;
17
18fn starnix_network_info(mark: u32) -> NetworkInfo {
19    NetworkInfo::Starnix(StarnixNetworkInfo {
20        mark: Some(mark),
21        handle: Some(0),
22        ..Default::default()
23    })
24}
25
26fn starnix_network(network_id: u32) -> Network {
27    Network {
28        network_id: Some(network_id),
29        info: Some(starnix_network_info(network_id)),
30        dns_servers: Some(Default::default()),
31        ..Default::default()
32    }
33}
34
35fn fuchsia_network(network_id: u32) -> Network {
36    Network {
37        network_id: Some(network_id),
38        info: Some(NetworkInfo::Fuchsia(FuchsiaNetworkInfo { ..Default::default() })),
39        dns_servers: Some(Default::default()),
40        ..Default::default()
41    }
42}
43
44pub trait ToNetwork {
45    fn to_network(self, registry: RegistryType) -> Network;
46}
47
48impl ToNetwork for u32 {
49    fn to_network(self, registry: RegistryType) -> Network {
50        match registry {
51            RegistryType::Starnix => starnix_network(self),
52            RegistryType::Fuchsia => fuchsia_network(self),
53        }
54    }
55}
56
57pub enum RegistryType {
58    Starnix,
59    Fuchsia,
60}
61
62impl ToNetwork for (u32, Vec<IpAddress>) {
63    fn to_network(self, registry: RegistryType) -> Network {
64        let (v4, v6) = self.1.iter().fold((Vec::new(), Vec::new()), |(mut v4s, mut v6s), s| {
65            match s {
66                IpAddress::Ipv4(v4) => v4s.push(*v4),
67                IpAddress::Ipv6(v6) => v6s.push(*v6),
68            }
69            (v4s, v6s)
70        });
71        let base = match registry {
72            RegistryType::Starnix => starnix_network(self.0),
73            RegistryType::Fuchsia => fuchsia_network(self.0),
74        };
75        Network {
76            dns_servers: Some(NetworkDnsServers {
77                v4: Some(v4),
78                v6: Some(v6),
79                ..Default::default()
80            }),
81            ..base
82        }
83    }
84}
85
86impl<N: ToNetwork + Clone> ToNetwork for &N {
87    fn to_network(self, registry: RegistryType) -> Network {
88        self.clone().to_network(registry)
89    }
90}
91
92pub trait NetworkRegistry {
93    fn set_default(
94        &self,
95        network_id: &OptionalUint32,
96    ) -> impl Future<Output = Result<NetworkRegistrySetDefaultResult, fidl::Error>>;
97    fn add(
98        &self,
99        network: &Network,
100    ) -> impl Future<Output = Result<NetworkRegistryAddResult, fidl::Error>>;
101    fn update(
102        &self,
103        network: &Network,
104    ) -> impl Future<Output = Result<NetworkRegistryUpdateResult, fidl::Error>>;
105    fn remove(
106        &self,
107        network_id: u32,
108    ) -> impl Future<Output = Result<NetworkRegistryRemoveResult, fidl::Error>>;
109}
110
111macro_rules! impl_network_registry {
112    ($($ty:ty),*) => {
113        $(
114            impl NetworkRegistry for $ty {
115                fn set_default(
116                    &self,
117                    network_id: &OptionalUint32,
118                ) -> impl Future<Output = Result<NetworkRegistrySetDefaultResult, fidl::Error>> {
119                    self.set_default(network_id)
120                }
121
122                fn add(
123                    &self,
124                    network: &Network,
125                ) -> impl Future<Output = Result<NetworkRegistryAddResult, fidl::Error>> {
126                    self.add(network)
127                }
128
129                fn update(
130                    &self,
131                    network: &Network,
132                ) -> impl Future<Output = Result<NetworkRegistryUpdateResult, fidl::Error>> {
133                    self.update(network)
134                }
135
136                fn remove(
137                    &self,
138                    network_id: u32,
139                ) -> impl Future<Output = Result<NetworkRegistryRemoveResult, fidl::Error>> {
140                    self.remove(network_id)
141                }
142            }
143        )*
144    };
145    ($($ty:ty),*,) => { impl_network_registry!($($ty),*); };
146}
147
148impl_network_registry!(StarnixNetworksProxy, FuchsiaNetworksProxy);
149
150pub async fn respond_to_socketproxy(
151    socket_proxy_req_stream: &mut FuchsiaNetworksRequestStream,
152    result: Result<(), NetworkRegistryError>,
153) {
154    socket_proxy_req_stream
155        .next()
156        .map(|req| match req.expect("request stream ended").expect("receive request") {
157            FuchsiaNetworksRequest::SetDefault { network_id: _, responder } => {
158                let res = result.map_err(|e| {
159                    assert_matches!(e, NetworkRegistryError::SetDefault(err) => {
160                        return err;
161                    });
162                });
163                responder.send(res).expect("respond to SetDefault");
164            }
165            FuchsiaNetworksRequest::Add { network: _, responder } => {
166                let res = result.map_err(|e| {
167                    assert_matches!(e, NetworkRegistryError::Add(err) => {
168                        return err;
169                    });
170                });
171                responder.send(res).expect("respond to Add");
172            }
173            FuchsiaNetworksRequest::Update { network: _, responder: _ } => {
174                unreachable!("not called in tests");
175            }
176            FuchsiaNetworksRequest::Remove { network_id: _, responder } => {
177                let res = result.map_err(|e| {
178                    assert_matches!(e, NetworkRegistryError::Remove(err) => {
179                        return err;
180                    });
181                });
182                responder.send(res).expect("respond to Remove");
183            }
184        })
185        .await;
186}