Skip to content
This repository was archived by the owner on Jan 18, 2026. It is now read-only.

Commit c37231c

Browse files
Asankilppk5ls20
andauthored
feat: add ICMP ping fallback to TCP mechanism (#33)
Co-authored-by: pk5ls20 <pk5ls20@outlook.com>
1 parent ce8d99a commit c37231c

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

mania/src/core/ping.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
use std::io::Result;
22
use std::net::SocketAddr;
3-
use std::time::Duration;
4-
3+
use std::time::{Duration, Instant};
54
use surge_ping::{Client, Config, ICMP, PingIdentifier, PingSequence};
5+
use tokio::net::TcpStream;
6+
use tokio::task::JoinSet;
67

78
/// Ping a list of addresses and return the latency.
89
pub async fn ping(addrs: Vec<SocketAddr>, ipv6: bool) -> Result<Vec<(SocketAddr, Duration)>> {
10+
// 首先尝试ICMP ping
911
let icmp = Client::new(&if ipv6 {
1012
Config::builder().kind(ICMP::V6).build()
1113
} else {
1214
Config::default()
13-
})?;
15+
});
1416

17+
match icmp {
18+
Ok(icmp) => ping_with_icmp(icmp, addrs).await,
19+
Err(e) => {
20+
tracing::debug!("ICMP ping failed: {}, fallback to TCP ping", e);
21+
ping_with_tcp(addrs).await
22+
}
23+
}
24+
}
25+
26+
async fn ping_with_icmp(
27+
icmp: Client,
28+
addrs: Vec<SocketAddr>,
29+
) -> Result<Vec<(SocketAddr, Duration)>> {
1530
let mut pingers = Vec::with_capacity(addrs.len());
1631
for (i, addr) in addrs.iter().enumerate() {
1732
let pinger = icmp.pinger(addr.ip(), PingIdentifier(i as u16)).await;
1833
pingers.push(pinger);
1934
}
2035

2136
let mut results = Vec::with_capacity(addrs.len());
22-
let mut join_set = tokio::task::JoinSet::new();
37+
let mut join_set = JoinSet::new();
2338
for (mut pinger, addr) in pingers.into_iter().zip(addrs) {
2439
join_set.spawn(async move {
2540
let latency = pinger
@@ -35,3 +50,26 @@ pub async fn ping(addrs: Vec<SocketAddr>, ipv6: bool) -> Result<Vec<(SocketAddr,
3550

3651
Ok(results)
3752
}
53+
54+
async fn ping_with_tcp(addrs: Vec<SocketAddr>) -> Result<Vec<(SocketAddr, Duration)>> {
55+
let mut results = Vec::with_capacity(addrs.len());
56+
let mut join_set = JoinSet::new();
57+
58+
for addr in addrs {
59+
join_set.spawn(async move {
60+
let start = Instant::now();
61+
let timeout = Duration::from_secs(1);
62+
let latency = match tokio::time::timeout(timeout, TcpStream::connect(addr)).await {
63+
Ok(Ok(_)) => start.elapsed(),
64+
_ => Duration::MAX,
65+
};
66+
(addr, latency)
67+
});
68+
}
69+
70+
while let Some(result) = join_set.join_next().await {
71+
results.push(result?);
72+
}
73+
74+
Ok(results)
75+
}

0 commit comments

Comments
 (0)