diff --git a/src/lib.rs b/src/lib.rs index eb1fec3..b7f8363 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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, }; diff --git a/src/ping.rs b/src/ping.rs index e9e3841..7f854e5 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -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}; @@ -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 { + 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 @@ -75,8 +81,6 @@ fn ping_with_socktype( payload: Option<&Token>, bind_device: Option<&str>, ) -> Result { - let time_start = SystemTime::now(); - let timeout = match timeout { Some(timeout) => timeout, None => Duration::from_secs(4), @@ -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]; cast is sound @@ -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(), @@ -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) }); - } } } @@ -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,