#[derive(Clone, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct FlowCtrlParameters {
pub cc_xoff_client: CellCount<{ tor_cell::relaycell::PAYLOAD_MAX_SIZE_ALL as u32 }>,
pub cc_xoff_exit: CellCount<{ tor_cell::relaycell::PAYLOAD_MAX_SIZE_ALL as u32 }>,
pub cc_xon_rate: CellCount<{ tor_cell::relaycell::PAYLOAD_MAX_SIZE_ANY as u32 }>,
pub cc_xon_change_pct: u32,
pub cc_xon_ewma_cnt: u32,
}
impl FlowCtrlParameters {
#[cfg(test)]
pub(crate) fn defaults_for_tests() -> Self {
Self {
cc_xoff_client: CellCount::new(500),
cc_xoff_exit: CellCount::new(500),
cc_xon_rate: CellCount::new(500),
cc_xon_change_pct: 25,
cc_xon_ewma_cnt: 2,
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct CellCount<const BYTES_PER_CELL: u32>(u32);
impl<const BYTES_PER_CELL: u32> CellCount<BYTES_PER_CELL> {
pub const fn new(cells: u32) -> Self {
Self(cells)
}
pub const fn as_cells(&self) -> u32 {
self.0
}
pub const fn as_bytes(&self) -> u64 {
let cells = self.0 as u64;
cells
.checked_mul(BYTES_PER_CELL as u64)
.expect("u32 * u32 should fit within a u64")
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn compare_to_ctor_values() {
let params = FlowCtrlParameters {
cc_xoff_client: CellCount::new(1),
cc_xoff_exit: CellCount::new(1),
cc_xon_rate: CellCount::new(1),
cc_xon_change_pct: 1,
cc_xon_ewma_cnt: 1,
};
const C_TOR_RELAY_PAYLOAD_SIZE_MIN: u64 = 509 - (16 + 1 + 2 + 2);
const C_TOR_RELAY_PAYLOAD_SIZE_MAX: u64 = 509 - (1 + 2 + 2 + 4 + 2);
assert_eq!(
params.cc_xoff_client.as_bytes(),
C_TOR_RELAY_PAYLOAD_SIZE_MIN,
);
assert_eq!(params.cc_xoff_exit.as_bytes(), C_TOR_RELAY_PAYLOAD_SIZE_MIN);
assert_eq!(params.cc_xon_rate.as_bytes(), C_TOR_RELAY_PAYLOAD_SIZE_MAX);
}
}