11use std:: io:: Result ;
22use std:: net:: SocketAddr ;
3- use std:: time:: Duration ;
4-
3+ use std:: time:: { Duration , Instant } ;
54use 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.
89pub 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