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 #[deprecated(note = "QUIC draft versions are no longer supported")]
63 pub support_draft_29: bool,
64
65 /// TLS client config for the inner [`quinn::ClientConfig`].
66 client_tls_config: Arc<QuicClientConfig>,
67 /// TLS server config for the inner [`quinn::ServerConfig`].
68 server_tls_config: Arc<QuicServerConfig>,
69 /// Libp2p identity of the node.
70 keypair: libp2p_identity::Keypair,
71
72 /// Parameters governing MTU discovery. See [`MtuDiscoveryConfig`] for details.
73 mtu_discovery_config: Option<MtuDiscoveryConfig>,
74}
75
76#[expect(deprecated)]
77impl Config {
78 /// Creates a new configuration object with default values.
79 pub fn new(keypair: &libp2p_identity::Keypair) -> Self {
80 let client_tls_config = Arc::new(
81 QuicClientConfig::try_from(libp2p_tls::make_client_config(keypair, None).unwrap())
82 .unwrap(),
83 );
84 let server_tls_config = Arc::new(
85 QuicServerConfig::try_from(libp2p_tls::make_server_config(keypair).unwrap()).unwrap(),
86 );
87 Self {
88 client_tls_config,
89 server_tls_config,
90 support_draft_29: false,
91 handshake_timeout: Duration::from_secs(5),
92 max_idle_timeout: 10 * 1000,
93 max_concurrent_stream_limit: 256,
94 keep_alive_interval: Duration::from_secs(5),
95 max_connection_data: 15_000_000,
96
97 // Ensure that one stream is not consuming the whole connection.
98 max_stream_data: 10_000_000,
99 keypair: keypair.clone(),
100 mtu_discovery_config: Some(Default::default()),
101 }
102 }
103
104 /// Set the upper bound to the max UDP payload size that MTU discovery will search for.
105 pub fn mtu_upper_bound(mut self, value: u16) -> Self {
106 self.mtu_discovery_config
107 .get_or_insert_with(Default::default)
108 .upper_bound(value);
109 self
110 }
111
112 /// Disable MTU path discovery (it is enabled by default).
113 pub fn disable_path_mtu_discovery(mut self) -> Self {
114 self.mtu_discovery_config = None;
115 self
116 }
117}
118
119/// Represents the inner configuration for [`quinn`].
120#[derive(Debug, Clone)]
121pub(crate) struct QuinnConfig {
122 pub(crate) client_config: quinn::ClientConfig,
123 pub(crate) server_config: quinn::ServerConfig,
124 pub(crate) endpoint_config: quinn::EndpointConfig,
125}
126
127#[expect(deprecated)]
128impl From<Config> for QuinnConfig {
129 fn from(config: Config) -> QuinnConfig {
130 let Config {
131 client_tls_config,
132 server_tls_config,
133 max_idle_timeout,
134 max_concurrent_stream_limit,
135 keep_alive_interval,
136 max_connection_data,
137 max_stream_data,
138 support_draft_29,
139 handshake_timeout: _,
140 keypair,
141 mtu_discovery_config,
142 } = config;
143 let mut transport = quinn::TransportConfig::default();
144 // Disable uni-directional streams.
145 transport.max_concurrent_uni_streams(0u32.into());
146 transport.max_concurrent_bidi_streams(max_concurrent_stream_limit.into());
147 // Disable datagrams.
148 transport.datagram_receive_buffer_size(None);
149 transport.keep_alive_interval(Some(keep_alive_interval));
150 transport.max_idle_timeout(Some(VarInt::from_u32(max_idle_timeout).into()));
151 transport.allow_spin(false);
152 transport.stream_receive_window(max_stream_data.into());
153 transport.receive_window(max_connection_data.into());
154 transport.mtu_discovery_config(mtu_discovery_config);
155 let transport = Arc::new(transport);
156
157 let mut server_config = quinn::ServerConfig::with_crypto(server_tls_config);
158 server_config.transport = Arc::clone(&transport);
159 // Disables connection migration.
160 // Long-term this should be enabled, however we then need to handle address change
161 // on connections in the `Connection`.
162 server_config.migration(false);
163
164 let mut client_config = quinn::ClientConfig::new(client_tls_config);
165 client_config.transport_config(transport);
166
167 let mut endpoint_config = keypair
168 .derive_secret(b"libp2p quic stateless reset key")
169 .map(|secret| {
170 let reset_key = Arc::new(ring::hmac::Key::new(ring::hmac::HMAC_SHA256, &secret));
171 quinn::EndpointConfig::new(reset_key)
172 })
173 .unwrap_or_default();
174
175 if !support_draft_29 {
176 endpoint_config.supported_versions(vec![1]);
177 }
178
179 QuinnConfig {
180 client_config,
181 server_config,
182 endpoint_config,
183 }
184 }
185}