From bfd3a9d7d91a7e804dbb06d6b86ff13815b9baef Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 22 Aug 2026 21:33:54 +0800 Subject: [PATCH] bump hbb_common: WebRTC peer connections own their I/O runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closing the controlling window left the controlled side waiting out ICE decay — ~25-30s in the peer's log, its disconnected/failed ladder running to completion — where TCP delivers a FIN at once. The session end closed the pc by spawning onto io_loop's own `#[tokio::main(flavor = "current_thread")]` runtime, which is dropped the moment io_loop returns, and nothing after that call yields: the task was never polled even once, so no DTLS close_notify ever left. Every attempt to fix that on the caller's side failed the same way, because the mismatch was never about where the close ran: a pc's UDP sockets register with the reactor, and its ICE/DTLS/SCTP pumps spawn on the runtime, that is current while it is built — so a pc created by a session outlives the only runtime that can drive its I/O, and a close driven anywhere else completes without reaching the wire. The bump homes them where they can outlive any caller: WebRTCStream builds on a process-lifetime runtime and every detached close runs there as its own never-cancelled task. io_loop keeps its plain close_webrtc() calls and only documents why nothing here may spawn or await the teardown on the dying session runtime. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016HV43uh1ztv6Wm5qi3Y1ne --- libs/hbb_common | 2 +- src/client/io_loop.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/hbb_common b/libs/hbb_common index 1f8463d72..01ee2f46e 160000 --- a/libs/hbb_common +++ b/libs/hbb_common @@ -1 +1 @@ -Subproject commit 1f8463d720e9d9452be75d3b5e584a787ad34385 +Subproject commit 01ee2f46ece493110510b8d8b5ca019488f33f7a diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 411c3ea9b..9fc07895d 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -197,7 +197,9 @@ impl Remote { } self.handle_disconnected(round); // Close the WebRTC pc on this decline path too (no-op for TCP/WS); otherwise its - // pc lingers in the global session cache until ICE decays on its own. + // pc lingers in the global session cache until ICE decays on its own. The pc + // and its teardown live on hbb_common's WebRTC I/O runtime, so this session + // runtime's death on return affects neither. peer.close_webrtc(); return; } @@ -347,7 +349,11 @@ impl Remote { log::debug!("Exit io_loop of id={}", self.handler.get_id()); // Close the WebRTC peer connection (if this session used it) so its pc is not left // lingering in the global session cache after the session ends; dropping `peer` - // alone does not release it. No-op for TCP/WebSocket transports. + // alone does not release it. No-op for TCP/WebSocket transports. The pc, its + // sockets and pump tasks, and this close all live on hbb_common's WebRTC I/O + // runtime — nothing may run them on this session runtime, which is dropped the + // moment io_loop returns and would kill the teardown (or, if awaited under a + // timeout, cancel it after `close()` latches `is_closed`, stranding the pc). peer.close_webrtc(); // Stop client audio server. if let Some(s) = self.stop_voice_call_sender.take() {