use caret::caret_int;
use derive_builder::Builder;
use tor_config::{ConfigBuildError, impl_standard_builder};
use tor_units::Percentage;
#[non_exhaustive]
#[derive(Builder, Copy, Clone, Debug, amplify::Getters)]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct FixedWindowParams {
#[getter(as_copy)]
circ_window_start: u16,
#[getter(as_copy)]
circ_window_min: u16,
#[getter(as_copy)]
circ_window_max: u16,
}
impl_standard_builder! { FixedWindowParams: !Deserialize + !Default }
#[non_exhaustive]
#[derive(Copy, Clone, Debug, amplify::Getters)]
pub struct VegasQueueParams {
#[getter(as_copy)]
alpha: u32,
#[getter(as_copy)]
beta: u32,
#[getter(as_copy)]
delta: u32,
#[getter(as_copy)]
gamma: u32,
#[getter(as_copy)]
ss_cwnd_cap: u32,
}
impl From<(u32, u32, u32, u32, u32)> for VegasQueueParams {
fn from(v: (u32, u32, u32, u32, u32)) -> Self {
Self {
alpha: v.0,
beta: v.1,
delta: v.2,
gamma: v.3,
ss_cwnd_cap: v.4,
}
}
}
#[non_exhaustive]
#[derive(Builder, Copy, Clone, Debug, amplify::Getters)]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct VegasParams {
cell_in_queue_params: VegasQueueParams,
#[getter(as_copy)]
ss_cwnd_max: u32,
#[getter(as_copy)]
cwnd_full_gap: u32,
cwnd_full_min_pct: Percentage<u32>,
#[getter(as_copy)]
cwnd_full_per_cwnd: u32,
}
impl_standard_builder! { VegasParams: !Deserialize + !Default }
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum Algorithm {
FixedWindow(FixedWindowParams),
Vegas(VegasParams),
}
impl Algorithm {
pub(crate) fn compatible_with_cgo(&self) -> bool {
match self {
Algorithm::FixedWindow(_) => false,
Algorithm::Vegas(_) => true,
}
}
}
caret_int! {
pub struct AlgorithmType(i32) {
FIXED_WINDOW = 0,
VEGAS = 2,
}
}
#[non_exhaustive]
#[derive(Builder, Clone, Debug, amplify::Getters)]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct RoundTripEstimatorParams {
ewma_cwnd_pct: Percentage<u32>,
#[getter(as_copy)]
ewma_max: u32,
#[getter(as_copy)]
ewma_ss_max: u32,
rtt_reset_pct: Percentage<u32>,
}
impl_standard_builder! { RoundTripEstimatorParams: !Deserialize + !Default }
#[non_exhaustive]
#[derive(Builder, Clone, Copy, Debug, amplify::Getters)]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct CongestionWindowParams {
#[getter(as_copy)]
cwnd_init: u32,
cwnd_inc_pct_ss: Percentage<u32>,
#[getter(as_copy)]
cwnd_inc: u32,
#[getter(as_copy)]
cwnd_inc_rate: u32,
#[getter(as_copy)]
cwnd_min: u32,
#[getter(as_copy)]
cwnd_max: u32,
#[getter(as_copy)]
sendme_inc: u32,
}
impl_standard_builder! { CongestionWindowParams: !Deserialize + !Default}
impl CongestionWindowParams {
pub(crate) fn set_sendme_inc(&mut self, inc: u8) {
self.sendme_inc = u32::from(inc);
}
}
#[non_exhaustive]
#[derive(Builder, Clone, Debug, amplify::Getters)]
#[builder(build_fn(error = "ConfigBuildError"))]
pub struct CongestionControlParams {
alg: Algorithm,
fixed_window_params: FixedWindowParams,
#[getter(as_mut)]
#[getter(as_copy)]
cwnd_params: CongestionWindowParams,
rtt_params: RoundTripEstimatorParams,
}
impl_standard_builder! { CongestionControlParams: !Deserialize + !Default }
impl CongestionControlParams {
pub(crate) fn is_enabled(&self) -> bool {
!matches!(self.alg(), Algorithm::FixedWindow(_))
}
pub(crate) fn use_fallback_alg(&mut self) {
self.alg = Algorithm::FixedWindow(self.fixed_window_params);
}
}
pub(crate) fn is_sendme_inc_valid(inc: u8, params: &CongestionControlParams) -> bool {
let inc_u32 = u32::from(inc);
if inc == 0 {
return false;
}
let inc_consensus = params.cwnd_params().sendme_inc();
if inc_u32 > (inc_consensus.saturating_add(1)) || inc_u32 < (inc_consensus.saturating_sub(1)) {
return false;
}
true
}
#[cfg(test)]
mod test {
use crate::{
ccparams::is_sendme_inc_valid, congestion::test_utils::params::build_cc_vegas_params,
};
#[test]
fn test_sendme_inc_valid() {
let params = build_cc_vegas_params();
let ref_inc = params.cwnd_params().sendme_inc() as u8;
assert!(is_sendme_inc_valid(ref_inc, ¶ms));
assert!(is_sendme_inc_valid(ref_inc + 1, ¶ms));
assert!(is_sendme_inc_valid(ref_inc - 1, ¶ms));
assert!(!is_sendme_inc_valid(0, ¶ms));
assert!(!is_sendme_inc_valid(ref_inc + 2, ¶ms));
assert!(!is_sendme_inc_valid(ref_inc - 2, ¶ms));
}
}