diff --git a/Cargo.lock b/Cargo.lock index 2792b60d9..c00b0ade1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3651,7 +3651,7 @@ dependencies = [ [[package]] name = "kcp-sys" version = "0.1.0" -source = "git+https://github.com/rustdesk-org/kcp-sys#1e5e30ab8b8c2f7787ab0f88822de36476531562" +source = "git+https://github.com/rustdesk-org/kcp-sys#32a6c09fc6223f54aea83981a6aa8995931d29be" dependencies = [ "anyhow", "auto_impl", @@ -3660,6 +3660,7 @@ dependencies = [ "bytes", "cc", "dashmap 6.1.0", + "log", "parking_lot", "rand 0.8.5", "thiserror 2.0.11", diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 29b7601ca..4de0e7e32 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -77,6 +77,7 @@ pub struct Remote { video_threads: HashMap, chroma: Arc>>, last_record_state: bool, + sent_close_reason: bool, } #[derive(Default)] @@ -125,6 +126,7 @@ impl Remote { video_threads: Default::default(), chroma: Default::default(), last_record_state: false, + sent_close_reason: false, } } @@ -172,7 +174,7 @@ impl Remote { ) .await { - Ok(((mut peer, direct, pk, _kcp), (feedback, rendezvous_server))) => { + Ok(((mut peer, direct, pk, kcp), (feedback, rendezvous_server))) => { self.handler .connection_round_state .lock() @@ -320,6 +322,13 @@ impl Remote { if let Some(s) = self.stop_voice_call_sender.take() { s.send(()).ok(); } + if kcp.is_some() { + // Send the close reason if it hasn't been sent yet, as KCP cannot detect the socket close event. + self.send_close_reason(&mut peer, "kcp").await; + // KCP does not send messages immediately, so wait to ensure the last message is sent. + // 1ms works in my test, but 30ms is more reliable. + tokio::time::sleep(Duration::from_millis(30)).await; + } } Err(err) => { self.handler.on_establish_connection_error(err.to_string()); @@ -511,14 +520,22 @@ impl Remote { } } + async fn send_close_reason(&mut self, peer: &mut Stream, reason: &str) { + if self.sent_close_reason { + return; + } + let mut misc = Misc::new(); + misc.set_close_reason(reason.to_owned()); + let mut msg = Message::new(); + msg.set_misc(misc); + allow_err!(peer.send(&msg).await); + self.sent_close_reason = true; + } + async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool { match data { Data::Close => { - let mut misc = Misc::new(); - misc.set_close_reason("".to_owned()); - let mut msg = Message::new(); - msg.set_misc(misc); - allow_err!(peer.send(&msg).await); + self.send_close_reason(peer, "").await; return false; } Data::Login((os_username, os_password, password, remember)) => { @@ -1712,6 +1729,7 @@ impl Remote { } } Some(misc::Union::CloseReason(c)) => { + self.sent_close_reason = true; // The controlled end will close, no need to send close reason self.handler.msgbox("error", "Connection Error", &c, ""); return false; } diff --git a/src/server/connection.rs b/src/server/connection.rs index e02b24918..01d84437d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1937,6 +1937,16 @@ impl Connection { } async fn on_message(&mut self, msg: Message) -> bool { + if let Some(message::Union::Misc(misc)) = &msg.union { + // Move the CloseReason forward, as this message needs to be received when unauthorized, especially for kcp. + if let Some(misc::Union::CloseReason(s)) = &misc.union { + log::info!("receive close reason: {}", s); + self.on_close("Peer close", true).await; + raii::AuthedConnID::check_remove_session(self.inner.id(), self.session_key()); + return false; + } + } + // After handling CloseReason messages, proceed to process other message types if let Some(message::Union::LoginRequest(lr)) = msg.union { self.handle_login_request_without_validation(&lr).await; if self.authorized { @@ -2790,15 +2800,6 @@ impl Connection { Some(Instant::now().into()), ); } - Some(misc::Union::CloseReason(_)) => { - self.on_close("Peer close", true).await; - raii::AuthedConnID::check_remove_session( - self.inner.id(), - self.session_key(), - ); - return false; - } - Some(misc::Union::RestartRemoteDevice(_)) => { #[cfg(not(any(target_os = "android", target_os = "ios")))] if self.restart {