Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ mod packet;
mod ping;

pub use crate::errors::Error;
#[allow(deprecated)]
pub use crate::ping::{
Ping, PingResult, SocketType, SocketType::DGRAM, SocketType::RAW, dgramsock, new, ping, rawsock,
};
28 changes: 11 additions & 17 deletions src/ping.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::net::{IpAddr, SocketAddr};
use std::time::{Duration, SystemTime};
use std::time::{Duration, Instant};

use rand::random;
use socket2::{Domain, Protocol, Socket, Type};
Expand All @@ -11,6 +11,12 @@ const TOKEN_SIZE: usize = 24;
const ECHO_REQUEST_BUFFER_SIZE: usize = ICMP_HEADER_SIZE + TOKEN_SIZE;
type Token = [u8; TOKEN_SIZE];

fn remaining_timeout(started_at: Instant, timeout: Duration) -> std::io::Result<Duration> {
timeout
.checked_sub(started_at.elapsed())
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::TimedOut, "ping request timed out"))
}

/// The kind of socket used to send the ICMP request.
///
/// The default depends on the platform. On Windows [`Ping::new`] uses
Expand Down Expand Up @@ -75,8 +81,6 @@ fn ping_with_socktype(
payload: Option<&Token>,
bind_device: Option<&str>,
) -> Result<PingResult, Error> {
let time_start = SystemTime::now();

let timeout = match timeout {
Some(timeout) => timeout,
None => Duration::from_secs(4),
Expand Down Expand Up @@ -125,12 +129,12 @@ fn ping_with_socktype(

socket.set_write_timeout(Some(timeout))?;

let started_at = Instant::now();
socket.send_to(&mut buffer, &dest.into())?;

// loop until either an echo whose payload token matches was received or timeout is over
let mut elapsed_time = Duration::from_secs(0);
loop {
socket.set_read_timeout(Some(timeout - elapsed_time))?;
socket.set_read_timeout(Some(remaining_timeout(started_at, timeout)?))?;

let mut buffer: [u8; 2048] = [0; 2048];
// socket2 0.6 recv_from requires &mut [MaybeUninit<u8>]; cast is sound
Expand Down Expand Up @@ -172,16 +176,10 @@ fn ping_with_socktype(
}
};

// update elapsed time before deciding whether the payload token matches
elapsed_time = match SystemTime::now().duration_since(time_start) {
Ok(reply) => reply,
Err(_) => return Err(Error::InternalError.into()),
};

if reply.payload == request.payload {
// payload token matched: this reply belongs to our request
return Ok(PingResult {
rtt: elapsed_time,
rtt: started_at.elapsed(),
ident: reply.ident,
seq_cnt: reply.seq_cnt,
payload: reply.payload.to_vec(),
Expand All @@ -190,11 +188,6 @@ fn ping_with_socktype(
ttl: recv_ttl,
});
}

if elapsed_time >= timeout {
let error = std::io::Error::new(std::io::ErrorKind::TimedOut, "Timeout occured");
return Err(Error::IoError { error: (error) });
}
}
}

Expand Down Expand Up @@ -237,6 +230,7 @@ pub mod dgramsock {
}
}

#[deprecated(since = "0.8.0", note = "use `Ping::new` builder and `Ping::send` instead")]
pub fn ping(
addr: IpAddr,
timeout: Option<Duration>,
Expand Down
Loading