aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-proto/src/congestion/fixed.rs
blob: 9197cfb4b443cce46366255a1fd1450414e361c8 (plain)
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Implementation of the Fixed Window congestion control algorithm.
//!
//! This is used by the circuit reactor in order to decide when to send data and SENDMEs.
//!
//! The vanilla flow control system of fixed window SENDMEs in the spec.

use crate::Result;

use super::{
    CongestionControlAlgorithm, CongestionSignals, CongestionWindow, State,
    params::{Algorithm, FixedWindowParams},
    rtt::{ClockStall, RoundtripTimeEstimator},
    sendme::{self, WindowParams},
};

/// Fixed window algorithm which is essentially the SENDME v0 with fixed receive and send window
/// size.
#[derive(Clone, Debug)]
pub(crate) struct FixedWindow {
    /// Window used to say how many cells we can receive.
    recvwindow: sendme::CircRecvWindow,
    /// Window used to say how many cells we can send.
    sendwindow: sendme::CircSendWindow,
    /// The params from the consensus.
    params: FixedWindowParams,
}

impl FixedWindow {
    /// Create a new `FixedWindow` form a given initial sendwindow size.
    ///
    /// Note: the initial recvwindow size is given by [`sendme::CircParams::start`].
    pub(crate) fn new(params: FixedWindowParams) -> Self {
        let initial_window = params.circ_window_start();
        Self {
            recvwindow: sendme::CircRecvWindow::new(sendme::CircParams::start()),
            sendwindow: sendme::CircSendWindow::new(initial_window),
            params,
        }
    }
}

impl CongestionControlAlgorithm for FixedWindow {
    fn uses_stream_sendme(&self) -> bool {
        true
    }

    fn uses_xon_xoff(&self) -> bool {
        false
    }

    fn is_next_cell_sendme(&self) -> bool {
        self.sendwindow.should_record_tag()
    }

    fn can_send(&self) -> bool {
        self.sendwindow.window() > 0
    }

    fn cwnd(&self) -> Option<CongestionWindow> {
        None
    }

    fn sendme_received(
        &mut self,
        _state: &mut State,
        _rtt: &mut RoundtripTimeEstimator,
        _signals: CongestionSignals,
        _clock_stall: ClockStall,
    ) -> Result<()> {
        self.sendwindow.put()
    }

    fn sendme_sent(&mut self) -> Result<()> {
        self.recvwindow.put();
        Ok(())
    }

    fn data_received(&mut self) -> Result<bool> {
        self.recvwindow.take()
    }

    fn data_sent(&mut self) -> Result<()> {
        self.sendwindow.take()
    }

    #[cfg(feature = "conflux")]
    fn inflight(&self) -> Option<u32> {
        None
    }

    #[cfg(test)]
    fn send_window(&self) -> u32 {
        u32::from(self.sendwindow.window())
    }

    fn algorithm(&self) -> Algorithm {
        Algorithm::FixedWindow(self.params)
    }
}