s2n_quic_core/connection/
limits.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3#[cfg(feature = "alloc")]
4use crate::application::ServerName;
5use crate::{
6    ack,
7    event::{api::SocketAddress, IntoEvent},
8    inet, recovery, stream,
9    transport::parameters::{
10        AckDelayExponent, ActiveConnectionIdLimit, InitialFlowControlLimits, InitialMaxData,
11        InitialMaxStreamDataBidiLocal, InitialMaxStreamDataBidiRemote, InitialMaxStreamDataUni,
12        InitialMaxStreamsBidi, InitialMaxStreamsUni, InitialStreamLimits, MaxAckDelay,
13        MaxDatagramFrameSize, MaxIdleTimeout, MigrationSupport, TransportParameters,
14    },
15};
16#[cfg(feature = "alloc")]
17use bytes::Bytes;
18use core::time::Duration;
19use s2n_codec::decoder_invariant;
20
21pub use crate::transport::parameters::ValidationError;
22
23const MAX_HANDSHAKE_DURATION_DEFAULT: Duration = Duration::from_secs(10);
24
25//= https://www.rfc-editor.org/rfc/rfc9000#section-10.1.2
26//# A connection will time out if no packets are sent or received for a
27//# period longer than the time negotiated using the max_idle_timeout
28//# transport parameter; see Section 10.  However, state in middleboxes
29//# might time out earlier than that.  Though REQ-5 in [RFC4787]
30//# recommends a 2-minute timeout interval, experience shows that sending
31//# packets every 30 seconds is necessary to prevent the majority of
32//# middleboxes from losing state for UDP flows [GATEWAY].
33const MAX_KEEP_ALIVE_PERIOD_DEFAULT: Duration = Duration::from_secs(30);
34
35//= https://www.rfc-editor.org/rfc/rfc9000#section-8.1
36//# Prior to validating the client address, servers MUST NOT send more
37//# than three times as many bytes as the number of bytes they have
38//# received.
39pub const ANTI_AMPLIFICATION_MULTIPLIER: u8 = 3;
40
41pub const DEFAULT_STREAM_BATCH_SIZE: u8 = 1;
42
43#[non_exhaustive]
44#[derive(Debug)]
45pub struct ConnectionInfo<'a> {
46    pub remote_address: SocketAddress<'a>,
47}
48
49impl<'a> ConnectionInfo<'a> {
50    #[inline]
51    #[doc(hidden)]
52    pub fn new(remote_address: &'a inet::SocketAddress) -> Self {
53        Self {
54            remote_address: remote_address.into_event(),
55        }
56    }
57}
58
59#[non_exhaustive]
60#[derive(Debug)]
61#[cfg(feature = "alloc")]
62pub struct HandshakeInfo<'a> {
63    pub remote_address: SocketAddress<'a>,
64    pub server_name: Option<&'a ServerName>,
65    pub application_protocol: &'a Bytes,
66}
67
68#[cfg(feature = "alloc")]
69impl<'a> HandshakeInfo<'a> {
70    pub fn new(
71        remote_address: &'a inet::SocketAddress,
72        server_name: Option<&'a ServerName>,
73        application_protocol: &'a Bytes,
74    ) -> HandshakeInfo<'a> {
75        Self {
76            remote_address: remote_address.into_event(),
77            server_name,
78            application_protocol,
79        }
80    }
81}
82
83#[derive(Clone, Copy, Debug)]
84pub struct Limits {
85    pub(crate) max_idle_timeout: MaxIdleTimeout,
86    pub(crate) data_window: InitialMaxData,
87    pub(crate) bidirectional_local_data_window: InitialMaxStreamDataBidiLocal,
88    pub(crate) bidirectional_remote_data_window: InitialMaxStreamDataBidiRemote,
89    pub(crate) unidirectional_data_window: InitialMaxStreamDataUni,
90    pub(crate) max_open_local_bidirectional_streams: stream::limits::LocalBidirectional,
91    pub(crate) max_open_local_unidirectional_streams: stream::limits::LocalUnidirectional,
92    pub(crate) max_open_remote_bidirectional_streams: InitialMaxStreamsBidi,
93    pub(crate) max_open_remote_unidirectional_streams: InitialMaxStreamsUni,
94    pub(crate) max_ack_delay: MaxAckDelay,
95    pub(crate) ack_delay_exponent: AckDelayExponent,
96    pub(crate) max_active_connection_ids: ActiveConnectionIdLimit,
97    pub(crate) ack_elicitation_interval: u8,
98    pub(crate) ack_ranges_limit: u8,
99    pub(crate) max_send_buffer_size: stream::limits::MaxSendBufferSize,
100    pub(crate) max_handshake_duration: Duration,
101    pub(crate) max_keep_alive_period: Duration,
102    pub(crate) max_datagram_frame_size: MaxDatagramFrameSize,
103    pub(crate) initial_round_trip_time: Duration,
104    pub(crate) migration_support: MigrationSupport,
105    pub(crate) anti_amplification_multiplier: u8,
106    pub(crate) stream_batch_size: u8,
107}
108
109impl Default for Limits {
110    fn default() -> Self {
111        Self::new()
112    }
113}
114
115macro_rules! setter {
116    ($(#[doc = $doc:literal])* $name:ident, $field:ident, $inner:ty $(, |$validate_value:ident| $validation:block)?) => {
117        $(#[doc = $doc])*
118        pub fn $name(mut self, value: $inner) -> Result<Self, ValidationError> {
119            $(
120                let $validate_value = value;
121                $validation
122            )?
123            self.$field = value.try_into()?;
124            Ok(self)
125        }
126    };
127}
128
129impl Limits {
130    pub const fn new() -> Self {
131        Self {
132            max_idle_timeout: MaxIdleTimeout::RECOMMENDED,
133            data_window: InitialMaxData::RECOMMENDED,
134            bidirectional_local_data_window: InitialMaxStreamDataBidiLocal::RECOMMENDED,
135            bidirectional_remote_data_window: InitialMaxStreamDataBidiRemote::RECOMMENDED,
136            unidirectional_data_window: InitialMaxStreamDataUni::RECOMMENDED,
137            max_open_local_bidirectional_streams: stream::limits::LocalBidirectional::RECOMMENDED,
138            max_open_local_unidirectional_streams: stream::limits::LocalUnidirectional::RECOMMENDED,
139            max_open_remote_bidirectional_streams: InitialMaxStreamsBidi::RECOMMENDED,
140            max_open_remote_unidirectional_streams: InitialMaxStreamsUni::RECOMMENDED,
141            max_ack_delay: MaxAckDelay::RECOMMENDED,
142            ack_delay_exponent: AckDelayExponent::RECOMMENDED,
143            max_active_connection_ids: ActiveConnectionIdLimit::RECOMMENDED,
144            ack_elicitation_interval: ack::Settings::RECOMMENDED.ack_elicitation_interval,
145            ack_ranges_limit: ack::Settings::RECOMMENDED.ack_ranges_limit,
146            max_send_buffer_size: stream::Limits::RECOMMENDED.max_send_buffer_size,
147            max_handshake_duration: MAX_HANDSHAKE_DURATION_DEFAULT,
148            max_keep_alive_period: MAX_KEEP_ALIVE_PERIOD_DEFAULT,
149            max_datagram_frame_size: MaxDatagramFrameSize::DEFAULT,
150            initial_round_trip_time: recovery::DEFAULT_INITIAL_RTT,
151            migration_support: MigrationSupport::RECOMMENDED,
152            anti_amplification_multiplier: ANTI_AMPLIFICATION_MULTIPLIER,
153            stream_batch_size: DEFAULT_STREAM_BATCH_SIZE,
154        }
155    }
156
157    // We limit the initial data limit to u32::MAX (4GB), which far
158    // exceeds the reasonable amount of data a connection is
159    // initially allowed to send.
160    //
161    // By representing the flow control value as a u32, we save space
162    // on the connection state.
163    setter!(with_data_window, data_window, u64, |validate_value| {
164        decoder_invariant!(
165            validate_value <= u32::MAX.into(),
166            "data_window must be <= u32::MAX"
167        );
168    });
169    setter!(
170        with_bidirectional_local_data_window,
171        bidirectional_local_data_window,
172        u64,
173        |validate_value| {
174            decoder_invariant!(
175                validate_value <= u32::MAX.into(),
176                "bidirectional_local_data_window must be <= u32::MAX"
177            );
178        }
179    );
180    setter!(
181        with_bidirectional_remote_data_window,
182        bidirectional_remote_data_window,
183        u64,
184        |validate_value| {
185            decoder_invariant!(
186                validate_value <= u32::MAX.into(),
187                "bidirectional_remote_data_window must be <= u32::MAX"
188            );
189        }
190    );
191    setter!(
192        with_unidirectional_data_window,
193        unidirectional_data_window,
194        u64,
195        |validate_value| {
196            decoder_invariant!(
197                validate_value <= u32::MAX.into(),
198                "unidirectional_data_window must be <= u32::MAX"
199            );
200        }
201    );
202
203    setter!(with_max_idle_timeout, max_idle_timeout, Duration);
204
205    /// Sets both the max local and remote limits for bidirectional streams.
206    #[deprecated(
207        note = "use with_max_open_local_bidirectional_streams and with_max_open_remote_bidirectional_streams instead"
208    )]
209    pub fn with_max_open_bidirectional_streams(
210        mut self,
211        value: u64,
212    ) -> Result<Self, ValidationError> {
213        self.max_open_local_bidirectional_streams = value.try_into()?;
214        self.max_open_remote_bidirectional_streams = value.try_into()?;
215        Ok(self)
216    }
217
218    /// Sets the max local limits for bidirectional streams
219    ///
220    /// The value set is used instead of `with_max_open_bidirectional_streams` when set.
221    pub fn with_max_open_local_bidirectional_streams(
222        mut self,
223        value: u64,
224    ) -> Result<Self, ValidationError> {
225        self.max_open_local_bidirectional_streams = value.try_into()?;
226        Ok(self)
227    }
228
229    /// Sets the max remote limits for bidirectional streams.
230    ///
231    /// The value set is used instead of `with_max_open_bidirectional_streams` when set.
232    pub fn with_max_open_remote_bidirectional_streams(
233        mut self,
234        value: u64,
235    ) -> Result<Self, ValidationError> {
236        self.max_open_remote_bidirectional_streams = value.try_into()?;
237        Ok(self)
238    }
239
240    setter!(
241        with_max_open_local_unidirectional_streams,
242        max_open_local_unidirectional_streams,
243        u64
244    );
245    setter!(
246        with_max_open_remote_unidirectional_streams,
247        max_open_remote_unidirectional_streams,
248        u64
249    );
250    setter!(with_max_ack_delay, max_ack_delay, Duration);
251    setter!(
252        with_max_active_connection_ids,
253        max_active_connection_ids,
254        u64
255    );
256    setter!(with_stream_batch_size, stream_batch_size, u8);
257    setter!(with_ack_elicitation_interval, ack_elicitation_interval, u8);
258    setter!(with_max_ack_ranges, ack_ranges_limit, u8);
259    setter!(
260        /// Sets the maximum send buffer size for a Stream
261        ///
262        /// The send buffer contains unacknowledged application data. Constraining the maximum
263        /// size of this buffer limits the amount of memory a given Stream may consume. On
264        /// high bandwidth/high RTT connections this may act as a bottleneck, as the connection may be
265        /// waiting for data to be acknowledged by the peer before allowing more data to be sent.
266        /// Increasing this value should be carefully weighed against the potential downsides
267        /// of additional memory utilization as well as increased latency due to the capacity of the
268        /// send buffer exceeding the rate at which the network link and peer are able to drain from it.
269        /// Ideally, the max_send_buffer_size is configured to the minimum value that can support the
270        /// throughput requirements for the connection.
271        with_max_send_buffer_size,
272        max_send_buffer_size,
273        u32
274    );
275    setter!(
276        with_max_handshake_duration,
277        max_handshake_duration,
278        Duration
279    );
280    setter!(with_max_keep_alive_period, max_keep_alive_period, Duration);
281    /// Sets whether active connection migration is supported for a server endpoint (default: true)
282    ///
283    /// If set to false, the `disable_active_migration` transport parameter will be sent to the
284    /// peer, and any attempt by the peer to perform an active connection migration will be ignored.
285    pub fn with_active_connection_migration(
286        mut self,
287        enabled: bool,
288    ) -> Result<Self, ValidationError> {
289        if enabled {
290            self.migration_support = MigrationSupport::Enabled
291        } else {
292            self.migration_support = MigrationSupport::Disabled
293        }
294        Ok(self)
295    }
296
297    /// Sets the initial round trip time (RTT) for use in recovery mechanisms prior to
298    /// measuring an actual RTT sample.
299    ///
300    /// This is useful for environments where RTTs are mostly predictable (e.g. data centers)
301    /// and are much lower than the default 333 milliseconds.
302    pub fn with_initial_round_trip_time(
303        mut self,
304        value: Duration,
305    ) -> Result<Self, ValidationError> {
306        ensure!(
307            value >= recovery::MIN_RTT,
308            Err(ValidationError(
309                "provided value must be at least 1 microsecond",
310            ))
311        );
312
313        self.initial_round_trip_time = value;
314        Ok(self)
315    }
316
317    #[cfg(feature = "unstable-limits")]
318    setter!(
319        /// Limit how many bytes the Server sends prior to address validation (default: 3)
320        ///
321        /// Prior to validating the client address, servers will not send more
322        /// than `anti_amplification_multiplier` times as many bytes as the
323        /// number of bytes it has received.
324        with_anti_amplification_multiplier,
325        anti_amplification_multiplier,
326        u8
327    );
328
329    // internal APIs
330
331    #[doc(hidden)]
332    #[inline]
333    pub fn load_peer<A, B, C, D>(&mut self, peer_parameters: &TransportParameters<A, B, C, D>) {
334        self.max_idle_timeout
335            .load_peer(&peer_parameters.max_idle_timeout);
336    }
337
338    #[doc(hidden)]
339    #[inline]
340    pub const fn ack_settings(&self) -> ack::Settings {
341        ack::Settings {
342            ack_delay_exponent: self.ack_delay_exponent.as_u8(),
343            max_ack_delay: self.max_ack_delay.as_duration(),
344            ack_ranges_limit: self.ack_ranges_limit,
345            ack_elicitation_interval: self.ack_elicitation_interval,
346        }
347    }
348
349    #[doc(hidden)]
350    #[inline]
351    pub const fn initial_flow_control_limits(&self) -> InitialFlowControlLimits {
352        InitialFlowControlLimits {
353            stream_limits: self.initial_stream_limits(),
354            max_data: self.data_window.as_varint(),
355            max_open_remote_bidirectional_streams: self
356                .max_open_remote_bidirectional_streams
357                .as_varint(),
358            max_open_remote_unidirectional_streams: self
359                .max_open_remote_unidirectional_streams
360                .as_varint(),
361        }
362    }
363
364    #[doc(hidden)]
365    #[inline]
366    pub const fn initial_stream_limits(&self) -> InitialStreamLimits {
367        InitialStreamLimits {
368            max_data_bidi_local: self.bidirectional_local_data_window.as_varint(),
369            max_data_bidi_remote: self.bidirectional_remote_data_window.as_varint(),
370            max_data_uni: self.unidirectional_data_window.as_varint(),
371        }
372    }
373
374    #[doc(hidden)]
375    #[inline]
376    pub fn stream_limits(&self) -> stream::Limits {
377        stream::Limits {
378            max_send_buffer_size: self.max_send_buffer_size,
379            max_open_local_unidirectional_streams: self.max_open_local_unidirectional_streams,
380            max_open_local_bidirectional_streams: self.max_open_local_bidirectional_streams,
381        }
382    }
383
384    #[doc(hidden)]
385    #[inline]
386    pub fn max_idle_timeout(&self) -> Option<Duration> {
387        self.max_idle_timeout.as_duration()
388    }
389
390    #[doc(hidden)]
391    #[inline]
392    pub fn max_handshake_duration(&self) -> Duration {
393        self.max_handshake_duration
394    }
395
396    #[doc(hidden)]
397    #[inline]
398    pub fn max_keep_alive_period(&self) -> Duration {
399        self.max_keep_alive_period
400    }
401
402    #[doc(hidden)]
403    #[inline]
404    pub fn initial_round_trip_time(&self) -> Duration {
405        self.initial_round_trip_time
406    }
407
408    #[doc(hidden)]
409    #[inline]
410    pub fn active_migration_enabled(&self) -> bool {
411        matches!(self.migration_support, MigrationSupport::Enabled)
412    }
413
414    #[doc(hidden)]
415    #[inline]
416    pub fn anti_amplification_multiplier(&self) -> u8 {
417        self.anti_amplification_multiplier
418    }
419
420    #[doc(hidden)]
421    #[inline]
422    pub fn stream_batch_size(&self) -> u8 {
423        self.stream_batch_size
424    }
425}
426
427#[must_use]
428#[derive(Debug)]
429pub struct UpdatableLimits<'a>(&'a mut Limits);
430
431impl<'a> UpdatableLimits<'a> {
432    pub fn new(limits: &'a mut Limits) -> UpdatableLimits<'a> {
433        UpdatableLimits(limits)
434    }
435
436    pub fn with_stream_batch_size(&mut self, size: u8) {
437        self.0.stream_batch_size = size;
438    }
439}
440
441/// Creates limits for a given connection
442pub trait Limiter: 'static + Send {
443    fn on_connection(&mut self, info: &ConnectionInfo) -> Limits;
444
445    /// Provides another opportunity to change connection limits with information
446    /// from the handshake
447    #[inline]
448    #[cfg(feature = "alloc")]
449    fn on_post_handshake(&mut self, info: &HandshakeInfo, limits: &mut UpdatableLimits) {
450        let _ = info;
451        let _ = limits;
452    }
453}
454
455/// Implement Limiter for a Limits struct
456impl Limiter for Limits {
457    fn on_connection(&mut self, _into: &ConnectionInfo) -> Limits {
458        *self
459    }
460    #[cfg(feature = "alloc")]
461    fn on_post_handshake(&mut self, _info: &HandshakeInfo, _limits: &mut UpdatableLimits) {}
462}
463
464#[cfg(test)]
465mod tests {
466    use super::*;
467
468    // Local max data limits should be <= u32::MAX
469    #[test]
470    fn limit_validation() {
471        let mut data = u32::MAX as u64 + 1;
472        let limits = Limits::default();
473        assert!(limits.with_data_window(data).is_err());
474        assert!(limits.with_bidirectional_local_data_window(data).is_err());
475        assert!(limits.with_bidirectional_remote_data_window(data).is_err());
476        assert!(limits.with_unidirectional_data_window(data).is_err());
477
478        data = u32::MAX as u64;
479        assert!(limits.with_data_window(data).is_ok());
480        assert!(limits.with_bidirectional_local_data_window(data).is_ok());
481        assert!(limits.with_bidirectional_remote_data_window(data).is_ok());
482        assert!(limits.with_unidirectional_data_window(data).is_ok());
483    }
484
485    // Limits can be updated through the UpdatableLimits wrapper
486    #[test]
487    fn updatable_limits() {
488        let mut limits = Limits::default();
489        assert_eq!(limits.stream_batch_size, 1);
490        let mut updatable_limits = UpdatableLimits::new(&mut limits);
491        let new_size = 10;
492        updatable_limits.with_stream_batch_size(new_size);
493        assert_eq!(limits.stream_batch_size, new_size);
494    }
495}