s2n_quic_core/
dc.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    connection::Limits,
6    event::{
7        api::{EndpointType, SocketAddress},
8        IntoEvent as _,
9    },
10    inet,
11    transport::parameters::{DcSupportedVersions, InitialFlowControlLimits},
12    varint::VarInt,
13};
14use core::{
15    num::NonZeroU32,
16    sync::atomic::{AtomicU16, Ordering},
17    time::Duration,
18};
19
20mod disabled;
21mod traits;
22
23#[cfg(any(test, feature = "testing"))]
24pub mod testing;
25
26pub use disabled::*;
27use s2n_codec::{decoder_value, DecoderError, Encoder, EncoderValue};
28pub use traits::*;
29
30pub type Version = u32;
31
32// dc versions supported by this code, in order of preference (SUPPORTED_VERSIONS[0] is most preferred)
33pub const SUPPORTED_VERSIONS: [Version; 1] = [0x0];
34
35/// Called on the server to select the dc version to use (if any)
36///
37/// The server's version preference takes precedence
38pub fn select_version(client_supported_versions: DcSupportedVersions) -> Option<Version> {
39    let client_supported_versions = client_supported_versions.into_iter().as_slice();
40    SUPPORTED_VERSIONS
41        .iter()
42        .find(|&supported_version| client_supported_versions.contains(supported_version))
43        .copied()
44}
45
46/// Information about the connection that may be used
47/// when create a new dc path
48#[derive(Clone, Debug)]
49#[non_exhaustive]
50pub struct ConnectionInfo<'a> {
51    /// The address (IP + Port) of the remote peer
52    pub remote_address: SocketAddress<'a>,
53    /// The dc version that has been negotiated
54    pub dc_version: u32,
55    /// Various settings relevant to the dc path
56    pub application_params: ApplicationParams,
57    /// The local endpoint type (client or server)
58    pub endpoint_type: EndpointType,
59}
60
61impl<'a> ConnectionInfo<'a> {
62    #[inline]
63    #[doc(hidden)]
64    pub fn new(
65        remote_address: &'a inet::SocketAddress,
66        dc_version: Version,
67        application_params: ApplicationParams,
68        endpoint_type: EndpointType,
69    ) -> Self {
70        Self {
71            remote_address: remote_address.into_event(),
72            dc_version,
73            application_params,
74            endpoint_type,
75        }
76    }
77}
78
79/// Information about a received datagram that may be used
80/// when parsing it for a secret control packet
81#[derive(Clone, Debug)]
82#[non_exhaustive]
83pub struct DatagramInfo<'a> {
84    /// The address (IP + Port) of the remote peer
85    pub remote_address: SocketAddress<'a>,
86}
87
88impl<'a> DatagramInfo<'a> {
89    #[inline]
90    #[doc(hidden)]
91    pub fn new(remote_address: &'a inet::SocketAddress) -> Self {
92        Self {
93            remote_address: remote_address.into_event(),
94        }
95    }
96}
97
98/// Various settings relevant to the dc path
99#[derive(Debug)]
100#[non_exhaustive]
101pub struct ApplicationParams {
102    pub max_datagram_size: AtomicU16,
103    pub remote_max_data: VarInt,
104    pub local_send_max_data: VarInt,
105    pub local_recv_max_data: VarInt,
106    // Actually a Duration, stored as milliseconds to shrink this struct
107    pub max_idle_timeout: Option<NonZeroU32>,
108}
109
110impl Clone for ApplicationParams {
111    fn clone(&self) -> Self {
112        Self {
113            max_datagram_size: AtomicU16::new(self.max_datagram_size.load(Ordering::Relaxed)),
114            remote_max_data: self.remote_max_data,
115            local_send_max_data: self.local_send_max_data,
116            local_recv_max_data: self.local_recv_max_data,
117            max_idle_timeout: self.max_idle_timeout,
118        }
119    }
120}
121
122impl ApplicationParams {
123    pub fn new(
124        max_datagram_size: u16,
125        peer_flow_control_limits: &InitialFlowControlLimits,
126        limits: &Limits,
127    ) -> Self {
128        Self {
129            max_datagram_size: AtomicU16::new(max_datagram_size),
130            remote_max_data: peer_flow_control_limits.max_data,
131            local_send_max_data: limits.initial_stream_limits().max_data_bidi_local,
132            local_recv_max_data: limits.initial_stream_limits().max_data_bidi_remote,
133            max_idle_timeout: limits
134                .max_idle_timeout()
135                // If > u32::MAX, treat as not having an idle timeout, that's ~50 days.
136                .and_then(|v| v.as_millis().try_into().ok())
137                .and_then(NonZeroU32::new),
138        }
139    }
140
141    pub fn max_idle_timeout(&self) -> Option<Duration> {
142        Some(Duration::from_millis(self.max_idle_timeout?.get() as u64))
143    }
144
145    pub fn max_datagram_size(&self) -> u16 {
146        self.max_datagram_size.load(Ordering::Relaxed)
147    }
148}
149
150decoder_value!(
151    impl<'a> ApplicationParams {
152        fn decode(buffer: Buffer) -> Result<Self> {
153            let (max_datagram_size, buffer) = buffer.decode::<u16>()?;
154            let (remote_max_data, buffer) = buffer.decode::<VarInt>()?;
155            let (local_send_max_data, buffer) = buffer.decode::<VarInt>()?;
156            let (local_recv_max_data, buffer) = buffer.decode::<VarInt>()?;
157
158            let (timeout_value, buffer) = buffer.decode::<VarInt>()?;
159            let timeout_value: u32 = timeout_value.try_into().map_err(|_| {
160                DecoderError::InvariantViolation("Timeout value exceeds u32 maximum")
161            })?;
162            let max_idle_timeout = NonZeroU32::new(timeout_value);
163
164            Ok((
165                Self {
166                    max_datagram_size: AtomicU16::new(max_datagram_size),
167                    remote_max_data,
168                    local_send_max_data,
169                    local_recv_max_data,
170                    max_idle_timeout,
171                },
172                buffer,
173            ))
174        }
175    }
176);
177
178impl EncoderValue for ApplicationParams {
179    fn encode<E: Encoder>(&self, buffer: &mut E) {
180        buffer.encode(&self.max_datagram_size.load(Ordering::Relaxed));
181        buffer.encode(&self.remote_max_data);
182        buffer.encode(&self.local_send_max_data);
183        buffer.encode(&self.local_recv_max_data);
184
185        match self.max_idle_timeout {
186            Some(timeout) => {
187                buffer.encode(&VarInt::from(u32::from(timeout)));
188            }
189            None => {
190                buffer.encode(&VarInt::from(0u32));
191            }
192        }
193    }
194}
195
196#[cfg(test)]
197mod tests {
198    use crate::{
199        connection::Limits, dc::ApplicationParams, transport::parameters::InitialFlowControlLimits,
200        varint::VarInt,
201    };
202    use std::{sync::atomic::Ordering, time::Duration};
203
204    #[test]
205    fn clone() {
206        let initial_flow_control_limits = InitialFlowControlLimits {
207            max_data: VarInt::from_u32(2222),
208            ..Default::default()
209        };
210
211        let limits = Limits {
212            bidirectional_local_data_window: 1234.try_into().unwrap(),
213            bidirectional_remote_data_window: 6789.try_into().unwrap(),
214            max_idle_timeout: Duration::from_millis(999).try_into().unwrap(),
215            ..Default::default()
216        };
217
218        let params = ApplicationParams::new(9000, &initial_flow_control_limits, &limits);
219
220        assert_eq!(9000, params.max_datagram_size.load(Ordering::Relaxed));
221        assert_eq!(limits.max_idle_timeout(), params.max_idle_timeout());
222        assert_eq!(1234, params.local_send_max_data.as_u64());
223        assert_eq!(6789, params.local_recv_max_data.as_u64());
224        assert_eq!(2222, params.remote_max_data.as_u64());
225
226        let cloned_params = params.clone();
227
228        assert_eq!(
229            params.max_datagram_size.load(Ordering::Relaxed),
230            cloned_params.max_datagram_size.load(Ordering::Relaxed)
231        );
232        assert_eq!(params.max_idle_timeout, cloned_params.max_idle_timeout);
233        assert_eq!(
234            params.local_send_max_data,
235            cloned_params.local_send_max_data
236        );
237        assert_eq!(
238            params.local_recv_max_data,
239            cloned_params.local_recv_max_data
240        );
241        assert_eq!(params.remote_max_data, cloned_params.remote_max_data);
242    }
243}