From 13256ae2eb9c49c57876abe7a8de6906ebebcf27 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Mon, 17 Jun 2024 19:45:06 +0800 Subject: [PATCH] over_tls_client_run_with_ssr_url --- src/api.rs | 47 ++++++++++++++++++++++++---------------------- src/bin/overtls.rs | 37 ++++++++++++++++++++++++------------ src/cmdopt.rs | 10 +++++----- 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/api.rs b/src/api.rs index 210074d..14065b0 100644 --- a/src/api.rs +++ b/src/api.rs @@ -73,12 +73,18 @@ pub unsafe extern "C" fn over_tls_client_run( /// # Safety /// /// Run the overtls client with SSR URL. -/// The callback function will be called when the client is listening on a port. -/// It should be thread-safe and will be called with the port number and should be called only once. +/// Parameters: +/// - `url`: SSR style URL string of the server node, e.g. "ssr://server:port:protocol:method:obfs:password_base64/?params_base64". +/// - `listen_addr`: The address to listen on, in the format of "ip:port". +/// - `verbosity`: The verbosity level of the logger. +/// - `callback`: The callback function to be called when the client is listening on a port. +/// It should be thread-safe and will be called with the port number and should be called only once. +/// - `ctx`: The context pointer to be passed to the callback function. /// #[no_mangle] pub unsafe extern "C" fn over_tls_client_run_with_ssr_url( url: *const c_char, + listen_addr: *const c_char, verbosity: ArgVerbosity, callback: Option, ctx: *mut c_void, @@ -89,31 +95,28 @@ pub unsafe extern "C" fn over_tls_client_run_with_ssr_url( log::warn!("failed to set logger, error={:?}", err); } } - let url = match std::ffi::CStr::from_ptr(url).to_str() { - Err(err) => { - log::error!("invalid config path, error={:?}", err); - return -1; - } - Ok(url) => url, + + let result = || { + let url = std::ffi::CStr::from_ptr(url).to_str()?; + let listen_addr = if listen_addr.is_null() { + std::net::SocketAddr::from(([127, 0, 0, 1], 1080)) + } else { + std::ffi::CStr::from_ptr(listen_addr).to_str()?.parse()? + }; + + let mut config = Config::from_ssr_url(url)?; + config.set_listen_addr(listen_addr); + config.check_correctness(false)?; + _over_tls_client_run(config, callback, ctx) }; - let mut config = match Config::from_ssr_url(url) { + match result() { + Ok(_) => 0, Err(err) => { - log::error!("failed to load config, error={:?}", err); - return -2; + log::error!("failed to run client, error={:?}", err); + -1 } - Ok(config) => config, - }; - - if let Err(err) = config.check_correctness(false) { - log::error!("invalid config, error={:?}", err); - return -3; } - if let Err(err) = _over_tls_client_run(config, callback, ctx) { - log::error!("failed to run client, error={:?}", err); - return -4; - } - 0 } fn _over_tls_client_run(config: Config, callback: Option, ctx: *mut c_void) -> Result<()> { diff --git a/src/bin/overtls.rs b/src/bin/overtls.rs index e4d6cdf..7891302 100644 --- a/src/bin/overtls.rs +++ b/src/bin/overtls.rs @@ -8,14 +8,6 @@ fn main() -> Result<(), BoxError> { return Err("C API is not supported for server".into()); } - // TODO: Using opt.node_url to generate a config file for client is not supported yet. - let cfg = opt.config.as_ref().ok_or("Config file is required for client")?; - - // Test the C API usage - let config_path_str = cfg.as_path().to_string_lossy().into_owned(); - let c_string = std::ffi::CString::new(config_path_str)?; - let config_path: *const std::os::raw::c_char = c_string.as_ptr(); - let join = ctrlc2::set_handler(|| { log::info!("Ctrl-C received, exiting..."); unsafe { overtls::over_tls_client_stop() }; @@ -30,9 +22,30 @@ fn main() -> Result<(), BoxError> { unsafe extern "C" fn port_cb(port: i32, _ctx: *mut std::os::raw::c_void) { log::info!("Listening on {}", port); } - unsafe { overtls::over_tls_client_run(config_path, opt.verbosity, Some(port_cb), std::ptr::null_mut()) }; - join.join().expect("Couldn't join on the associated thread"); + if let Some(cfg) = opt.config.as_ref() { + // Test the C API usage + let config_path_str = cfg.as_path().to_string_lossy().into_owned(); + let c_string = std::ffi::CString::new(config_path_str)?; + let config_path: *const std::os::raw::c_char = c_string.as_ptr(); + + unsafe { overtls::over_tls_client_run(config_path, opt.verbosity, Some(port_cb), std::ptr::null_mut()) }; + + join.join().expect("Couldn't join on the associated thread"); + } else if let Some(url) = opt.url_of_node.as_ref() { + let url_str = std::ffi::CString::new(url.as_str())?; + let url_ptr = url_str.as_ptr(); + + let listen_addr = opt.listen_addr.unwrap_or(std::net::SocketAddr::from(([127, 0, 0, 1], 1080))); + let listen_addr = std::ffi::CString::new(listen_addr.to_string())?; + let listen_addr = listen_addr.as_ptr(); + + unsafe { overtls::over_tls_client_run_with_ssr_url(url_ptr, listen_addr, opt.verbosity, Some(port_cb), std::ptr::null_mut()) }; + + join.join().expect("Couldn't join on the associated thread"); + } else { + return Err("Config file or node URL is required".into()); + } return Ok(()); } @@ -45,8 +58,8 @@ fn main() -> Result<(), BoxError> { let mut config = if let Some(file) = opt.config { Config::from_config_file(file)? - } else if let Some(ref node_url) = opt.node_url { - let mut cfg = Config::from_ssr_url(node_url)?; + } else if let Some(ref url_of_node) = opt.url_of_node { + let mut cfg = Config::from_ssr_url(url_of_node)?; cfg.set_listen_addr(opt.listen_addr.unwrap_or(std::net::SocketAddr::from(([127, 0, 0, 1], 1080)))); cfg } else { diff --git a/src/cmdopt.rs b/src/cmdopt.rs index 825d415..295cfff 100644 --- a/src/cmdopt.rs +++ b/src/cmdopt.rs @@ -81,15 +81,15 @@ pub struct CmdOpt { pub role: Role, /// Config file path - #[arg(short, long, value_name = "file path", conflicts_with = "node_url")] + #[arg(short, long, value_name = "file path", conflicts_with = "url_of_node")] pub config: Option, /// URL of the server node used by client #[arg(short, long, value_name = "url", conflicts_with = "config")] - pub node_url: Option, + pub url_of_node: Option, /// Local listening address associated with the URL - #[arg(short, long, value_name = "addr:port", requires = "node_url", conflicts_with = "config")] + #[arg(short, long, value_name = "addr:port", requires = "url_of_node", conflicts_with = "config")] pub listen_addr: Option, /// Cache DNS Query result @@ -139,11 +139,11 @@ impl CmdOpt { if args.listen_addr.is_some() { output_error_and_exit("Listen address is not supported for server"); } - if args.node_url.is_some() { + if args.url_of_node.is_some() { output_error_and_exit("Node URL is not supported for server"); } } - if args.role == Role::Client && args.config.is_none() && args.node_url.is_none() { + if args.role == Role::Client && args.config.is_none() && args.url_of_node.is_none() { output_error_and_exit("Config file or node URL is required for client"); } args