iroh_relay/ping_tracker.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
use n0_future::time::{self, Duration, Instant};
use tracing::debug;
/// Maximum time for a ping response in the relay protocol.
pub const PING_TIMEOUT: Duration = Duration::from_secs(5);
/// Tracks pings on a single relay connection.
///
/// Only the last ping needs is useful, any previously sent ping is forgotten and ignored.
#[derive(Debug)]
pub struct PingTracker {
inner: Option<PingInner>,
default_timeout: Duration,
}
#[derive(Debug)]
struct PingInner {
data: [u8; 8],
deadline: Instant,
}
impl Default for PingTracker {
fn default() -> Self {
Self::new(PING_TIMEOUT)
}
}
impl PingTracker {
/// Creates a new ping tracker, setting the ping timeout for pings.
pub fn new(default_timeout: Duration) -> Self {
Self {
inner: None,
default_timeout,
}
}
/// Returns the current timeout set for pings.
pub fn default_timeout(&self) -> Duration {
self.default_timeout
}
/// Starts a new ping.
pub fn new_ping(&mut self) -> [u8; 8] {
let ping_data = rand::random();
debug!(data = ?ping_data, "Sending ping to relay server.");
self.inner = Some(PingInner {
data: ping_data,
deadline: Instant::now() + self.default_timeout,
});
ping_data
}
/// Updates the ping tracker with a received pong.
///
/// Only the pong of the most recent ping will do anything. There is no harm feeding
/// any pong however.
pub fn pong_received(&mut self, data: [u8; 8]) {
if self.inner.as_ref().map(|inner| inner.data) == Some(data) {
debug!(?data, "Pong received from relay server");
self.inner = None;
}
}
/// Cancel-safe waiting for a ping timeout.
///
/// Unless the most recent sent ping times out, this will never return.
pub async fn timeout(&mut self) {
match self.inner {
Some(PingInner { deadline, data }) => {
time::sleep_until(deadline).await;
debug!(?data, "Ping timeout.");
self.inner = None;
}
None => std::future::pending().await,
}
}
}