use std::{sync::Arc, time::Duration};
use quinn::{
crypto::rustls::{QuicClientConfig, QuicServerConfig},
MtuDiscoveryConfig, VarInt,
};
use crate::{config::TransportConfig, tls};
#[derive(Clone)]
pub struct QuicConfig {
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,
client_tls_config: Arc<QuicClientConfig>,
server_tls_config: Arc<QuicServerConfig>,
keypair: foctet_core::key::Keypair,
mtu_discovery_config: Option<MtuDiscoveryConfig>,
}
impl QuicConfig {
pub fn new(keypair: &foctet_core::key::Keypair) -> Self {
let client_tls_config = Arc::new(
QuicClientConfig::try_from(tls::config::make_client_config(keypair, None).unwrap())
.unwrap(),
);
let server_tls_config = Arc::new(
QuicServerConfig::try_from(tls::config::make_server_config(keypair).unwrap()).unwrap(),
);
Self {
client_tls_config,
server_tls_config,
handshake_timeout: Duration::from_secs(5),
max_idle_timeout: 10 * 1000,
max_concurrent_stream_limit: 256,
max_connection_data: 15_000_000,
max_stream_data: 10_000_000,
keep_alive_interval: Duration::from_secs(5),
keypair: keypair.clone(),
mtu_discovery_config: Some(Default::default()),
}
}
pub fn set_mtu_upper_bound(&mut self, value: u16) {
self.mtu_discovery_config
.get_or_insert_with(Default::default)
.upper_bound(value);
}
pub fn disable_path_mtu_discovery(&mut self) {
self.mtu_discovery_config = None;
}
}
impl From<TransportConfig> for QuicConfig {
fn from(config: TransportConfig) -> QuicConfig {
let client_tls_config =
Arc::new(QuicClientConfig::try_from(config.client_tls_config().clone()).unwrap());
let server_tls_config =
Arc::new(QuicServerConfig::try_from(config.server_tls_config().clone()).unwrap());
let mut quic_config = QuicConfig {
client_tls_config,
server_tls_config,
handshake_timeout: config.connection_timeout,
max_idle_timeout: 10 * 1000,
max_concurrent_stream_limit: config.max_concurrent_stream,
max_connection_data: 15_000_000,
max_stream_data: 10_000_000,
keep_alive_interval: Duration::from_secs(5),
keypair: config.keypair().clone(),
mtu_discovery_config: Some(Default::default()),
};
if let Some(mtu_upper_bound) = config.mtu_upper_bound {
quic_config.set_mtu_upper_bound(mtu_upper_bound);
}
if let Some(enable_mtu_discovery) = config.enable_mtu_discovery {
if !enable_mtu_discovery {
quic_config.disable_path_mtu_discovery();
}
}
quic_config
}
}
#[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,
}
impl From<QuicConfig> for QuinnConfig {
fn from(config: QuicConfig) -> QuinnConfig {
let QuicConfig {
client_tls_config,
server_tls_config,
max_idle_timeout,
max_concurrent_stream_limit,
keep_alive_interval,
max_connection_data,
max_stream_data,
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 secret = keypair.secret().to_bytes();
let reset_key = Arc::new(ring::hmac::Key::new(ring::hmac::HMAC_SHA256, &secret));
let endpoint_config = quinn::EndpointConfig::new(reset_key);
QuinnConfig {
client_config,
server_config,
endpoint_config,
}
}
}