From 07b31cc3f325ea5790dfd3c69ebf6992eeb2d8bb Mon Sep 17 00:00:00 2001 From: ospab Date: Fri, 15 May 2026 22:04:11 +0300 Subject: [PATCH] fix: resolve infinite fatal tick log spam with auto-reconnect and centralize UAC elevation in run_client_core to protect GUI apps --- ostp-client/src/bridge.rs | 49 ++++++++++++++++++++++++--------------- ostp-client/src/runner.rs | 12 +++++----- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/ostp-client/src/bridge.rs b/ostp-client/src/bridge.rs index d6e2d65..3c5e6ea 100644 --- a/ostp-client/src/bridge.rs +++ b/ostp-client/src/bridge.rs @@ -277,33 +277,44 @@ impl Bridge { } _ = retransmit_tick.tick() => { if self.running { + let mut fatal_err = None; if let Some(sessions) = sessions_opt.as_mut() { for session in sessions.iter_mut() { - let action = match session.machine.on_event(OstpEvent::Tick) { - Ok(a) => a, - Err(e) => { - let _ = tx.send(UiEvent::Log(format!("Protocol tick error: {e}"))).await; - continue; - } - }; - - let mut queue = vec![action]; - while let Some(current_action) = queue.pop() { - match current_action { - ProtocolAction::Multiple(nested) => { - for a in nested { - queue.push(a); + match session.machine.on_event(OstpEvent::Tick) { + Ok(action) => { + let mut queue = vec![action]; + while let Some(current_action) = queue.pop() { + match current_action { + ProtocolAction::Multiple(nested) => { + for a in nested { + queue.push(a); + } + } + ProtocolAction::SendDatagram(frame) => { + let _ = send_datagram(&session.socket, &frame, self.turn_enabled).await; + self.metrics.bytes_sent.fetch_add(frame.len() as u64, Ordering::Relaxed); + } + _ => {} } } - ProtocolAction::SendDatagram(frame) => { - let _ = send_datagram(&session.socket, &frame, self.turn_enabled).await; - self.metrics.bytes_sent.fetch_add(frame.len() as u64, Ordering::Relaxed); - } - _ => {} + } + Err(e) => { + fatal_err = Some(e); + break; } } } } + + if let Some(e) = fatal_err { + let _ = tx.send(UiEvent::Log(format!("Protocol tick fatal error: {e}"))).await; + self.running = false; + _proxy_guard = None; + sessions_opt = None; + udp_rx_opt = None; + stream_map.clear(); + let _ = tx.send(UiEvent::TunnelStopped).await; + } } } proxy_ev = proxy_rx.recv(), if self.running && sessions_opt.as_ref().map(|s| { diff --git a/ostp-client/src/runner.rs b/ostp-client/src/runner.rs index 9a816cf..102943b 100644 --- a/ostp-client/src/runner.rs +++ b/ostp-client/src/runner.rs @@ -106,12 +106,6 @@ pub async fn run_client(config: crate::config::ClientConfig) -> Result<()> { hide_console(); } - #[cfg(target_os = "windows")] - if config.mode == "tun" && !is_admin() { - println!("[ostp-client] TUN mode requires Administrator privileges. Relaunching as Admin..."); - relaunch_as_admin()?; - } - let metrics = Arc::new(BridgeMetrics { bytes_sent: portable_atomic::AtomicU64::new(0), bytes_recv: portable_atomic::AtomicU64::new(0), @@ -133,6 +127,12 @@ pub async fn run_client_core( metrics: Arc, mut shutdown_rx_ext: watch::Receiver, ) -> Result<()> { + #[cfg(target_os = "windows")] + if config.mode == "tun" && !is_admin() { + println!("[ostp-client] TUN mode requires Administrator privileges. Relaunching executable as Admin..."); + relaunch_as_admin()?; + } + if config.mode == "tun" && !config.exclusions.processes.is_empty() { println!("[ostp-client] WARNING: process exclusions are not supported in the current TUN implementation"); }