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::*;
27pub use traits::*;
28
29pub type Version = u32;
30
31// dc versions supported by this code, in order of preference (SUPPORTED_VERSIONS[0] is most preferred)
32pub const SUPPORTED_VERSIONS: [Version; 1] = [0x0];
33
34/// Called on the server to select the dc version to use (if any)
35///
36/// The server's version preference takes precedence
37pub fn select_version(client_supported_versions: DcSupportedVersions) -> Option<Version> {
38    let client_supported_versions = client_supported_versions.into_iter().as_slice();
39    SUPPORTED_VERSIONS
40        .iter()
41        .find(|&supported_version| client_supported_versions.contains(supported_version))
42        .copied()
43}
44
45/// Information about the connection that may be used
46/// when create a new dc path
47#[derive(Clone, Debug)]
48#[non_exhaustive]
49pub struct ConnectionInfo<'a> {
50    /// The address (IP + Port) of the remote peer
51    pub remote_address: SocketAddress<'a>,
52    /// The dc version that has been negotiated
53    pub dc_version: u32,
54    /// Various settings relevant to the dc path
55    pub application_params: ApplicationParams,
56    /// The local endpoint type (client or server)
57    pub endpoint_type: EndpointType,
58}
59
60impl<'a> ConnectionInfo<'a> {
61    #[inline]
62    #[doc(hidden)]
63    pub fn new(
64        remote_address: &'a inet::SocketAddress,
65        dc_version: Version,
66        application_params: ApplicationParams,
67        endpoint_type: EndpointType,
68    ) -> Self {
69        Self {
70            remote_address: remote_address.into_event(),
71            dc_version,
72            application_params,
73            endpoint_type,
74        }
75    }
76}
77
78/// Information about a received datagram that may be used
79/// when parsing it for a secret control packet
80#[derive(Clone, Debug)]
81#[non_exhaustive]
82pub struct DatagramInfo<'a> {
83    /// The address (IP + Port) of the remote peer
84    pub remote_address: SocketAddress<'a>,
85}
86
87impl<'a> DatagramInfo<'a> {
88    #[inline]
89    #[doc(hidden)]
90    pub fn new(remote_address: &'a inet::SocketAddress) -> Self {
91        Self {
92            remote_address: remote_address.into_event(),
93        }
94    }
95}
96
97/// Various settings relevant to the dc path
98#[derive(Debug)]
99#[non_exhaustive]
100pub struct ApplicationParams {
101    pub max_datagram_size: AtomicU16,
102    pub remote_max_data: VarInt,
103    pub local_send_max_data: VarInt,
104    pub local_recv_max_data: VarInt,
105    // Actually a Duration, stored as milliseconds to shrink this struct
106    pub max_idle_timeout: Option<NonZeroU32>,
107}
108
109impl Clone for ApplicationParams {
110    fn clone(&self) -> Self {
111        Self {
112            max_datagram_size: AtomicU16::new(self.max_datagram_size.load(Ordering::Relaxed)),
113            remote_max_data: self.remote_max_data,
114            local_send_max_data: self.local_send_max_data,
115            local_recv_max_data: self.local_recv_max_data,
116            max_idle_timeout: self.max_idle_timeout,
117        }
118    }
119}
120
121impl ApplicationParams {
122    pub fn new(
123        max_datagram_size: u16,
124        peer_flow_control_limits: &InitialFlowControlLimits,
125        limits: &Limits,
126    ) -> Self {
127        Self {
128            max_datagram_size: AtomicU16::new(max_datagram_size),
129            remote_max_data: peer_flow_control_limits.max_data,
130            local_send_max_data: limits.initial_stream_limits().max_data_bidi_local,
131            local_recv_max_data: limits.initial_stream_limits().max_data_bidi_remote,
132            max_idle_timeout: limits
133                .max_idle_timeout()
134                // If > u32::MAX, treat as not having an idle timeout, that's ~50 days.
135                .and_then(|v| v.as_millis().try_into().ok())
136                .and_then(NonZeroU32::new),
137        }
138    }
139
140    pub fn max_idle_timeout(&self) -> Option<Duration> {
141        Some(Duration::from_millis(self.max_idle_timeout?.get() as u64))
142    }
143
144    pub fn max_datagram_size(&self) -> u16 {
145        self.max_datagram_size.load(Ordering::Relaxed)
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use crate::{
152        connection::Limits, dc::ApplicationParams, transport::parameters::InitialFlowControlLimits,
153        varint::VarInt,
154    };
155    use std::{sync::atomic::Ordering, time::Duration};
156
157    #[test]
158    fn clone() {
159        let initial_flow_control_limits = InitialFlowControlLimits {
160            max_data: VarInt::from_u32(2222),
161            ..Default::default()
162        };
163
164        let limits = Limits {
165            bidirectional_local_data_window: 1234.try_into().unwrap(),
166            bidirectional_remote_data_window: 6789.try_into().unwrap(),
167            max_idle_timeout: Duration::from_millis(999).try_into().unwrap(),
168            ..Default::default()
169        };
170
171        let params = ApplicationParams::new(9000, &initial_flow_control_limits, &limits);
172
173        assert_eq!(9000, params.max_datagram_size.load(Ordering::Relaxed));
174        assert_eq!(limits.max_idle_timeout(), params.max_idle_timeout());
175        assert_eq!(1234, params.local_send_max_data.as_u64());
176        assert_eq!(6789, params.local_recv_max_data.as_u64());
177        assert_eq!(2222, params.remote_max_data.as_u64());
178
179        let cloned_params = params.clone();
180
181        assert_eq!(
182            params.max_datagram_size.load(Ordering::Relaxed),
183            cloned_params.max_datagram_size.load(Ordering::Relaxed)
184        );
185        assert_eq!(params.max_idle_timeout, cloned_params.max_idle_timeout);
186        assert_eq!(
187            params.local_send_max_data,
188            cloned_params.local_send_max_data
189        );
190        assert_eq!(
191            params.local_recv_max_data,
192            cloned_params.local_recv_max_data
193        );
194        assert_eq!(params.remote_max_data, cloned_params.remote_max_data);
195    }
196}