dhcpv6_client/
provider.rs1use fidl::endpoints::ServerEnd;
6use fidl_fuchsia_net_dhcpv6::{ClientMarker, ClientProviderRequest, ClientProviderRequestStream};
7use fidl_fuchsia_net_dhcpv6_ext::NewClientParams;
8
9use futures::{Future, StreamExt as _};
10
11use anyhow::Result;
12use log::warn;
13
14pub(crate) async fn run_client_provider<Fut, F>(
16 stream: ClientProviderRequestStream,
17 serve_client: F,
18) where
19 Fut: Future<Output = Result<()>>,
20 F: Fn(NewClientParams, ServerEnd<ClientMarker>) -> Fut,
21{
22 stream
23 .for_each_concurrent(None, |request| async {
24 match request {
25 Ok(ClientProviderRequest::NewClient { params, request, control_handle: _ }) => {
26 let params: NewClientParams = match params.try_into() {
27 Ok(params) => params,
28 Err(e) => {
29 warn!("NewClientParams validation error: {}", e);
30 request
32 .close_with_epitaph(zx::Status::INVALID_ARGS)
33 .unwrap_or_else(|e| warn!("closing NewClient request channel with epitaph INVALID_ARGS: {}", e));
34 return;
35 }
36 };
37 let params_str = format!("{:?}", params);
41 let () =
42 serve_client(params, request).await.unwrap_or_else(|e: anyhow::Error| {
43 warn!("error running client with params {}: {:?}", params_str, e);
46 });
47 }
48 Err(e) => warn!("client provider request FIDL error: {}", e),
49 }
50 })
51 .await
52}
53
54#[cfg(test)]
55mod tests {
56 use fidl::endpoints::create_endpoints;
57 use fidl_fuchsia_net_dhcpv6::ClientProviderMarker;
58 use fidl_fuchsia_net_dhcpv6_ext::ClientConfig;
59 use fuchsia_async as fasync;
60 use futures::join;
61
62 use anyhow::{anyhow, Error};
63 use assert_matches::assert_matches;
64 use net_declare::fidl_socket_addr_v6;
65
66 use super::*;
67
68 async fn serve_client(
69 _param: NewClientParams,
70 _request: ServerEnd<ClientMarker>,
71 ) -> Result<()> {
72 Ok(())
73 }
74
75 async fn start_err_client(
76 _param: NewClientParams,
77 _request: ServerEnd<ClientMarker>,
78 ) -> Result<()> {
79 Err(anyhow!("fake test error"))
80 }
81
82 async fn test_client_provider<Fut, F>(serve_client: F)
83 where
84 Fut: Future<Output = Result<()>>,
85 F: Fn(NewClientParams, ServerEnd<ClientMarker>) -> Fut,
86 {
87 let (client_end, server_end) = create_endpoints::<ClientProviderMarker>();
88 let client_provider_proxy = client_end.into_proxy();
89 let client_provider_stream = server_end.into_stream();
90
91 let test_fut = async {
92 for interface_id in 0..10 {
93 let (_client_end, server_end) = create_endpoints::<ClientMarker>();
94 client_provider_proxy
95 .new_client(
96 &NewClientParams {
97 interface_id: interface_id,
98 address: fidl_socket_addr_v6!("[fe01::1:2]:546"),
99 config: ClientConfig {
100 information_config: Default::default(),
101 non_temporary_address_config: Default::default(),
102 prefix_delegation_config: None,
103 },
104 duid: None,
105 }
106 .into(),
107 server_end,
108 )
109 .expect("failed to request new client");
110 }
111 drop(client_provider_proxy);
112 Ok(())
113 };
114 let provider_fut = run_client_provider(client_provider_stream, serve_client);
115
116 let (test_res, ()): (Result<_, Error>, ()) = join!(test_fut, provider_fut);
117 assert_matches!(test_res, Ok(()));
118 }
119
120 #[fasync::run_singlethreaded(test)]
121 async fn test_client_provider_serve_client_success() {
122 let () = test_client_provider(serve_client).await;
123 }
124
125 #[fasync::run_singlethreaded(test)]
126 async fn test_client_provider_should_keep_running_on_client_err() {
127 let () = test_client_provider(start_err_client).await;
128 }
129}