diff --git a/src/ipc.rs b/src/ipc.rs index ffe1b08a5..f27cc941e 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -741,10 +741,10 @@ async fn handle(data: Data, stream: &mut Connection) { if is_server() { let _ = privacy_mode::turn_off_privacy(0, Some(PrivacyModeState::OffByPeer)); } - #[cfg(any(target_os = "macos", target_os = "linux"))] if crate::is_main() { // below part is for main windows can be reopen during rustdesk installation and installing service from UI // this make new ipc server (domain socket) can be created. + #[cfg(not(windows))] std::fs::remove_file(&Config::ipc_path("")).ok(); #[cfg(target_os = "linux")] { @@ -763,6 +763,17 @@ async fn handle(data: Data, stream: &mut Connection) { .spawn() .ok(); } + #[cfg(windows)] + { + // On Windows, when service is being installed, wait a bit then restart the GUI + hbb_common::sleep(2.0).await; + if let Ok(exe) = std::env::current_exe() { + std::process::Command::new(&exe) + .arg("--no-server") + .spawn() + .ok(); + } + } // leave above open a little time hbb_common::sleep(0.3).await; // in case below exit failed diff --git a/src/server.rs b/src/server.rs index 86f7b5396..66d784a43 100644 --- a/src/server.rs +++ b/src/server.rs @@ -590,13 +590,40 @@ pub async fn start_server(is_server: bool, no_server: bool) { if is_server { crate::common::set_server_running(true); std::thread::spawn(move || { - if let Err(err) = crate::ipc::start("") { - log::error!("Failed to start ipc: {}", err); - if crate::is_server() { - log::error!("ipc is occupied by another process, try kill it"); - std::thread::spawn(stop_main_window_process).join().ok(); + // Retry IPC server start with exponential backoff during service installation + let mut attempts = 0; + let max_attempts = 10; // Increase attempts to handle service installation scenario + let mut wait_time = 1; + + loop { + match crate::ipc::start("") { + Ok(_) => break, + Err(err) => { + attempts += 1; + log::error!("Failed to start ipc (attempt {}/{}): {}", attempts, max_attempts, err); + + if attempts >= max_attempts { + if crate::is_server() { + log::error!("ipc is occupied by another process after {} attempts", max_attempts); + // Check if we're being started as part of service installation + // In that case, the GUI needs time to close its IPC server + let is_service_installation = std::env::var("RUSTDESK_SERVICE_INSTALLATION").is_ok(); + + if !is_service_installation { + log::error!("Not during service installation, try kill the process occupying IPC"); + std::thread::spawn(stop_main_window_process).join().ok(); + } else { + log::info!("Service installation detected, GUI should restart itself"); + } + } + std::process::exit(-1); + } + + // Wait before retrying with exponential backoff + std::thread::sleep(std::time::Duration::from_secs(wait_time)); + wait_time = std::cmp::min(wait_time * 2, 10); // Cap at 10 seconds + } } - std::process::exit(-1); } }); input_service::fix_key_down_timeout_loop(); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 1645b242d..68c952af9 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1224,9 +1224,14 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver { log::error!("ipc connection closed: {}", err); + // Don't quit immediately if we're starting the service + // Give the service time to start and allow retries if is_cm { - crate::ui_cm_interface::quit_cm(); + // Check if service is starting up + let mut service_starting = false; + + #[cfg(windows)] + { + // On Windows, check if we're in elevated mode or if service is being installed + let is_elevated = crate::platform::is_elevated(None).unwrap_or(false); + service_starting = !is_elevated && (crate::platform::installing_service() || + (crate::platform::is_installed() && !crate::platform::is_root())); + } + + #[cfg(not(windows))] + { + // On other platforms, check if service is installed but not running as root + service_starting = crate::platform::is_installed() && + !crate::platform::is_root(); + } + + if !service_starting { + crate::ui_cm_interface::quit_cm(); + } } break; } @@ -1321,6 +1348,36 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver= max_attempts { + let mut service_starting = false; + + #[cfg(windows)] + { + // On Windows, check if service is being installed/started + let is_elevated = crate::platform::is_elevated(None).unwrap_or(false); + service_starting = !is_elevated && (crate::platform::installing_service() || + (crate::platform::is_installed() && !crate::platform::is_root())); + } + + #[cfg(not(windows))] + { + // On other platforms + service_starting = crate::platform::is_installed() && + !crate::platform::is_root(); + } + + if !service_starting { + log::error!("Failed to connect after {} attempts, quitting", max_attempts); + crate::ui_cm_interface::quit_cm(); + break; + } + } } *UI_STATUS.lock().unwrap() = UiStatus { status_num: -1, @@ -1333,7 +1390,9 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver