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.
This commit is contained in:
GlassOnTin 2025-05-29 16:21:08 +01:00
parent 1d24fcb2d0
commit 64cfdf67a7
2 changed files with 45 additions and 7 deletions

View File

@ -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

View File

@ -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();