use std::net::{TcpStream, ToSocketAddrs};
use std::time::Duration;
pub fn probe(addr: impl ToSocketAddrs, timeout: Duration) -> bool {
let Ok(mut addrs) = addr.to_socket_addrs() else {
return false;
};
addrs.any(|candidate| TcpStream::connect_timeout(&candidate, timeout).is_ok())
}
#[must_use]
pub fn is_online(timeout: Duration) -> bool {
probe("1.1.1.1:443", timeout) || probe("8.8.8.8:53", timeout)
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::TcpListener;
const WAIT: Duration = Duration::from_secs(2);
#[test]
fn open_port_probes_true() -> Result<(), std::io::Error> {
let listener = TcpListener::bind("127.0.0.1:0")?;
let port = listener.local_addr()?.port();
assert!(probe(format!("127.0.0.1:{port}"), WAIT));
Ok(())
}
#[test]
fn closed_port_probes_false() -> Result<(), std::io::Error> {
let listener = TcpListener::bind("127.0.0.1:0")?;
let port = listener.local_addr()?.port();
drop(listener);
assert!(!probe(format!("127.0.0.1:{port}"), WAIT));
Ok(())
}
#[test]
fn unresolvable_host_probes_false() {
assert!(!probe("nonexistent.invalid:80", WAIT));
}
}