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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Multiplexor configuration
//
// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later
/// Configuration parameters for the multiplexor.
/// See each method for details on the parameters.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Options {
pub(crate) keepalive_interval: crate::timing::OptionalDuration,
pub(crate) keepalive_timeout: crate::timing::OptionalDuration,
pub(crate) datagram_buffer_size: usize,
pub(crate) stream_buffer_size: usize,
pub(crate) bind_buffer_size: usize,
pub(crate) max_flow_id_retries: usize,
pub(crate) rwnd: u32,
pub(crate) default_rwnd_threshold: u32,
}
impl Default for Options {
fn default() -> Self {
Self::new()
}
}
impl Options {
/// Create a new [`Options`] instance with default values.
#[must_use]
pub const fn new() -> Self {
const DATAGRAM_BUFFER_SIZE: usize = 1 << 9;
const STREAM_BUFFER_SIZE: usize = 1 << 4;
const MAX_FLOW_ID_RETRIES: usize = 3;
#[cfg(not(test))]
const RWND: u32 = 1 << 9;
#[cfg(test)]
const RWND: u32 = 4;
#[cfg(not(test))]
const DEFAULT_RWND_THRESHOLD: u32 = 1 << 8;
#[cfg(test)]
const DEFAULT_RWND_THRESHOLD: u32 = RWND;
Self {
keepalive_interval: crate::timing::OptionalDuration::NONE,
keepalive_timeout: crate::timing::OptionalDuration::NONE,
datagram_buffer_size: DATAGRAM_BUFFER_SIZE,
stream_buffer_size: STREAM_BUFFER_SIZE,
bind_buffer_size: 0,
max_flow_id_retries: MAX_FLOW_ID_RETRIES,
rwnd: RWND,
default_rwnd_threshold: DEFAULT_RWND_THRESHOLD,
}
}
/// Sets the interval at which to send [`Ping`](crate::ws::Message::Ping) frames.
#[must_use]
pub const fn keepalive_interval(mut self, interval: crate::timing::OptionalDuration) -> Self {
self.keepalive_interval = interval;
self
}
/// Sets the maximum allowed delay between sending a [`Ping`](crate::ws::Message::Ping)
/// and receiving a corresponding [`Pong`](crate::ws::Message::Pong).
#[must_use]
pub fn keepalive_timeout(mut self, timeout: crate::timing::OptionalDuration) -> Self {
self.keepalive_timeout = timeout.max(self.keepalive_interval);
self
}
/// Number of datagram frames to buffer in the channels on the receiving end.
/// If the buffer is not read fast enough, excess datagrams will be dropped.
///
/// # Panics
/// Panics if the buffer size is not positive.
#[must_use]
pub const fn datagram_buffer_size(mut self, size: usize) -> Self {
assert!(size > 0, "datagram_buffer_size must be greater than 0");
self.datagram_buffer_size = size;
self
}
/// Number of `MuxStream`s to buffer in the channels on the receiving end.
/// Since there is a handshake to obtain `MuxStream`s, there should be no
/// need to have a crazy high buffer size.
///
/// # Panics
/// Panics if the buffer size is not positive.
#[must_use]
pub const fn stream_buffer_size(mut self, size: usize) -> Self {
assert!(size > 0, "stream_buffer_size must be greater than 0");
self.stream_buffer_size = size;
self
}
/// Number of [`Bind`](crate::frame::OpCode::Bind) requests to buffer
/// in the channels on the receiving end.
/// Setting this to zero disallows the multiplexor from accepting any
/// `Bind` requests from the other end and
/// is the default. Make sure the security implications are understood
/// before enabling this.
#[must_use]
pub const fn bind_buffer_size(mut self, size: usize) -> Self {
self.bind_buffer_size = size;
self
}
/// Number of retries for establishing a connection if the other end rejects our `flow_id` selection.
///
/// # Panics
/// Panics if the number of retries is not positive.
#[must_use]
pub const fn max_flow_id_retries(mut self, retries: usize) -> Self {
assert!(retries > 0, "max_flow_id_retries must be greater than 0");
self.max_flow_id_retries = retries;
self
}
/// Number of `StreamFrame`s to buffer in `MuxStream`'s channels before blocking.
///
/// # Panics
/// Panics if the buffer size is not positive or does not fit in a `usize`.
#[must_use]
#[expect(clippy::cast_possible_truncation)]
pub const fn rwnd(mut self, rwnd: u32) -> Self {
// Make sure this value fits in a usize
assert!((rwnd as usize) as u32 == rwnd, "rwnd must fit in a usize");
assert!(rwnd > 0, "rwnd must be greater than 0");
self.rwnd = rwnd;
self
}
/// Number of [`Push`](crate::frame::OpCode::Push) frames between [`Acknowledge`](crate::frame::OpCode::Acknowledge)s:
/// If too low, `Acknowledge`s will consume too much bandwidth;
/// If too high, writers may block.
///
/// Note that if the peer indicates a lower `rwnd` value in the handshake,
/// this value will be ignored for that connection.
///
/// # Panics
/// Panics if the value is not positive.
#[must_use]
pub const fn default_rwnd_threshold(mut self, threshold: u32) -> Self {
assert!(
threshold > 0,
"default_rwnd_threshold must be greater than 0"
);
self.default_rwnd_threshold = threshold;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn test_options() {
let options = Options::new()
.keepalive_interval(Duration::from_secs(100).into())
.datagram_buffer_size(33)
.stream_buffer_size(44)
.bind_buffer_size(55)
.max_flow_id_retries(66)
.rwnd(77)
.default_rwnd_threshold(88);
assert_eq!(options.keepalive_interval, Duration::from_secs(100).into());
assert_eq!(options.datagram_buffer_size, 33);
assert_eq!(options.stream_buffer_size, 44);
assert_eq!(options.bind_buffer_size, 55);
assert_eq!(options.max_flow_id_retries, 66);
assert_eq!(options.rwnd, 77);
assert_eq!(options.default_rwnd_threshold, 88);
}
}