use std::{sync::Arc, time::Duration};
use quinn::{
crypto::rustls::{QuicClientConfig, QuicServerConfig},
MtuDiscoveryConfig, VarInt,
};
#[derive(Clone)]
pub struct Config {
pub handshake_timeout: Duration,
pub max_idle_timeout: u32,
pub keep_alive_interval: Duration,
pub max_concurrent_stream_limit: u32,
pub max_stream_data: u32,
pub max_connection_data: u32,
#[deprecated(note = "QUIC draft versions are no longer supported")]
pub support_draft_29: bool,
client_tls_config: Arc<QuicClientConfig>,
server_tls_config: Arc<QuicServerConfig>,
keypair: libp2p_identity::Keypair,
mtu_discovery_config: Option<MtuDiscoveryConfig>,
}
#[expect(deprecated)]
impl Config {
pub fn new(keypair: &libp2p_identity::Keypair) -> Self {
let client_tls_config = Arc::new(
QuicClientConfig::try_from(libp2p_tls::make_client_config(keypair, None).unwrap())
.unwrap(),
);
let server_tls_config = Arc::new(
QuicServerConfig::try_from(libp2p_tls::make_server_config(keypair).unwrap()).unwrap(),
);
Self {
client_tls_config,
server_tls_config,
support_draft_29: false,
handshake_timeout: Duration::from_secs(5),
max_idle_timeout: 10 * 1000,
max_concurrent_stream_limit: 256,
keep_alive_interval: Duration::from_secs(5),
max_connection_data: 15_000_000,
max_stream_data: 10_000_000,
keypair: keypair.clone(),
mtu_discovery_config: Some(Default::default()),
}
}
pub fn mtu_upper_bound(mut self, value: u16) -> Self {
self.mtu_discovery_config
.get_or_insert_with(Default::default)
.upper_bound(value);
self
}
pub fn disable_path_mtu_discovery(mut self) -> Self {
self.mtu_discovery_config = None;
self
}
}
#[derive(Debug, Clone)]
pub(crate) struct QuinnConfig {
pub(crate) client_config: quinn::ClientConfig,
pub(crate) server_config: quinn::ServerConfig,
pub(crate) endpoint_config: quinn::EndpointConfig,
}
#[expect(deprecated)]
impl From<Config> for QuinnConfig {
fn from(config: Config) -> QuinnConfig {
let Config {
client_tls_config,
server_tls_config,
max_idle_timeout,
max_concurrent_stream_limit,
keep_alive_interval,
max_connection_data,
max_stream_data,
support_draft_29,
handshake_timeout: _,
keypair,
mtu_discovery_config,
} = config;
let mut transport = quinn::TransportConfig::default();
transport.max_concurrent_uni_streams(0u32.into());
transport.max_concurrent_bidi_streams(max_concurrent_stream_limit.into());
transport.datagram_receive_buffer_size(None);
transport.keep_alive_interval(Some(keep_alive_interval));
transport.max_idle_timeout(Some(VarInt::from_u32(max_idle_timeout).into()));
transport.allow_spin(false);
transport.stream_receive_window(max_stream_data.into());
transport.receive_window(max_connection_data.into());
transport.mtu_discovery_config(mtu_discovery_config);
let transport = Arc::new(transport);
let mut server_config = quinn::ServerConfig::with_crypto(server_tls_config);
server_config.transport = Arc::clone(&transport);
server_config.migration(false);
let mut client_config = quinn::ClientConfig::new(client_tls_config);
client_config.transport_config(transport);
let mut endpoint_config = keypair
.derive_secret(b"libp2p quic stateless reset key")
.map(|secret| {
let reset_key = Arc::new(ring::hmac::Key::new(ring::hmac::HMAC_SHA256, &secret));
quinn::EndpointConfig::new(reset_key)
})
.unwrap_or_default();
if !support_draft_29 {
endpoint_config.supported_versions(vec![1]);
}
QuinnConfig {
client_config,
server_config,
endpoint_config,
}
}
}