xref: /aosp_15_r20/tools/netsim/rust/http-proxy/src/manager.rs (revision cf78ab8cffb8fc9207af348f23af247fb04370a6)
1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::util::{into_raw_descriptor, ProxyConfig};
16 use crate::{connector::Connector, error::Error};
17 use libslirp_rs::libslirp::{ProxyConnect, ProxyManager};
18 use log::{debug, warn};
19 use std::net::SocketAddr;
20 use std::sync::Arc;
21 use tokio::runtime::Runtime;
22 
23 /// # Manager
24 ///
25 /// The `Manager` struct implements the `ProxyManager` trait from
26 /// `libslirp_rs`.  It is responsible for managing TCP connections
27 /// through an HTTP proxy using the `Connector` struct.
28 ///
29 /// The `Manager` uses a `tokio::runtime::Runtime` to spawn tasks for
30 /// establishing proxy connections.  It takes a proxy configuration
31 /// string as input, which is parsed into a `ProxyConfig` to create a
32 /// `Connector` instance.
33 ///
34 /// The `try_connect` method attempts to establish a connection to the
35 /// given `SocketAddr` through the proxy.  If successful, it calls the
36 /// `proxy_connect` function with the raw file descriptor of the
37 /// connected socket.
38 ///
39 /// # Example
40 ///
41 /// ```
42 /// use std::net::SocketAddr;
43 /// use libslirp_rs::libslirp::ProxyConnect;
44 ///
45 /// struct MyProxyConnect;
46 ///
47 /// impl ProxyConnect for MyProxyConnect {
48 ///     fn proxy_connect(&self, fd: i32, sockaddr: SocketAddr) {
49 ///         // Handle the connected socket
50 ///     }
51 /// }
52 ///
53 /// #[tokio::main]
54 /// async fn main() {
55 /// }
56 /// ```
57 pub struct Manager {
58     runtime: Arc<Runtime>,
59     connector: Connector,
60 }
61 
62 impl Manager {
new(proxy: &str) -> Result<Self, Error>63     pub fn new(proxy: &str) -> Result<Self, Error> {
64         let config = ProxyConfig::from_string(&proxy)?;
65         Ok(Self {
66             runtime: Arc::new(Runtime::new()?),
67             connector: Connector::new(config.addr, config.username, config.password),
68         })
69     }
70 }
71 
72 impl ProxyManager for Manager {
73     /// Attempts to establish a TCP connection to the given `sockaddr` through the proxy.
74     ///
75     /// This function spawns a new task in the `tokio` runtime to handle the connection process.
76     /// If the connection is successful, it calls the `proxy_connect` function of the provided
77     /// `ProxyConnect` object with the raw file descriptor of the connected socket.
78     ///
79     /// # Arguments
80     ///
81     /// * `sockaddr` - The target socket address to connect to.
82     /// * `connect_id` - An identifier for the connection.
83     /// * `connect_func` - A `ProxyConnect` object that will be called with the connected socket.
84     ///
85     /// # Returns
86     ///
87     /// `true` if the connection attempt was initiated, `false` otherwise.
try_connect( &self, sockaddr: SocketAddr, connect_id: usize, connect_func: Box<dyn ProxyConnect + Send>, ) -> bool88     fn try_connect(
89         &self,
90         sockaddr: SocketAddr,
91         connect_id: usize,
92         connect_func: Box<dyn ProxyConnect + Send>,
93     ) -> bool {
94         debug!("Connecting to {sockaddr:?} with connect ID {connect_id}");
95         let connector = self.connector.clone();
96 
97         self.runtime.handle().spawn(async move {
98             let fd = match connector.connect(sockaddr).await {
99                 Ok(tcp_stream) => into_raw_descriptor(tcp_stream),
100                 Err(e) => {
101                     warn!("Failed to connect to proxy {}. {}", sockaddr, e);
102                     -1
103                 }
104             };
105             connect_func.proxy_connect(fd, sockaddr);
106         });
107 
108         true
109     }
110 
111     /// Removes a connection with the given `connect_id`.
112     ///
113     /// Currently, this function only logs a debug message.
114     ///
115     /// # Arguments
116     ///
117     /// * `connect_id` - The identifier of the connection to remove.
remove(&self, connect_id: usize)118     fn remove(&self, connect_id: usize) {
119         debug!("Remove connect ID {}", connect_id);
120     }
121 }
122