From 8d3be6fb8c5d8f49331e55edf517b4b1ff043277 Mon Sep 17 00:00:00 2001 From: foxxcn Date: Sun, 11 Oct 2026 22:19:39 +0800 Subject: [PATCH] webrtc: break the session/peer-connection cycle that leaked UDP sockets Every taken-over session left about three UDP sockets open on the device (one ICE host candidate per local address), so rustkvm_app's fd count grew by ~3.5 per session even though pc.close() was called. webrtc-util's UdpSocket::close is a no-op; the socket only closes when its last Arc drops. The on_data_channel handler, which the peer connection owns, captured a Session clone holding Arc, and DataChannelManager passed that Session on into the data channel callbacks. The connection therefore owned a reference to itself and was never dropped, keeping its ICE agent and candidate sockets alive. Give the handler a Session clone without the peer connection; data channel routing only uses the id and channels. Co-Authored-By: Claude Opus 5.5 --- app/src/webrtc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/webrtc.rs b/app/src/webrtc.rs index 2481285..93a3662 100644 --- a/app/src/webrtc.rs +++ b/app/src/webrtc.rs @@ -327,7 +327,12 @@ impl WebRTCApi { }) })); - let session_clone = session.clone(); + // This handler (and the data channel callbacks it installs) lives inside + // the peer connection, so it must not hold the connection itself: that + // cycle kept every closed session's ICE agent alive, and with it one + // UDP socket per local address, because UDP conns only close on drop. + let mut session_clone = session.clone(); + session_clone.peer_connection = None; peer_connection.on_data_channel(Box::new(move |data_channel: Arc| { let session = session_clone.clone(); let label = data_channel.label().to_string();