Skip to content

Commit

Permalink
Expose QUIC ConfigBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
mempirate authored Jan 19, 2024
2 parents a79810c + 4c66e47 commit b5364c5
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 4 deletions.
2 changes: 1 addition & 1 deletion msg-socket/src/req/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ where
response_rx.await.map_err(|_| ReqError::SocketClosed)?
}

/// Connects to the target with the default options. WARN: this will block until the connection can be established.
/// Connects to the target with the default options. WARN: this will wait until the connection can be established.
pub async fn connect(&mut self, endpoint: SocketAddr) -> Result<(), ReqError> {
// Initialize communication channels
let (to_driver, from_socket) = mpsc::channel(DEFAULT_BUFFER_SIZE);
Expand Down
112 changes: 110 additions & 2 deletions msg-transport/src/quic/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use quinn::IdleTimeout;
use quinn::{congestion::ControllerFactory, IdleTimeout};
use std::{sync::Arc, time::Duration};

use super::tls::{self_signed_certificate, unsafe_client_config};
Expand All @@ -11,6 +11,114 @@ pub struct Config {
pub server_config: quinn::ServerConfig,
}

#[derive(Debug)]
pub struct ConfigBuilder<C> {
cc: C,
initial_mtu: u16,
max_stream_bandwidth: u32,
expected_rtt: u32,
max_idle_timeout: Duration,
keep_alive_interval: Duration,
}

impl<C> ConfigBuilder<C>
where
C: ControllerFactory + Default + Send + Sync + 'static,
{
/// Creates a new [`ConfigBuilder`] with sensible defaults.
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
cc: C::default(),
initial_mtu: 1460,
max_stream_bandwidth: 50 * MiB,
expected_rtt: 100,
max_idle_timeout: Duration::from_secs(60 * 5),
keep_alive_interval: Duration::from_secs(15),
}
}

/// Sets the initial MTU.
pub fn initial_mtu(mut self, mtu: u16) -> Self {
self.initial_mtu = mtu;
self
}

/// Sets the maximum stream bandwidth in bytes per second.
pub fn max_stream_bandwidth(mut self, bandwidth: u32) -> Self {
self.max_stream_bandwidth = bandwidth;
self
}

/// Sets the expected round-trip time in milliseconds.
pub fn expected_rtt(mut self, rtt: u32) -> Self {
self.expected_rtt = rtt;
self
}

/// Sets the maximum idle timeout.
pub fn max_idle_timeout(mut self, timeout: Duration) -> Self {
self.max_idle_timeout = timeout;
self
}

/// Sets the keep-alive interval.
pub fn keep_alive_interval(mut self, interval: Duration) -> Self {
self.keep_alive_interval = interval;
self
}

/// Sets the congestion controller.
pub fn congestion_controller(mut self, cc: C) -> Self {
self.cc = cc;
self
}

/// Builds the QUIC [`Config`].
pub fn build(self) -> Config {
let mut transport = quinn::TransportConfig::default();

// Stream receive window
let stream_rwnd = self.max_stream_bandwidth / 1000 * self.expected_rtt;

transport
.keep_alive_interval(Some(self.keep_alive_interval))
.max_idle_timeout(Some(
IdleTimeout::try_from(self.max_idle_timeout).expect("Valid idle timeout"),
))
// Disable datagram support
.datagram_receive_buffer_size(None)
.datagram_send_buffer_size(0)
.max_concurrent_uni_streams(0u32.into())
.initial_mtu(self.initial_mtu)
.min_mtu(self.initial_mtu)
.allow_spin(false)
.stream_receive_window((8 * stream_rwnd).into())
.congestion_controller_factory(self.cc)
.initial_rtt(Duration::from_millis(self.expected_rtt.into()))
.send_window((8 * stream_rwnd).into());

let transport = Arc::new(transport);
let (cert, key) = self_signed_certificate();

let mut server_config =
quinn::ServerConfig::with_single_cert(cert, key).expect("Valid rustls config");

server_config.use_retry(true);
server_config.transport_config(Arc::clone(&transport));

let mut client_config = quinn::ClientConfig::new(Arc::new(unsafe_client_config()));

client_config.transport_config(transport);

Config {
endpoint_config: quinn::EndpointConfig::default(),
client_config,
server_config,
}
}
}

impl Default for Config {
fn default() -> Self {
// The expected RTT in ms. This has a big impact on initial performance.
Expand All @@ -23,7 +131,7 @@ impl Default for Config {

// Default initial window is 12000 bytes. This is limited to not overwhelm slow links.
let mut cc = quinn::congestion::CubicConfig::default();
// 4 MiB initial window
// 1 MiB initial window
// Note that this is a very high initial window outside of private networks.
// TODO: document this and make it configurable
cc.initial_window(MiB as u64);
Expand Down
3 changes: 2 additions & 1 deletion msg-transport/src/quic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ mod config;
mod stream;
mod tls;

use config::Config;
pub use config::{Config, ConfigBuilder};
pub use quinn::congestion;
use stream::QuicStream;

/// A QUIC error.
Expand Down

0 comments on commit b5364c5

Please sign in to comment.