fix(async): finish the blocking-call sweep — scan, 3 SSH handlers, DNS

A codebase sweep for siblings of e282c059 (blocking network I/O parked
on the tokio runtime) found the openwrt fix was incomplete:

- openwrt.scan: scan_subnet is async in name only — up to 255 SEQUENTIAL
  blocking TCP probes at 500ms each (~2 min on a /24 that silently
  drops) plus a blocking SSH verify per candidate. One click of 'scan
  for routers' held a worker for that whole time. Now spawn_blocking.
- provision-tollgate / scan-wifi / configure-wan still ran their SSH
  exchanges inline; bounded_tcp caps each socket op but a session is
  many sequential ops (provision runs opkg install over SSH), so worst
  case was minutes. All three now spawn_blocking.
- network::check_dns: blocking glibc to_socket_addrs with no app-level
  bound, on every Server-tab load via network.diagnostics. Against a
  stale resolver — the moved-network case — that is 5-40s per refresh.
  Now spawn_blocking plus a 5s cap, so the tile reports 'no DNS'
  instead of hanging.

Verified false positives left alone: every other bare TcpStream::connect
targets 127.0.0.1 (fails instantly), and every remote reqwest client
already sets a timeout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-15 11:03:08 -04:00
co-authored by Claude Fable 5
parent 6e89acced7
commit 203c2b6e50
2 changed files with 70 additions and 14 deletions
+17 -2
View File
@@ -302,9 +302,24 @@ async fn check_tor_connectivity() -> bool {
}
/// Check DNS resolution works.
///
/// `to_socket_addrs` is blocking glibc resolution with no app-level bound:
/// against a dead or stale resolver — the moved-network case — it can block
/// 540s (timeout × attempts × nameservers). This runs on every Server-tab
/// load via `network.diagnostics`, so inline it parked a tokio worker each
/// refresh. Off the runtime, and bounded so the tile reports "no DNS"
/// instead of hanging.
async fn check_dns() -> bool {
use std::net::ToSocketAddrs;
"cloudflare.com:443".to_socket_addrs().is_ok()
let probe = tokio::task::spawn_blocking(|| {
use std::net::ToSocketAddrs;
"cloudflare.com:443".to_socket_addrs().is_ok()
});
match tokio::time::timeout(std::time::Duration::from_secs(5), probe).await {
Ok(Ok(ok)) => ok,
// Timed out or the task failed: the blocking resolve may still be
// running on the pool, but the caller is no longer waiting on it.
_ => false,
}
}
// --- Router Compatibility Abstraction ---