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
|
use std::{io, net::Ipv4Addr};
/// Pinger errors
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// Failed to run `ping` process
#[error("Failed to run ping command")]
PingError(#[from] io::Error),
/// ICMP timed out
#[error("Ping timed out")]
TimeoutError,
}
/// A pinger that sends ICMP requests without waiting for responses
pub struct Pinger {
addr: Ipv4Addr,
processes: Vec<duct::Handle>,
}
impl Pinger {
/// Creates a new pinger that will send ICMP requests only through the specified interface
pub fn new(addr: Ipv4Addr) -> Result<Self, Error> {
Ok(Self {
processes: vec![],
addr,
})
}
fn try_deplete_process_list(&mut self) {
self.processes.retain(|child| {
match child.try_wait() {
// child has terminated, doesn't have to be retained
Ok(Some(_)) => false,
_ => true,
}
});
}
}
impl super::Pinger for Pinger {
// Send an ICMP packet without waiting for a reply
fn send_icmp(&mut self) -> Result<(), Error> {
self.try_deplete_process_list();
let cmd = ping_cmd(self.addr, 1);
let handle = cmd.start().map_err(Error::PingError)?;
self.processes.push(handle);
Ok(())
}
fn reset(&mut self) {
let processes = std::mem::take(&mut self.processes);
for proc in processes {
if proc
.try_wait()
.map(|maybe_stopped| maybe_stopped.is_none())
.unwrap_or(false)
{
if let Err(err) = proc.kill() {
log::error!("Failed to kill ping process: {}", err);
}
}
}
}
}
impl Drop for Pinger {
fn drop(&mut self) {
for child in self.processes.iter_mut() {
if let Err(e) = child.kill() {
log::error!("Failed to kill ping process: {}", e);
}
}
}
}
fn ping_cmd(ip: Ipv4Addr, timeout_secs: u16) -> duct::Expression {
let timeout_secs = timeout_secs.to_string();
let ip = ip.to_string();
let args = ["-n", "-i", "1", "-w", &timeout_secs, &ip];
duct::cmd("ping", args)
.stdin_null()
.stdout_null()
.unchecked()
}
|