use std::io::ErrorKind;
use std::net::{IpAddr, SocketAddr};
use std::time::{Duration, Instant};
use tokio::net::TcpStream;
const CONNECT_TIMEOUT: Duration = Duration::from_secs(2);
pub struct ReachResult {
pub ok: bool,
pub detail: String,
pub ms: u128,
}
pub async fn reachable(ip: IpAddr, port: u16) -> ReachResult {
let addr = SocketAddr::new(ip, port);
let start = Instant::now();
let outcome = tokio::time::timeout(CONNECT_TIMEOUT, TcpStream::connect(addr)).await;
let ms = start.elapsed().as_millis();
match outcome {
Ok(Ok(_)) => ReachResult {
ok: true,
detail: "reachable".into(),
ms,
},
Ok(Err(e)) if e.kind() == ErrorKind::ConnectionRefused => ReachResult {
ok: true,
detail: "reachable (port closed, host answered)".into(),
ms,
},
Ok(Err(e)) => ReachResult {
ok: false,
detail: format!("unreachable ({})", e.kind()),
ms,
},
Err(_) => ReachResult {
ok: false,
detail: "unreachable or timed out".into(),
ms,
},
}
}