use std::{cmp, net::SocketAddr, time::Duration, time::Instant};
use super::{mtud::MtuDiscovery, pacing::Pacer};
use crate::{config::MtuDiscoveryConfig, congestion, packet::SpaceId, TIMER_GRANULARITY};
pub(super) struct PathData {
pub(super) remote: SocketAddr,
pub(super) rtt: RttEstimator,
pub(super) sending_ecn: bool,
pub(super) congestion: Box<dyn congestion::Controller>,
pub(super) pacing: Pacer,
pub(super) challenge: Option<u64>,
pub(super) challenge_pending: bool,
pub(super) validated: bool,
pub(super) total_sent: u64,
pub(super) total_recvd: u64,
pub(super) mtud: MtuDiscovery,
pub(super) first_packet_after_rtt_sample: Option<(SpaceId, u64)>,
}
impl PathData {
pub(super) fn new(
remote: SocketAddr,
initial_rtt: Duration,
congestion: Box<dyn congestion::Controller>,
initial_mtu: u16,
min_mtu: u16,
peer_max_udp_payload_size: Option<u16>,
mtud_config: Option<MtuDiscoveryConfig>,
now: Instant,
validated: bool,
) -> Self {
Self {
remote,
rtt: RttEstimator::new(initial_rtt),
sending_ecn: true,
pacing: Pacer::new(initial_rtt, congestion.initial_window(), initial_mtu, now),
congestion,
challenge: None,
challenge_pending: false,
validated,
total_sent: 0,
total_recvd: 0,
mtud: mtud_config.map_or(MtuDiscovery::disabled(initial_mtu, min_mtu), |config| {
MtuDiscovery::new(initial_mtu, min_mtu, peer_max_udp_payload_size, config)
}),
first_packet_after_rtt_sample: None,
}
}
pub(super) fn from_previous(remote: SocketAddr, prev: &Self, now: Instant) -> Self {
let congestion = prev.congestion.clone_box();
let smoothed_rtt = prev.rtt.get();
Self {
remote,
rtt: prev.rtt,
pacing: Pacer::new(smoothed_rtt, congestion.window(), prev.current_mtu(), now),
sending_ecn: true,
congestion,
challenge: None,
challenge_pending: false,
validated: false,
total_sent: 0,
total_recvd: 0,
mtud: prev.mtud.clone(),
first_packet_after_rtt_sample: prev.first_packet_after_rtt_sample,
}
}
pub(super) fn anti_amplification_blocked(&self, bytes_to_send: u64) -> bool {
!self.validated && self.total_recvd * 3 < self.total_sent + bytes_to_send
}
pub(super) fn current_mtu(&self) -> u16 {
self.mtud.current_mtu()
}
}
#[derive(Copy, Clone)]
pub struct RttEstimator {
latest: Duration,
smoothed: Option<Duration>,
var: Duration,
min: Duration,
}
impl RttEstimator {
fn new(initial_rtt: Duration) -> Self {
Self {
latest: initial_rtt,
smoothed: None,
var: initial_rtt / 2,
min: initial_rtt,
}
}
pub fn get(&self) -> Duration {
self.smoothed.unwrap_or(self.latest)
}
pub fn conservative(&self) -> Duration {
self.get().max(self.latest)
}
pub fn min(&self) -> Duration {
self.min
}
pub(crate) fn pto_base(&self) -> Duration {
self.get() + cmp::max(4 * self.var, TIMER_GRANULARITY)
}
pub(crate) fn update(&mut self, ack_delay: Duration, rtt: Duration) {
self.latest = rtt;
self.min = cmp::min(self.min, self.latest);
if let Some(smoothed) = self.smoothed {
let adjusted_rtt = if self.min + ack_delay <= self.latest {
self.latest - ack_delay
} else {
self.latest
};
let var_sample = if smoothed > adjusted_rtt {
smoothed - adjusted_rtt
} else {
adjusted_rtt - smoothed
};
self.var = (3 * self.var + var_sample) / 4;
self.smoothed = Some((7 * smoothed + adjusted_rtt) / 8);
} else {
self.smoothed = Some(self.latest);
self.var = self.latest / 2;
self.min = self.latest;
}
}
}