From ccebb900e833b831989ea354104b12378bc2fd8d Mon Sep 17 00:00:00 2001 From: FujiApple Date: Wed, 24 Jul 2024 21:54:20 +0800 Subject: [PATCH] feat(core): do not crash the tracer for some socket errors (#1238) --- crates/trippy-core/src/strategy.rs | 31 +++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/crates/trippy-core/src/strategy.rs b/crates/trippy-core/src/strategy.rs index 4692412e4..b4e01b08c 100644 --- a/crates/trippy-core/src/strategy.rs +++ b/crates/trippy-core/src/strategy.rs @@ -1,13 +1,13 @@ use self::state::TracerState; use crate::config::StrategyConfig; -use crate::error::{Error, Result}; +use crate::error::{Error, IoError, Result}; use crate::net::Network; use crate::probe::{ ProbeStatus, Response, ResponseData, ResponseSeq, ResponseSeqIcmp, ResponseSeqTcp, ResponseSeqUdp, }; use crate::types::{Checksum, Sequence, TimeToLive, TraceId}; -use crate::{Extensions, IcmpPacketType, MultipathStrategy, PortDirection, Protocol}; +use crate::{Extensions, IcmpPacketType, MultipathStrategy, PortDirection, Probe, Protocol}; use std::net::IpAddr; use std::time::{Duration, SystemTime}; use tracing::instrument; @@ -99,16 +99,20 @@ impl)> Strategy { let sent = SystemTime::now(); match self.config.protocol { Protocol::Icmp => { - network.send_probe(st.next_probe(sent))?; + let probe = st.next_probe(sent); + Self::do_send(network, st, probe)?; + } + Protocol::Udp => { + let probe = st.next_probe(sent); + Self::do_send(network, st, probe)?; } - Protocol::Udp => network.send_probe(st.next_probe(sent))?, Protocol::Tcp => { let mut probe = if st.round_has_capacity() { st.next_probe(sent) } else { return Err(Error::InsufficientCapacity); }; - while let Err(err) = network.send_probe(probe) { + while let Err(err) = Self::do_send(network, st, probe) { match err { Error::AddressInUse(_) => { if st.round_has_capacity() { @@ -126,6 +130,23 @@ impl)> Strategy { Ok(()) } + /// Send the probe and handle errors. + /// + /// Some errors are transient and should not be considered fatal. In these cases we mark the + /// probe as failed and continue. + fn do_send(network: &mut N, st: &mut TracerState, probe: Probe) -> Result<()> { + match network.send_probe(probe) { + Ok(()) => Ok(()), + Err(Error::IoError( + IoError::Bind(_, _) | IoError::Connect(_, _) | IoError::SendTo(_, _), + )) => { + st.fail_probe(); + Ok(()) + } + Err(err) => Err(err), + } + } + /// Read and process the next incoming `ICMP` packet. /// /// We allow multiple probes to be in-flight at any time, and we cannot guarantee that responses