1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#[cfg(target_os = "linux")]
use std::ffi::CStr;
use std::{
net::{IpAddr, SocketAddr},
time::{Duration, Instant},
};
use rand::random;
use tokio::task;
use tokio::time::sleep;
use crate::error::{Result, SurgeError};
use crate::icmp::{EchoReply, EchoRequest};
use crate::unix::AsyncSocket;
#[derive(Debug, Clone)]
pub struct Pinger {
host: IpAddr,
ident: u16,
size: usize,
timeout: Duration,
socket: AsyncSocket,
}
impl Pinger {
pub fn new(host: IpAddr) -> Result<Pinger> {
Ok(Pinger {
host,
ident: random(),
size: 56,
timeout: Duration::from_secs(2),
socket: AsyncSocket::new()?,
})
}
#[cfg(target_os = "linux")]
pub fn bind_device(&mut self, interface: Option<&CStr>) -> Result<&mut Pinger> {
self.socket.bind_device(interface)?;
Ok(self)
}
pub fn ident(&mut self, val: u16) -> &mut Pinger {
self.ident = val;
self
}
pub fn size(&mut self, size: usize) -> &mut Pinger {
self.size = size;
self
}
pub fn timeout(&mut self, timeout: Duration) -> &mut Pinger {
self.timeout = timeout;
self
}
async fn recv_reply(&self) -> Result<EchoReply> {
let mut buffer = [0; 2048];
loop {
let size = self.socket.recv(&mut buffer).await?;
let echo_reply = EchoReply::decode(&buffer[..size])?;
if echo_reply.identifier == self.ident {
return Ok(echo_reply);
}
}
}
pub async fn ping(&self, seq_cnt: u16) -> Result<(EchoReply, Duration)> {
let sender = self.socket.clone();
let mut packet = EchoRequest::new(self.ident, seq_cnt, self.size).encode()?;
let sock_addr = SocketAddr::new(self.host, 0);
let send_time = Instant::now();
task::spawn(async move {
let _size = sender
.send_to(&mut packet, &sock_addr.into())
.await
.expect("socket send packet error");
});
tokio::select! {
reply = self.recv_reply() => {
reply.map(|echo_reply| (echo_reply, Instant::now() - send_time))
}
_ = sleep(self.timeout) => Err(SurgeError::Timeout),
}
}
}