fix: resolve infinite fatal tick log spam with auto-reconnect and centralize UAC elevation in run_client_core to protect GUI apps

This commit is contained in:
ospab 2026-05-15 22:04:11 +03:00
parent 609564fdd9
commit 07b31cc3f3
2 changed files with 36 additions and 25 deletions

View File

@ -277,33 +277,44 @@ impl Bridge {
} }
_ = retransmit_tick.tick() => { _ = retransmit_tick.tick() => {
if self.running { if self.running {
let mut fatal_err = None;
if let Some(sessions) = sessions_opt.as_mut() { if let Some(sessions) = sessions_opt.as_mut() {
for session in sessions.iter_mut() { for session in sessions.iter_mut() {
let action = match session.machine.on_event(OstpEvent::Tick) { match session.machine.on_event(OstpEvent::Tick) {
Ok(a) => a, Ok(action) => {
Err(e) => { let mut queue = vec![action];
let _ = tx.send(UiEvent::Log(format!("Protocol tick error: {e}"))).await; while let Some(current_action) = queue.pop() {
continue; match current_action {
} ProtocolAction::Multiple(nested) => {
}; for a in nested {
queue.push(a);
let mut queue = vec![action]; }
while let Some(current_action) = queue.pop() { }
match current_action { ProtocolAction::SendDatagram(frame) => {
ProtocolAction::Multiple(nested) => { let _ = send_datagram(&session.socket, &frame, self.turn_enabled).await;
for a in nested { self.metrics.bytes_sent.fetch_add(frame.len() as u64, Ordering::Relaxed);
queue.push(a); }
_ => {}
} }
} }
ProtocolAction::SendDatagram(frame) => { }
let _ = send_datagram(&session.socket, &frame, self.turn_enabled).await; Err(e) => {
self.metrics.bytes_sent.fetch_add(frame.len() as u64, Ordering::Relaxed); 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| { proxy_ev = proxy_rx.recv(), if self.running && sessions_opt.as_ref().map(|s| {

View File

@ -106,12 +106,6 @@ pub async fn run_client(config: crate::config::ClientConfig) -> Result<()> {
hide_console(); 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 { let metrics = Arc::new(BridgeMetrics {
bytes_sent: portable_atomic::AtomicU64::new(0), bytes_sent: portable_atomic::AtomicU64::new(0),
bytes_recv: portable_atomic::AtomicU64::new(0), bytes_recv: portable_atomic::AtomicU64::new(0),
@ -133,6 +127,12 @@ pub async fn run_client_core(
metrics: Arc<BridgeMetrics>, metrics: Arc<BridgeMetrics>,
mut shutdown_rx_ext: watch::Receiver<bool>, mut shutdown_rx_ext: watch::Receiver<bool>,
) -> Result<()> { ) -> 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() { if config.mode == "tun" && !config.exclusions.processes.is_empty() {
println!("[ostp-client] WARNING: process exclusions are not supported in the current TUN implementation"); println!("[ostp-client] WARNING: process exclusions are not supported in the current TUN implementation");
} }