use std::net::SocketAddr;
use enum_dispatch::enum_dispatch;
use futures::stream::{FuturesUnordered, StreamExt};
use tokio::{
net::TcpStream,
time::{sleep, Duration},
};
#[derive(Debug)]
pub enum PingResult {
Timeout,
Addr(SocketAddr),
Err,
}
macro_rules! addr {
($($ip:expr),+) => {
SocketAddr::new(
crate::ip!($($ip),+),
443,
)
};
}
#[enum_dispatch]
trait PingCtrl {
async fn ping(self) -> PingResult;
}
#[enum_dispatch(PingCtrl)]
pub enum Pinger {
Ping,
Timeout,
}
pub struct Ping(SocketAddr);
impl PingCtrl for Ping {
async fn ping(self) -> PingResult {
if TcpStream::connect(&self.0).await.is_ok() {
PingResult::Addr(self.0)
} else {
PingResult::Err
}
}
}
pub struct Timeout(u64);
impl PingCtrl for Timeout {
async fn ping(self) -> PingResult {
sleep(Duration::from_secs(self.0)).await;
PingResult::Timeout
}
}
pub async fn use_ipv6() -> bool {
let addr_li: &[SocketAddr] = &[
addr!(0x2606, 0x4700, 0x4700, 0, 0, 0, 0, 0x64),
addr!(0x2400, 0x3200, 0, 0, 0, 0, 0, 0x0001),
addr!(0x2400, 0xda00, 0, 0, 0, 0, 0, 0x6666),
addr!(0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888),
addr!(120, 53, 53, 53),
addr!(1, 1, 1, 1),
addr!(8, 8, 8, 8),
addr!(223, 5, 5, 5),
];
let mut timeout = 3;
'out: loop {
let mut ing = FuturesUnordered::new();
for addr in addr_li {
ing.push(Pinger::from(Ping(*addr)).ping());
}
ing.push(Pinger::from(Timeout(timeout)).ping());
if timeout < 10 {
timeout += 1;
}
while let Some(result) = ing.next().await {
match result {
PingResult::Addr(addr) => return addr.is_ipv6(),
PingResult::Timeout => {
continue 'out;
}
_ => {}
}
}
}
}