Backed out changeset 317994df7ee4 (bug 1889691) for causing dt failures @ browser_web...
[gecko.git] / third_party / rust / neqo-transport / src / connection / params.rs
blob72d1efa3eeb2211ae47b6b72400f10081f5f8df8
1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4 // option. This file may not be copied, modified, or distributed
5 // except according to those terms.
7 use std::{cmp::max, time::Duration};
9 pub use crate::recovery::FAST_PTO_SCALE;
10 use crate::{
11     connection::{ConnectionIdManager, Role, LOCAL_ACTIVE_CID_LIMIT},
12     recv_stream::RECV_BUFFER_SIZE,
13     rtt::GRANULARITY,
14     stream_id::StreamType,
15     tparams::{self, PreferredAddress, TransportParameter, TransportParametersHandler},
16     tracking::DEFAULT_ACK_DELAY,
17     version::{Version, VersionConfig},
18     CongestionControlAlgorithm, Res,
21 const LOCAL_MAX_DATA: u64 = 0x3FFF_FFFF_FFFF_FFFF; // 2^62-1
22 const LOCAL_STREAM_LIMIT_BIDI: u64 = 16;
23 const LOCAL_STREAM_LIMIT_UNI: u64 = 16;
24 /// See `ConnectionParameters.ack_ratio` for a discussion of this value.
25 pub const ACK_RATIO_SCALE: u8 = 10;
26 /// By default, aim to have the peer acknowledge 4 times per round trip time.
27 /// See `ConnectionParameters.ack_ratio` for more.
28 const DEFAULT_ACK_RATIO: u8 = 4 * ACK_RATIO_SCALE;
29 /// The local value for the idle timeout period.
30 const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
31 const MAX_QUEUED_DATAGRAMS_DEFAULT: usize = 10;
33 /// What to do with preferred addresses.
34 #[derive(Debug, Clone)]
35 pub enum PreferredAddressConfig {
36     /// Disabled, whether for client or server.
37     Disabled,
38     /// Enabled at a client, disabled at a server.
39     Default,
40     /// Enabled at both client and server.
41     Address(PreferredAddress),
44 /// `ConnectionParameters` use for setting intitial value for QUIC parameters.
45 /// This collects configuration like initial limits, protocol version, and
46 /// congestion control algorithm.
47 #[derive(Debug, Clone)]
48 pub struct ConnectionParameters {
49     versions: VersionConfig,
50     cc_algorithm: CongestionControlAlgorithm,
51     /// Initial connection-level flow control limit.
52     max_data: u64,
53     /// Initial flow control limit for receiving data on bidirectional streams that the peer
54     /// creates.
55     max_stream_data_bidi_remote: u64,
56     /// Initial flow control limit for receiving data on bidirectional streams that this endpoint
57     /// creates.
58     max_stream_data_bidi_local: u64,
59     /// Initial flow control limit for receiving data on unidirectional streams that the peer
60     /// creates.
61     max_stream_data_uni: u64,
62     /// Initial limit on bidirectional streams that the peer creates.
63     max_streams_bidi: u64,
64     /// Initial limit on unidirectional streams that this endpoint creates.
65     max_streams_uni: u64,
66     /// The ACK ratio determines how many acknowledgements we will request as a
67     /// fraction of both the current congestion window (expressed in packets) and
68     /// as a fraction of the current round trip time.  This value is scaled by
69     /// `ACK_RATIO_SCALE`; that is, if the goal is to have at least five
70     /// acknowledgments every round trip, set the value to `5 * ACK_RATIO_SCALE`.
71     /// Values less than `ACK_RATIO_SCALE` are clamped to `ACK_RATIO_SCALE`.
72     ack_ratio: u8,
73     /// The duration of the idle timeout for the connection.
74     idle_timeout: Duration,
75     preferred_address: PreferredAddressConfig,
76     datagram_size: u64,
77     outgoing_datagram_queue: usize,
78     incoming_datagram_queue: usize,
79     fast_pto: u8,
80     fuzzing: bool,
81     grease: bool,
82     pacing: bool,
85 impl Default for ConnectionParameters {
86     fn default() -> Self {
87         Self {
88             versions: VersionConfig::default(),
89             cc_algorithm: CongestionControlAlgorithm::NewReno,
90             max_data: LOCAL_MAX_DATA,
91             max_stream_data_bidi_remote: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
92             max_stream_data_bidi_local: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
93             max_stream_data_uni: u64::try_from(RECV_BUFFER_SIZE).unwrap(),
94             max_streams_bidi: LOCAL_STREAM_LIMIT_BIDI,
95             max_streams_uni: LOCAL_STREAM_LIMIT_UNI,
96             ack_ratio: DEFAULT_ACK_RATIO,
97             idle_timeout: DEFAULT_IDLE_TIMEOUT,
98             preferred_address: PreferredAddressConfig::Default,
99             datagram_size: 0,
100             outgoing_datagram_queue: MAX_QUEUED_DATAGRAMS_DEFAULT,
101             incoming_datagram_queue: MAX_QUEUED_DATAGRAMS_DEFAULT,
102             fast_pto: FAST_PTO_SCALE,
103             fuzzing: false,
104             grease: true,
105             pacing: true,
106         }
107     }
110 impl ConnectionParameters {
111     #[must_use]
112     pub fn get_versions(&self) -> &VersionConfig {
113         &self.versions
114     }
116     pub(crate) fn get_versions_mut(&mut self) -> &mut VersionConfig {
117         &mut self.versions
118     }
120     /// Describe the initial version that should be attempted and all the
121     /// versions that should be enabled.  This list should contain the initial
122     /// version and be in order of preference, with more preferred versions
123     /// before less preferred.
124     #[must_use]
125     pub fn versions(mut self, initial: Version, all: Vec<Version>) -> Self {
126         self.versions = VersionConfig::new(initial, all);
127         self
128     }
130     #[must_use]
131     pub fn get_cc_algorithm(&self) -> CongestionControlAlgorithm {
132         self.cc_algorithm
133     }
135     #[must_use]
136     pub fn cc_algorithm(mut self, v: CongestionControlAlgorithm) -> Self {
137         self.cc_algorithm = v;
138         self
139     }
141     #[must_use]
142     pub fn get_max_data(&self) -> u64 {
143         self.max_data
144     }
146     #[must_use]
147     pub fn max_data(mut self, v: u64) -> Self {
148         self.max_data = v;
149         self
150     }
152     #[must_use]
153     pub fn get_max_streams(&self, stream_type: StreamType) -> u64 {
154         match stream_type {
155             StreamType::BiDi => self.max_streams_bidi,
156             StreamType::UniDi => self.max_streams_uni,
157         }
158     }
160     /// # Panics
161     ///
162     /// If v > 2^60 (the maximum allowed by the protocol).
163     #[must_use]
164     pub fn max_streams(mut self, stream_type: StreamType, v: u64) -> Self {
165         assert!(v <= (1 << 60), "max_streams is too large");
166         match stream_type {
167             StreamType::BiDi => {
168                 self.max_streams_bidi = v;
169             }
170             StreamType::UniDi => {
171                 self.max_streams_uni = v;
172             }
173         }
174         self
175     }
177     /// Get the maximum stream data that we will accept on different types of streams.
178     ///
179     /// # Panics
180     ///
181     /// If `StreamType::UniDi` and `false` are passed as that is not a valid combination.
182     #[must_use]
183     pub fn get_max_stream_data(&self, stream_type: StreamType, remote: bool) -> u64 {
184         match (stream_type, remote) {
185             (StreamType::BiDi, false) => self.max_stream_data_bidi_local,
186             (StreamType::BiDi, true) => self.max_stream_data_bidi_remote,
187             (StreamType::UniDi, false) => {
188                 panic!("Can't get receive limit on a stream that can only be sent.")
189             }
190             (StreamType::UniDi, true) => self.max_stream_data_uni,
191         }
192     }
194     /// Set the maximum stream data that we will accept on different types of streams.
195     ///
196     /// # Panics
197     ///
198     /// If `StreamType::UniDi` and `false` are passed as that is not a valid combination
199     /// or if v >= 62 (the maximum allowed by the protocol).
200     #[must_use]
201     pub fn max_stream_data(mut self, stream_type: StreamType, remote: bool, v: u64) -> Self {
202         assert!(v < (1 << 62), "max stream data is too large");
203         match (stream_type, remote) {
204             (StreamType::BiDi, false) => {
205                 self.max_stream_data_bidi_local = v;
206             }
207             (StreamType::BiDi, true) => {
208                 self.max_stream_data_bidi_remote = v;
209             }
210             (StreamType::UniDi, false) => {
211                 panic!("Can't set receive limit on a stream that can only be sent.")
212             }
213             (StreamType::UniDi, true) => {
214                 self.max_stream_data_uni = v;
215             }
216         }
217         self
218     }
220     /// Set a preferred address (which only has an effect for a server).
221     #[must_use]
222     pub fn preferred_address(mut self, preferred: PreferredAddress) -> Self {
223         self.preferred_address = PreferredAddressConfig::Address(preferred);
224         self
225     }
227     /// Disable the use of preferred addresses.
228     #[must_use]
229     pub fn disable_preferred_address(mut self) -> Self {
230         self.preferred_address = PreferredAddressConfig::Disabled;
231         self
232     }
234     #[must_use]
235     pub fn get_preferred_address(&self) -> &PreferredAddressConfig {
236         &self.preferred_address
237     }
239     #[must_use]
240     pub fn ack_ratio(mut self, ack_ratio: u8) -> Self {
241         self.ack_ratio = ack_ratio;
242         self
243     }
245     #[must_use]
246     pub fn get_ack_ratio(&self) -> u8 {
247         self.ack_ratio
248     }
250     /// # Panics
251     ///
252     /// If `timeout` is 2^62 milliseconds or more.
253     #[must_use]
254     pub fn idle_timeout(mut self, timeout: Duration) -> Self {
255         assert!(timeout.as_millis() < (1 << 62), "idle timeout is too long");
256         self.idle_timeout = timeout;
257         self
258     }
260     #[must_use]
261     pub fn get_idle_timeout(&self) -> Duration {
262         self.idle_timeout
263     }
265     #[must_use]
266     pub fn get_datagram_size(&self) -> u64 {
267         self.datagram_size
268     }
270     #[must_use]
271     pub fn datagram_size(mut self, v: u64) -> Self {
272         self.datagram_size = v;
273         self
274     }
276     #[must_use]
277     pub fn get_outgoing_datagram_queue(&self) -> usize {
278         self.outgoing_datagram_queue
279     }
281     #[must_use]
282     pub fn outgoing_datagram_queue(mut self, v: usize) -> Self {
283         // The max queue length must be at least 1.
284         self.outgoing_datagram_queue = max(v, 1);
285         self
286     }
288     #[must_use]
289     pub fn get_incoming_datagram_queue(&self) -> usize {
290         self.incoming_datagram_queue
291     }
293     #[must_use]
294     pub fn incoming_datagram_queue(mut self, v: usize) -> Self {
295         // The max queue length must be at least 1.
296         self.incoming_datagram_queue = max(v, 1);
297         self
298     }
300     #[must_use]
301     pub fn get_fast_pto(&self) -> u8 {
302         self.fast_pto
303     }
305     /// Scale the PTO timer.  A value of `FAST_PTO_SCALE` follows the spec, a smaller
306     /// value does not, but produces more probes with the intent of ensuring lower
307     /// latency in the event of tail loss. A value of `FAST_PTO_SCALE/4` is quite
308     /// aggressive. Smaller values (other than zero) are not rejected, but could be
309     /// very wasteful. Values greater than `FAST_PTO_SCALE` delay probes and could
310     /// reduce performance. It should not be possible to increase the PTO timer by
311     /// too much based on the range of valid values, but a maximum value of 255 will
312     /// result in very poor performance.
313     /// Scaling PTO this way does not affect when persistent congestion is declared,
314     /// but may change how many retransmissions are sent before declaring persistent
315     /// congestion.
316     ///
317     /// # Panics
318     ///
319     /// A value of 0 is invalid and will cause a panic.
320     #[must_use]
321     pub fn fast_pto(mut self, scale: u8) -> Self {
322         assert_ne!(scale, 0);
323         self.fast_pto = scale;
324         self
325     }
327     #[must_use]
328     pub fn is_fuzzing(&self) -> bool {
329         self.fuzzing
330     }
332     #[must_use]
333     pub fn fuzzing(mut self, enable: bool) -> Self {
334         self.fuzzing = enable;
335         self
336     }
338     #[must_use]
339     pub fn is_greasing(&self) -> bool {
340         self.grease
341     }
343     #[must_use]
344     pub fn grease(mut self, grease: bool) -> Self {
345         self.grease = grease;
346         self
347     }
349     #[must_use]
350     pub fn pacing_enabled(&self) -> bool {
351         self.pacing
352     }
354     #[must_use]
355     pub fn pacing(mut self, pacing: bool) -> Self {
356         self.pacing = pacing;
357         self
358     }
360     /// # Errors
361     /// When a connection ID cannot be obtained.
362     /// # Panics
363     /// Only when this code includes a transport parameter that is invalid.
364     pub fn create_transport_parameter(
365         &self,
366         role: Role,
367         cid_manager: &mut ConnectionIdManager,
368     ) -> Res<TransportParametersHandler> {
369         let mut tps = TransportParametersHandler::new(role, self.versions.clone());
370         // default parameters
371         tps.local.set_integer(
372             tparams::ACTIVE_CONNECTION_ID_LIMIT,
373             u64::try_from(LOCAL_ACTIVE_CID_LIMIT).unwrap(),
374         );
375         tps.local.set_empty(tparams::DISABLE_MIGRATION);
376         tps.local.set_empty(tparams::GREASE_QUIC_BIT);
377         tps.local.set_integer(
378             tparams::MAX_ACK_DELAY,
379             u64::try_from(DEFAULT_ACK_DELAY.as_millis()).unwrap(),
380         );
381         tps.local.set_integer(
382             tparams::MIN_ACK_DELAY,
383             u64::try_from(GRANULARITY.as_micros()).unwrap(),
384         );
386         // set configurable parameters
387         tps.local
388             .set_integer(tparams::INITIAL_MAX_DATA, self.max_data);
389         tps.local.set_integer(
390             tparams::INITIAL_MAX_STREAM_DATA_BIDI_LOCAL,
391             self.max_stream_data_bidi_local,
392         );
393         tps.local.set_integer(
394             tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
395             self.max_stream_data_bidi_remote,
396         );
397         tps.local.set_integer(
398             tparams::INITIAL_MAX_STREAM_DATA_UNI,
399             self.max_stream_data_uni,
400         );
401         tps.local
402             .set_integer(tparams::INITIAL_MAX_STREAMS_BIDI, self.max_streams_bidi);
403         tps.local
404             .set_integer(tparams::INITIAL_MAX_STREAMS_UNI, self.max_streams_uni);
405         tps.local.set_integer(
406             tparams::IDLE_TIMEOUT,
407             u64::try_from(self.idle_timeout.as_millis()).unwrap_or(0),
408         );
409         if let PreferredAddressConfig::Address(preferred) = &self.preferred_address {
410             if role == Role::Server {
411                 let (cid, srt) = cid_manager.preferred_address_cid()?;
412                 tps.local.set(
413                     tparams::PREFERRED_ADDRESS,
414                     TransportParameter::PreferredAddress {
415                         v4: preferred.ipv4(),
416                         v6: preferred.ipv6(),
417                         cid,
418                         srt,
419                     },
420                 );
421             }
422         }
423         tps.local
424             .set_integer(tparams::MAX_DATAGRAM_FRAME_SIZE, self.datagram_size);
425         Ok(tps)
426     }