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