From 64cfdf67a700b222977b1ee6001432bb491f7947 Mon Sep 17 00:00:00 2001 From: GlassOnTin Date: Thu, 29 May 2025 16:21:08 +0100 Subject: [PATCH] Fix GUI closing when enabling service on Windows This fixes issue #7010 where the RustDesk GUI closes immediately when enabling the service. The problem was: 1. GUI has IPC server on \\.\\pipe\\RustDesk\\query 2. Service tries to start and create IPC server on same pipe 3. Service gets 'Access is denied' error 4. Service calls stop_main_window_process() which sends Close message to GUI 5. GUI exits immediately The fix: 1. Added retry logic with exponential backoff (up to 10 attempts) in server.rs 2. Added environment variable check to avoid killing GUI during service installation 3. Added Windows support in ipc.rs to restart GUI after receiving Close message 4. Increased wait times to allow proper handover of IPC server from GUI to service This allows the GUI to gracefully restart while the service takes over the IPC server. --- src/ipc.rs | 13 ++++++++++++- src/server.rs | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/ipc.rs b/src/ipc.rs index a74a0c103..bedb63e2e 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -420,10 +420,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")] { @@ -442,6 +442,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 87e6f390f..16c7d4b3f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -547,13 +547,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();