libp2p_quic/
config.rs

1// Copyright 2017-2020 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use std::{sync::Arc, time::Duration};
22
23use quinn::{
24    crypto::rustls::{QuicClientConfig, QuicServerConfig},
25    MtuDiscoveryConfig, VarInt,
26};
27
28/// Config for the transport.
29#[derive(Clone)]
30pub struct Config {
31    /// Timeout for the initial handshake when establishing a connection.
32    /// The actual timeout is the minimum of this and the [`Config::max_idle_timeout`].
33    pub handshake_timeout: Duration,
34    /// Maximum duration of inactivity in ms to accept before timing out the connection.
35    pub max_idle_timeout: u32,
36    /// Period of inactivity before sending a keep-alive packet.
37    /// Must be set lower than the idle_timeout of both
38    /// peers to be effective.
39    ///
40    /// See [`quinn::TransportConfig::keep_alive_interval`] for more
41    /// info.
42    pub keep_alive_interval: Duration,
43    /// Maximum number of incoming bidirectional streams that may be open
44    /// concurrently by the remote peer.
45    pub max_concurrent_stream_limit: u32,
46
47    /// Max unacknowledged data in bytes that may be sent on a single stream.
48    pub max_stream_data: u32,
49
50    /// Max unacknowledged data in bytes that may be sent in total on all streams
51    /// of a connection.
52    pub max_connection_data: u32,
53
54    /// Support QUIC version draft-29 for dialing and listening.
55    ///
56    /// Per default only QUIC Version 1 / [`libp2p_core::multiaddr::Protocol::QuicV1`]
57    /// is supported.
58    ///
59    /// If support for draft-29 is enabled servers support draft-29 and version 1 on all
60    /// QUIC listening addresses.
61    /// As client the version is chosen based on the remote's address.
62    pub support_draft_29: bool,
63
64    /// TLS client config for the inner [`quinn::ClientConfig`].
65    client_tls_config: Arc<QuicClientConfig>,
66    /// TLS server config for the inner [`quinn::ServerConfig`].
67    server_tls_config: Arc<QuicServerConfig>,
68    /// Libp2p identity of the node.
69    keypair: libp2p_identity::Keypair,
70
71    /// Parameters governing MTU discovery. See [`MtuDiscoveryConfig`] for details.
72    mtu_discovery_config: Option<MtuDiscoveryConfig>,
73}
74
75impl Config {
76    /// Creates a new configuration object with default values.
77    pub fn new(keypair: &libp2p_identity::Keypair) -> Self {
78        let client_tls_config = Arc::new(
79            QuicClientConfig::try_from(libp2p_tls::make_client_config(keypair, None).unwrap())
80                .unwrap(),
81        );
82        let server_tls_config = Arc::new(
83            QuicServerConfig::try_from(libp2p_tls::make_server_config(keypair).unwrap()).unwrap(),
84        );
85        Self {
86            client_tls_config,
87            server_tls_config,
88            support_draft_29: false,
89            handshake_timeout: Duration::from_secs(5),
90            max_idle_timeout: 10 * 1000,
91            max_concurrent_stream_limit: 256,
92            keep_alive_interval: Duration::from_secs(5),
93            max_connection_data: 15_000_000,
94
95            // Ensure that one stream is not consuming the whole connection.
96            max_stream_data: 10_000_000,
97            keypair: keypair.clone(),
98            mtu_discovery_config: Some(Default::default()),
99        }
100    }
101
102    /// Set the upper bound to the max UDP payload size that MTU discovery will search for.
103    pub fn mtu_upper_bound(mut self, value: u16) -> Self {
104        self.mtu_discovery_config
105            .get_or_insert_with(Default::default)
106            .upper_bound(value);
107        self
108    }
109
110    /// Disable MTU path discovery (it is enabled by default).
111    pub fn disable_path_mtu_discovery(mut self) -> Self {
112        self.mtu_discovery_config = None;
113        self
114    }
115}
116
117/// Represents the inner configuration for [`quinn`].
118#[derive(Debug, Clone)]
119pub(crate) struct QuinnConfig {
120    pub(crate) client_config: quinn::ClientConfig,
121    pub(crate) server_config: quinn::ServerConfig,
122    pub(crate) endpoint_config: quinn::EndpointConfig,
123}
124
125impl From<Config> for QuinnConfig {
126    fn from(config: Config) -> QuinnConfig {
127        let Config {
128            client_tls_config,
129            server_tls_config,
130            max_idle_timeout,
131            max_concurrent_stream_limit,
132            keep_alive_interval,
133            max_connection_data,
134            max_stream_data,
135            support_draft_29,
136            handshake_timeout: _,
137            keypair,
138            mtu_discovery_config,
139        } = config;
140        let mut transport = quinn::TransportConfig::default();
141        // Disable uni-directional streams.
142        transport.max_concurrent_uni_streams(0u32.into());
143        transport.max_concurrent_bidi_streams(max_concurrent_stream_limit.into());
144        // Disable datagrams.
145        transport.datagram_receive_buffer_size(None);
146        transport.keep_alive_interval(Some(keep_alive_interval));
147        transport.max_idle_timeout(Some(VarInt::from_u32(max_idle_timeout).into()));
148        transport.allow_spin(false);
149        transport.stream_receive_window(max_stream_data.into());
150        transport.receive_window(max_connection_data.into());
151        transport.mtu_discovery_config(mtu_discovery_config);
152        let transport = Arc::new(transport);
153
154        let mut server_config = quinn::ServerConfig::with_crypto(server_tls_config);
155        server_config.transport = Arc::clone(&transport);
156        // Disables connection migration.
157        // Long-term this should be enabled, however we then need to handle address change
158        // on connections in the `Connection`.
159        server_config.migration(false);
160
161        let mut client_config = quinn::ClientConfig::new(client_tls_config);
162        client_config.transport_config(transport);
163
164        let mut endpoint_config = keypair
165            .derive_secret(b"libp2p quic stateless reset key")
166            .map(|secret| {
167                let reset_key = Arc::new(ring::hmac::Key::new(ring::hmac::HMAC_SHA256, &secret));
168                quinn::EndpointConfig::new(reset_key)
169            })
170            .unwrap_or_default();
171
172        if !support_draft_29 {
173            endpoint_config.supported_versions(vec![1]);
174        }
175
176        QuinnConfig {
177            client_config,
178            server_config,
179            endpoint_config,
180        }
181    }
182}