From bb4d56a09044a66a8745f83e709d90df306f8b60 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 16 Apr 2026 14:17:18 +0200 Subject: [PATCH 1/2] Add more details to output (similar to ping) --- src/main.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index a6e93d6..0f9fc99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,6 @@ enum CustomError { HostResolutionFailure, SurgeError(SurgeError), IoError(std::io::Error), - TimeoutError, } impl From for CustomError { @@ -41,7 +40,6 @@ impl fmt::Display for CustomError { CustomError::HostResolutionFailure => write!(f, "Host resolution failure"), CustomError::SurgeError(e) => write!(f, "Surge error: {:?}", e), CustomError::IoError(e) => write!(f, "I/O error: {}", e), - CustomError::TimeoutError => write!(f, "Timeout error"), } } } @@ -62,17 +60,34 @@ async fn ping_host(target_host: &str, output_file: &str, timeout_ms: u64, interv let config = Config::default(); let client = Client::new(&config).map_err(CustomError::IoError)?; let mut pinger = client.pinger(ip_addr, PingIdentifier(0)).await; + let mut seq_num: u16 = 0; loop { - let result = match timeout(Duration::from_millis(timeout_ms), pinger.ping(PingSequence(0), &[0])).await { - Ok(Ok((_packet, _duration))) => { - format!("Host {} is reachable", target_host) + let result = match timeout(Duration::from_millis(timeout_ms), pinger.ping(PingSequence(seq_num), &[0])).await { + Ok(Ok((packet, duration))) => { + let rtt_ms = duration.as_secs_f64() * 1000.0; + match packet { + surge_ping::IcmpPacket::V4(icmpv4) => { + let packet_size = icmpv4.get_size(); + let ttl = icmpv4.get_ttl().unwrap_or(0); + format!( + "Host {} is reachable ({} bytes from {}: icmp_seq={} ttl={} time={:.3} ms)", + target_host, packet_size, target_host, seq_num, ttl, rtt_ms + ) + } + surge_ping::IcmpPacket::V6(_) => { + format!( + "Host {} is reachable (from {}: icmp_seq={} time={:.3} ms)", + target_host, target_host, seq_num, rtt_ms + ) + } + } } Ok(Err(_)) => { - format!("Host {} is unreachable", target_host) + format!("Host {} is unreachable (icmp_seq={} Destination Host Unreachable)", target_host, seq_num) } Err(_) => { - return Err(CustomError::TimeoutError); + format!("Host {} is unreachable (icmp_seq={} timeout)", target_host, seq_num) } }; @@ -83,6 +98,7 @@ async fn ping_host(target_host: &str, output_file: &str, timeout_ms: u64, interv println!("{}", content); } + seq_num = seq_num.wrapping_add(1); tokio::time::sleep(Duration::from_secs(interval_secs)).await; } } From 27fde5603f22ee26a75c21d7f05b54f91dee8107 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 16 Apr 2026 14:26:45 +0200 Subject: [PATCH 2/2] Add details --- src/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main.rs b/src/main.rs index 0f9fc99..0d47df0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ const DEFAULT_OUTPUT_FILE: &str = "output.txt"; const DEFAULT_TIMEOUT_MS: isize = 1000; const DEFAULT_INTERVAL_SECS: isize = 60; +/// Custom error type to encapsulate different kinds of errors that can occur in the application #[derive(Debug)] enum CustomError { HostResolutionFailure, @@ -22,18 +23,21 @@ enum CustomError { IoError(std::io::Error), } +/// Implement conversion from SurgeError to CustomError to allow easy error handling when performing ping operations impl From for CustomError { fn from(error: SurgeError) -> Self { CustomError::SurgeError(error) } } +/// Implement conversion from std::io::Error to CustomError to allow easy error handling when performing file operations impl From for CustomError { fn from(error: std::io::Error) -> Self { CustomError::IoError(error) } } +/// Custom error type that encapsulates different kinds of errors that can occur in the application impl fmt::Display for CustomError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -44,8 +48,10 @@ impl fmt::Display for CustomError { } } +/// Implement the standard Error trait for CustomError to allow it to be used as an error type in Rust impl Error for CustomError {} +/// Asynchronous function to ping a host and log the results to a file async fn ping_host(target_host: &str, output_file: &str, timeout_ms: u64, interval_secs: u64, verbose: bool) -> Result<(), CustomError> { let ip_addr = match target_host.parse::() { Ok(ip) => IpAddr::V4(ip), @@ -103,6 +109,7 @@ async fn ping_host(target_host: &str, output_file: &str, timeout_ms: u64, interv } } +/// Helper function to append content to a file, creating the file if it doesn't exist fn append_to_file(file_path: &str, content: &str) -> Result<(), CustomError> { if !fs::metadata(file_path).is_ok() { let _ = OpenOptions::new().create(true).write(true).open(file_path)?; @@ -113,6 +120,7 @@ fn append_to_file(file_path: &str, content: &str) -> Result<(), CustomError> { Ok(()) } +/// Main function that sets up the command-line interface and runs the application fn main() { let args: Vec = env::args().collect(); @@ -131,6 +139,7 @@ fn main() { app.run(args); } +/// Main action function that executes the pinging logic based on the provided context and flags fn action(context: &Context) { let target = context.string_flag("target").unwrap_or(DEFAULT_TARGET.to_string()); let output_file = context.string_flag("output").unwrap_or(DEFAULT_OUTPUT_FILE.to_string());