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;
11 connection::{ConnectionIdManager, Role, LOCAL_ACTIVE_CID_LIMIT},
12 recv_stream::RECV_BUFFER_SIZE,
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.
38 /// Enabled at a client, disabled at a server.
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.
53 /// Initial flow control limit for receiving data on bidirectional streams that the peer
55 max_stream_data_bidi_remote: u64,
56 /// Initial flow control limit for receiving data on bidirectional streams that this endpoint
58 max_stream_data_bidi_local: u64,
59 /// Initial flow control limit for receiving data on unidirectional streams that the peer
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.
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`.
73 /// The duration of the idle timeout for the connection.
74 idle_timeout: Duration,
75 preferred_address: PreferredAddressConfig,
77 outgoing_datagram_queue: usize,
78 incoming_datagram_queue: usize,
85 impl Default for ConnectionParameters {
86 fn default() -> 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,
100 outgoing_datagram_queue: MAX_QUEUED_DATAGRAMS_DEFAULT,
101 incoming_datagram_queue: MAX_QUEUED_DATAGRAMS_DEFAULT,
102 fast_pto: FAST_PTO_SCALE,
110 impl ConnectionParameters {
112 pub fn get_versions(&self) -> &VersionConfig {
116 pub(crate) fn get_versions_mut(&mut self) -> &mut VersionConfig {
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.
125 pub fn versions(mut self, initial: Version, all: Vec<Version>) -> Self {
126 self.versions = VersionConfig::new(initial, all);
131 pub fn get_cc_algorithm(&self) -> CongestionControlAlgorithm {
136 pub fn cc_algorithm(mut self, v: CongestionControlAlgorithm) -> Self {
137 self.cc_algorithm = v;
142 pub fn get_max_data(&self) -> u64 {
147 pub fn max_data(mut self, v: u64) -> Self {
153 pub fn get_max_streams(&self, stream_type: StreamType) -> u64 {
155 StreamType::BiDi => self.max_streams_bidi,
156 StreamType::UniDi => self.max_streams_uni,
162 /// If v > 2^60 (the maximum allowed by the protocol).
164 pub fn max_streams(mut self, stream_type: StreamType, v: u64) -> Self {
165 assert!(v <= (1 << 60), "max_streams is too large");
167 StreamType::BiDi => {
168 self.max_streams_bidi = v;
170 StreamType::UniDi => {
171 self.max_streams_uni = v;
177 /// Get the maximum stream data that we will accept on different types of streams.
181 /// If `StreamType::UniDi` and `false` are passed as that is not a valid combination.
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.")
190 (StreamType::UniDi, true) => self.max_stream_data_uni,
194 /// Set the maximum stream data that we will accept on different types of streams.
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).
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;
207 (StreamType::BiDi, true) => {
208 self.max_stream_data_bidi_remote = v;
210 (StreamType::UniDi, false) => {
211 panic!("Can't set receive limit on a stream that can only be sent.")
213 (StreamType::UniDi, true) => {
214 self.max_stream_data_uni = v;
220 /// Set a preferred address (which only has an effect for a server).
222 pub fn preferred_address(mut self, preferred: PreferredAddress) -> Self {
223 self.preferred_address = PreferredAddressConfig::Address(preferred);
227 /// Disable the use of preferred addresses.
229 pub fn disable_preferred_address(mut self) -> Self {
230 self.preferred_address = PreferredAddressConfig::Disabled;
235 pub fn get_preferred_address(&self) -> &PreferredAddressConfig {
236 &self.preferred_address
240 pub fn ack_ratio(mut self, ack_ratio: u8) -> Self {
241 self.ack_ratio = ack_ratio;
246 pub fn get_ack_ratio(&self) -> u8 {
252 /// If `timeout` is 2^62 milliseconds or more.
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;
261 pub fn get_idle_timeout(&self) -> Duration {
266 pub fn get_datagram_size(&self) -> u64 {
271 pub fn datagram_size(mut self, v: u64) -> Self {
272 self.datagram_size = v;
277 pub fn get_outgoing_datagram_queue(&self) -> usize {
278 self.outgoing_datagram_queue
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);
289 pub fn get_incoming_datagram_queue(&self) -> usize {
290 self.incoming_datagram_queue
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);
301 pub fn get_fast_pto(&self) -> u8 {
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
319 /// A value of 0 is invalid and will cause a panic.
321 pub fn fast_pto(mut self, scale: u8) -> Self {
322 assert_ne!(scale, 0);
323 self.fast_pto = scale;
328 pub fn is_fuzzing(&self) -> bool {
333 pub fn fuzzing(mut self, enable: bool) -> Self {
334 self.fuzzing = enable;
339 pub fn is_greasing(&self) -> bool {
344 pub fn grease(mut self, grease: bool) -> Self {
345 self.grease = grease;
350 pub fn pacing_enabled(&self) -> bool {
355 pub fn pacing(mut self, pacing: bool) -> Self {
356 self.pacing = pacing;
361 /// When a connection ID cannot be obtained.
363 /// Only when this code includes a transport parameter that is invalid.
364 pub fn create_transport_parameter(
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(),
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(),
381 tps.local.set_integer(
382 tparams::MIN_ACK_DELAY,
383 u64::try_from(GRANULARITY.as_micros()).unwrap(),
386 // set configurable parameters
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,
393 tps.local.set_integer(
394 tparams::INITIAL_MAX_STREAM_DATA_BIDI_REMOTE,
395 self.max_stream_data_bidi_remote,
397 tps.local.set_integer(
398 tparams::INITIAL_MAX_STREAM_DATA_UNI,
399 self.max_stream_data_uni,
402 .set_integer(tparams::INITIAL_MAX_STREAMS_BIDI, self.max_streams_bidi);
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),
409 if let PreferredAddressConfig::Address(preferred) = &self.preferred_address {
410 if role == Role::Server {
411 let (cid, srt) = cid_manager.preferred_address_cid()?;
413 tparams::PREFERRED_ADDRESS,
414 TransportParameter::PreferredAddress {
415 v4: preferred.ipv4(),
416 v6: preferred.ipv6(),
424 .set_integer(tparams::MAX_DATAGRAM_FRAME_SIZE, self.datagram_size);