1use anyhow::Error;
6use fidl::endpoints::ClientEnd;
7use fidl_fuchsia_testing_proxy::{TcpProxyControlMarker, TcpProxyControlProxy, TcpProxy_Marker};
8use fuchsia_component::client::connect_to_protocol;
9use futures::lock::Mutex;
10use log::info;
11use std::collections::HashMap;
12use std::fmt::{self, Debug};
13
14#[derive(Debug)]
15pub struct ProxyFacade {
16 internal: Mutex<Option<ProxyFacadeInternal>>,
17}
18
19impl ProxyFacade {
20 pub fn new() -> Self {
21 Self { internal: Mutex::new(None) }
22 }
23
24 pub async fn open_proxy(&self, target_port: u16, proxy_port: u16) -> Result<u16, Error> {
28 let mut internal_lock = self.internal.lock().await;
29 match *internal_lock {
30 None => {
31 let mut internal = ProxyFacadeInternal::new()?;
32 let result = internal.open_proxy(target_port, proxy_port).await;
33 *internal_lock = Some(internal);
34 result
35 }
36 Some(ref mut internal) => internal.open_proxy(target_port, proxy_port).await,
37 }
38 }
39
40 pub async fn drop_proxy(&self, target_port: u16) {
44 if let Some(ref mut internal) = *self.internal.lock().await {
45 internal.drop_proxy(target_port);
46 }
47 }
48
49 pub async fn stop_all_proxies(&self) {
52 if let Some(ref mut internal) = *self.internal.lock().await {
53 internal.stop_all_proxies();
54 }
55 }
56}
57
58struct ProxyFacadeInternal {
59 proxy_control: TcpProxyControlProxy,
61 open_proxies: HashMap<u16, OpenProxy>,
63}
64
65struct OpenProxy {
66 open_port: u16,
68 _proxy_handle: ClientEnd<TcpProxy_Marker>,
70 num_users: u32,
72}
73
74impl Debug for ProxyFacadeInternal {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 f.write_fmt(format_args!("ProxyFacadeInternal {:?}", self.proxy_control))
78 }
79}
80
81impl ProxyFacadeInternal {
82 fn new() -> Result<Self, Error> {
83 info!("Launching proxy component as V2");
84 let proxy_control = connect_to_protocol::<TcpProxyControlMarker>()?;
85 Ok(Self { proxy_control, open_proxies: HashMap::new() })
86 }
87
88 async fn open_proxy(&mut self, target_port: u16, proxy_port: u16) -> Result<u16, Error> {
89 match self.open_proxies.get_mut(&target_port) {
90 Some(proxy) => {
91 proxy.num_users += 1;
92 Ok(proxy.open_port)
93 }
94 None => {
95 let (client, server) = fidl::endpoints::create_endpoints::<TcpProxy_Marker>();
96 let open_port =
97 self.proxy_control.open_proxy_(target_port, proxy_port, server).await?;
98 self.open_proxies.insert(
99 target_port,
100 OpenProxy { open_port, _proxy_handle: client, num_users: 1 },
101 );
102 Ok(open_port)
103 }
104 }
105 }
106
107 fn drop_proxy(&mut self, target_port: u16) {
108 if let Some(mut proxy) = self.open_proxies.remove(&target_port) {
109 proxy.num_users -= 1;
110 if proxy.num_users > 0 {
111 self.open_proxies.insert(target_port, proxy);
112 }
113 }
114 }
115
116 fn stop_all_proxies(&mut self) {
117 self.open_proxies.clear();
118 }
119}