Skip to content

Commit 39961b3

Browse files
committed
Double timeout
1 parent 98c58b8 commit 39961b3

File tree

1 file changed

+35
-24
lines changed

1 file changed

+35
-24
lines changed

talpid-wireguard/src/lib.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,12 @@ async fn auto_mtu_detection(
10041004
use talpid_tunnel::{ICMP_HEADER_SIZE, MIN_IPV4_MTU};
10051005
use tokio_stream::StreamExt;
10061006

1007-
const PING_TIMEOUT: Duration = Duration::from_secs(5);
1007+
/// Max time to wait for any ping, when this expires,
1008+
/// we give up and throw an `Error::MtuDetectionAllDropped`
1009+
const PING_TIMEOUT: Duration = Duration::from_secs(10);
1010+
/// Max time to wait after the first ping arrives. Every ping
1011+
/// after this timeout will be counted as dropped.
1012+
const PING_OFFSET_TIMEOUT: Duration = Duration::from_secs(2);
10081013

10091014
let config_builder = Config::builder().kind(surge_ping::ICMP::V4);
10101015
#[cfg(any(target_os = "macos", target_os = "linux"))]
@@ -1015,6 +1020,8 @@ async fn auto_mtu_detection(
10151020
let linspace = mtu_spacing(MIN_IPV4_MTU, current_mtu, step_size);
10161021

10171022
let payload_buf = vec![0; current_mtu as usize];
1023+
1024+
let mut ping_stream = linspace
10181025
.iter()
10191026
.enumerate()
10201027
.map(|(i, &mtu)| {
@@ -1031,31 +1038,35 @@ async fn auto_mtu_detection(
10311038
.await
10321039
}
10331040
})
1034-
.collect();
1041+
.collect::<FuturesUnordered<_>>()
1042+
.map_ok(|(packet, _rtt)| {
1043+
let surge_ping::IcmpPacket::V4(packet) = packet else {
1044+
panic!("ICMP ping response was not of IPv4 type");
1045+
};
1046+
let size = packet.get_size() as u16 + IPV4_HEADER_SIZE;
1047+
log::trace!("Got ICMP ping response of total size {size}");
1048+
debug_assert_eq!(size, linspace[packet.get_sequence().0 as usize]);
1049+
size
1050+
});
1051+
1052+
let first_ping_size = match ping_stream
1053+
.next()
1054+
.await
1055+
.expect("At least one pings should be sent")
1056+
{
1057+
Ok(size) => size,
1058+
// If the first ping we get back timed out, then all of them did
1059+
Err(SurgeError::Timeout { .. }) => return Err(Error::MtuDetectionAllDropped),
1060+
// Short circuit and return error on unexpected error types
1061+
Err(e) => return Err(Error::MtuDetectionPingError(e)),
1062+
};
10351063

10361064
ping_stream
1037-
.map(|res| match res {
1038-
// Map successful pings to packet size
1039-
Ok((packet, _rtt)) => {
1040-
let surge_ping::IcmpPacket::V4(packet) = packet else {
1041-
panic!("ICMP ping response was not of IPv4 type");
1042-
};
1043-
let size = packet.get_size() as u16 + IPV4_HEADER_SIZE;
1044-
log::trace!("Got ICMP ping response of total size {size}");
1045-
debug_assert_eq!(size, linspace[packet.get_sequence().0 as usize]);
1046-
Ok(Some(size))
1047-
}
1048-
// Filter out dropped pings
1049-
Err(SurgeError::Timeout { seq }) => {
1050-
log::info!("Ping of size {} dropped", linspace[seq.0 as usize]);
1051-
Ok(None)
1052-
}
1053-
// Short circuit and return error on unexpected error types
1054-
Err(e) => Err(Error::MtuDetectionPingError(e)),
1055-
})
1056-
.try_fold(None, |acc, mtu| future::ready(Ok(acc.max(mtu))))
1057-
.await?
1058-
.ok_or(Error::MtuDetectionAllDropped)
1065+
.timeout(PING_OFFSET_TIMEOUT) // Start a new, sorter, timeout
1066+
.map_while(|res| res.ok()) // Filter out remaining pings after this timeout
1067+
.try_fold(first_ping_size, |acc, mtu| future::ready(Ok(acc.max(mtu)))) // Get largest ping
1068+
.await
1069+
.map_err(Error::MtuDetectionPingError)
10591070
}
10601071

10611072
/// Creates a linear spacing of MTU values with the given step size. Always includes the given end

0 commit comments

Comments
 (0)