修复windows服务不能自启动的问题

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