diff --git a/switch-desktop/Cargo.toml b/switch-desktop/Cargo.toml index 1f91447..d288719 100644 --- a/switch-desktop/Cargo.toml +++ b/switch-desktop/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "switch-desktop" -version = "1.0.4" +version = "1.0.5" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -28,9 +28,10 @@ fs2 = "0.4.3" os_info = "3.5.1" [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] sudo = "0.6.0" +libc = "0.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } #runas = "0.2.1" -windows-service = "0.5.0" +windows-service = "0.6.0" diff --git a/switch-desktop/src/config/mod.rs b/switch-desktop/src/config/mod.rs index e5317d1..6723c2e 100644 --- a/switch-desktop/src/config/mod.rs +++ b/switch-desktop/src/config/mod.rs @@ -25,6 +25,7 @@ pub fn set_win_server_home(home: PathBuf) { let _ = SWITCH_HOME_PATH.lock().insert(home); } +#[derive(Clone,Debug)] pub struct StartConfig { pub tap: bool, pub name: String, @@ -36,6 +37,7 @@ pub struct StartConfig { pub out_ips: Vec<(u32, u32, Ipv4Addr)>, #[cfg(any(unix))] pub off_command_server: bool, + pub log: bool, } fn ips_parse(ips: &Vec) -> Result, String> { @@ -89,6 +91,9 @@ fn ips_parse(ips: &Vec) -> Result, String> { pub fn default_config(start_args: StartArgs) -> Result { println!("========参数配置========"); + if start_args.log { + println!("print log"); + } let tap = start_args.tap; if tap { println!("use tap"); @@ -181,6 +186,7 @@ pub fn default_config(start_args: StartArgs) -> Result { out_ips: out_ips_c, #[cfg(any(unix))] off_command_server: start_args.off_command_server, + log: start_args.log, }; println!("========参数配置========"); Ok(base_config) @@ -193,7 +199,10 @@ pub fn read_config_file(config_path: PathBuf) -> Result { } else { return Err("读取配置文件失败".to_string()); }; - + let log = args_config.log; + if log { + println!("print log"); + } let tap = args_config.tap; if tap { println!("use tap"); @@ -284,6 +293,7 @@ pub fn read_config_file(config_path: PathBuf) -> Result { out_ips: out_ips_c, #[cfg(any(unix))] off_command_server: args_config.off_command_server, + log, }; println!("========参数配置========"); Ok(base_config) @@ -319,6 +329,43 @@ pub struct ArgsConfig { #[cfg(any(unix))] #[serde(default = "default_false")] pub off_command_server: bool, + #[serde(default = "default_false")] + pub log: bool, +} +#[cfg(windows)] +impl ArgsConfig { + pub fn new(start_config: StartConfig) -> ArgsConfig { + let in_ips = start_config.in_ips.iter().map(|(ip, mask, dest)| { + format!("{}/{},{}", Ipv4Addr::from(*ip), subnet_mask_to_integer(*mask), dest) + }).collect::>(); + let out_ips = start_config.out_ips.iter().map(|(ip, mask, dest)| { + format!("{}/{},{}", Ipv4Addr::from(*ip), subnet_mask_to_integer(*mask), dest) + }).collect::>(); + ArgsConfig { + tap: start_config.tap, + version: "1.0.5".to_string(), + token: start_config.token.to_string(), + name: start_config.name.to_string(), + server: start_config.server.to_string(), + nat_test_server: start_config.nat_test_server.iter().map(|v| v.to_string()).collect(), + device_id: start_config.device_id, + in_ips, + out_ips, + log: start_config.log, + #[cfg(any(unix))] + off_command_server: start_config.off_command_server, + } + } +} +#[cfg(windows)] +fn subnet_mask_to_integer(subnet_mask: u32) -> u8 { + let mut mask_bits = subnet_mask; + let mut num_bits = 0; + while mask_bits != 0 { + num_bits += 1; + mask_bits <<= 1; + } + num_bits as u8 } fn default_false() -> bool { diff --git a/switch-desktop/src/main.rs b/switch-desktop/src/main.rs index c31b0c7..8e3ec59 100644 --- a/switch-desktop/src/main.rs +++ b/switch-desktop/src/main.rs @@ -194,9 +194,12 @@ pub fn console_listen(switch: &Switch) { ); match term.read_line() { Ok(cmd) => { + #[cfg(unix)] if cmd.is_empty() { - log::warn!("非正常返回"); - return; + use libc::{STDIN_FILENO, isatty}; + if !unsafe { isatty(STDIN_FILENO) != 0 }{ + return; + } } if command(cmd.trim(), &switch).is_err() { println!("{}", style("stopping").red()); diff --git a/switch-desktop/src/windows/mod.rs b/switch-desktop/src/windows/mod.rs index 6dc6194..9b0d523 100644 --- a/switch-desktop/src/windows/mod.rs +++ b/switch-desktop/src/windows/mod.rs @@ -109,10 +109,6 @@ pub async fn main0(base_args: BaseArgs) { if let Some(code) = e.raw_os_error() { if code == 1060 { //指定的服务未安装。 - println!( - "{}", - style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red() - ); let config = Config::new( start_config.tap, start_config.token, @@ -252,7 +248,10 @@ fn pause() { let _ = term.read_char().unwrap(); } -fn install(path: PathBuf, auto: bool) -> Result<(), Error> { +fn install(mut path: PathBuf, auto: bool) -> Result<(), Error> { + if !path.is_absolute(){ + path = path.canonicalize().unwrap(); + } let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE; let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?; let current_exe_path = std::env::current_exe().unwrap(); @@ -305,18 +304,28 @@ fn change(auto: bool) -> Result<(), Error> { } else { ServiceStartType::OnDemand }; - let mut launch_arguments = Vec::new(); - launch_arguments.push(OsString::from(SERVICE_FLAG)); - launch_arguments.push(OsString::from( - config::get_home().to_str().unwrap(), - )); + let executable_path = config.executable_path.to_string_lossy().to_string(); + let executable_path = if executable_path.starts_with('"') && executable_path.ends_with('"') { + &executable_path[1..executable_path.len() - 1] + } else { + &executable_path + }; + let mut split = executable_path.split(SERVICE_FLAG); + let executable_path = split.next().unwrap().trim(); + let executable_path = if executable_path.starts_with('"') && executable_path.ends_with('"') { + PathBuf::from(&executable_path[1..executable_path.len() - 1]) + } else { + PathBuf::from(executable_path) + }; + let home_path = split.next().unwrap().trim(); + let launch_arguments = vec![OsString::from(SERVICE_FLAG),OsString::from(home_path)]; let service_info = ServiceInfo { name: OsString::from(SERVICE_NAME), display_name: config.display_name, service_type: SERVICE_TYPE, start_type, error_control: config.error_control, - executable_path: config.executable_path, + executable_path, launch_arguments, dependencies: config.dependencies, account_name: None, // run as System diff --git a/switch-desktop/src/windows/service.rs b/switch-desktop/src/windows/service.rs index f4667b3..4f4568a 100644 --- a/switch-desktop/src/windows/service.rs +++ b/switch-desktop/src/windows/service.rs @@ -3,7 +3,9 @@ use std::ffi::OsString; use std::sync::Arc; -use std::thread; +use std::io; +use std::io::Write; +use std::path::PathBuf; use std::time::Duration; use clap::Parser; @@ -15,36 +17,26 @@ use windows_service::service_control_handler::ServiceControlHandlerResult; use switch::core::{Config, Switch}; -use crate::{BaseArgs, Commands, config, StartArgs}; +use crate::{BaseArgs, Commands, config}; use crate::windows::SERVICE_NAME; define_windows_service!(ffi_service_main, switch_service_main); pub fn switch_service_main(arguments: Vec) { - let base_args = BaseArgs::parse_from(arguments); - match base_args.command { - Commands::Start(args) => { - if args.log { - let _ = config::log_config::log_service_init(); + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + match service_main(arguments).await { + Ok(_) => {} + Err(e) => { + log::error!("启动服务失败:{:?}",e); + } } - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .unwrap() - .block_on(async { - match service_main(args).await { - Ok(_) => {} - Err(e) => { - log::error!("启动服务失败:{:?}",e); - } - } - }) - } - _ => {} - } + }) } -async fn service_main(args: StartArgs) -> windows_service::Result<()> { - log::info!("service_main:{:?}",args); +async fn service_main(arguments: Vec) -> windows_service::Result<()> { let parker = crossbeam::sync::Parker::new(); let un_parker = parker.unparker().clone(); let event_handler = move |control_event| -> ServiceControlHandlerResult { @@ -78,15 +70,13 @@ async fn service_main(args: StartArgs) -> windows_service::Result<()> { wait_hint: Duration::default(), process_id: None, })?; - match start_switch(args).await { - Ok(switch) => { + match start_switch(arguments).await { + Ok(_) => { parker.park(); - if let Err(e) = switch.stop() { - log::warn!("switch stop:{:?}",e) - } + } Err(e) => { - log::error!("{:?}",e); + log::error!("服务启动失败 {:?}",e); } } status_handle.set_service_status(ServiceStatus { @@ -100,25 +90,76 @@ async fn service_main(args: StartArgs) -> windows_service::Result<()> { }) } -async fn start_switch(args: StartArgs) -> switch::Result> { - let start_config = if let Some(config_path) = &args.config { - match config::read_config_file(config_path.into()) { - Ok(start_config) => { - start_config - } - Err(e) => { - log::error!("{:?}", e); - return Err(switch::error::Error::Stop(e)); +fn auto_config_path() -> io::Result { + Ok(config::get_win_server_home().join("auto_config.yaml")) +} + +fn save_auto_config(start_config: config::StartConfig) -> io::Result<()> { + let mut file = std::fs::File::create(auto_config_path()?)?; + log::error!("auto_config_path()? {:?}",auto_config_path()?); + let config = config::ArgsConfig::new(start_config); + match serde_yaml::to_string(&config) { + Ok(yaml) => { + file.write_all(yaml.as_bytes()) + } + Err(e) => { + Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))) + } + } +} + +async fn start_switch(arguments: Vec) -> switch::Result<()> { + let start_config = match BaseArgs::try_parse_from(arguments) { + Ok(args) => { + match args.command { + Commands::Start(args) => { + if args.log { + let _ = config::log_config::log_service_init(); + } + if let Some(config_path) = &args.config { + match config::read_config_file(config_path.into()) { + Ok(start_config) => { + if let Err(e) = save_auto_config(start_config.clone()) { + log::warn!("配置文件保存失败:{:?}",e); + } + start_config + } + Err(e) => { + log::error!("{:?}", e); + return Err(switch::error::Error::Stop(e)); + } + } + } else { + match config::default_config(args) { + Ok(start_config) => { + if let Err(e) = save_auto_config(start_config.clone()) { + log::warn!("配置文件保存失败:{:?}",e); + } + start_config + } + Err(e) => { + log::error!("{:?}", e); + return Err(switch::error::Error::Stop(e)); + } + } + } + } + _ => { + return Err(switch::error::Error::Stop("配置文件错误".to_string())); + } } } - } else { - match config::default_config(args) { - Ok(start_config) => { - start_config - } - Err(e) => { - log::error!("{:?}", e); - return Err(switch::error::Error::Stop(e)); + Err(_) => { + match config::read_config_file(auto_config_path()?) { + Ok(start_config) => { + if start_config.log { + let _ = config::log_config::log_service_init(); + } + start_config + } + Err(e) => { + return Err(switch::error::Error::Stop(e)); + } } } }; @@ -132,20 +173,28 @@ async fn start_switch(args: StartArgs) -> switch::Result> { start_config.in_ips, start_config.out_ips, ); - let switch = Switch::start(config).await?; log::info!("switch-service服务启动"); - let switch = Arc::new(switch); - let command_server = crate::command::server::CommandServer::new(); - let switch1 = switch.clone(); - thread::spawn(move || { - if let Err(e) = config::update_pid(std::process::id()) { - log::error!("{:?}", e); - } - if let Err(e) = command_server.start(switch1) { - log::error!("{:?}", e); - } + + + tokio::spawn(async move { + match Switch::start(config).await { + Ok(switch) => { + let switch = Arc::new(switch); + let command_server = crate::command::server::CommandServer::new(); + if let Err(e) = config::update_pid(std::process::id()) { + log::error!("{:?}", e); + } + if let Err(e) = command_server.start(switch) { + log::error!("{:?}", e); + } + } + Err(e) => { + log::error!("{:?}", e); + } + }; + }); - Ok(switch) + Ok(()) } pub fn start() {