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