blob: 7f1ba66e868b16488a3599d9fa28ba9b70a240dc [file]
use std::fs::File;
use std::io::BufReader;
use std::net::SocketAddr;
use std::sync::Arc;
use anyhow::Result;
use error_set::ErrContext;
use quinn::{Endpoint, IdleTimeout, VarInt};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use tracing::info;
use crate::configs::quic::QuicConfig;
use crate::quic::listener;
use crate::quic::COMPONENT;
use crate::server_error::QuicError;
use crate::streaming::systems::system::SharedSystem;
/// Starts the QUIC server.
/// Returns the address the server is listening on.
pub fn start(config: QuicConfig, system: SharedSystem) -> SocketAddr {
info!("Initializing Iggy QUIC server...");
let address = config.address.parse().unwrap();
let quic_config = configure_quic(config);
if let Err(error) = quic_config {
panic!("Error when configuring QUIC: {:?}", error);
}
let endpoint = Endpoint::server(quic_config.unwrap(), address).unwrap();
let addr = endpoint.local_addr().unwrap();
listener::start(endpoint, system);
info!("Iggy QUIC server has started on: {:?}", addr);
addr
}
fn configure_quic(config: QuicConfig) -> Result<quinn::ServerConfig, QuicError> {
let (certificate, key) = match config.certificate.self_signed {
true => generate_self_signed_cert()?,
false => load_certificates(&config.certificate.cert_file, &config.certificate.key_file)?,
};
let mut server_config = quinn::ServerConfig::with_single_cert(certificate, key)
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to create server config")
})
.map_err(|_| QuicError::ConfigCreationError)?;
let mut transport = quinn::TransportConfig::default();
transport.initial_mtu(config.initial_mtu.as_bytes_u64() as u16);
transport.send_window(config.send_window.as_bytes_u64());
transport.receive_window(
VarInt::try_from(config.receive_window.as_bytes_u64())
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - invalid receive window")
})
.map_err(|_| QuicError::TransportConfigError)?,
);
transport.datagram_send_buffer_size(config.datagram_send_buffer_size.as_bytes_u64() as usize);
transport.max_concurrent_bidi_streams(
VarInt::try_from(config.max_concurrent_bidi_streams)
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - invalid bidi stream limit")
})
.map_err(|_| QuicError::TransportConfigError)?,
);
if !config.keep_alive_interval.is_zero() {
transport.keep_alive_interval(Some(config.keep_alive_interval.get_duration()));
}
if !config.max_idle_timeout.is_zero() {
let max_idle_timeout = IdleTimeout::try_from(config.max_idle_timeout.get_duration())
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - invalid idle timeout")
})
.map_err(|_| QuicError::TransportConfigError)?;
transport.max_idle_timeout(Some(max_idle_timeout));
}
server_config.transport_config(Arc::new(transport));
Ok(server_config)
}
fn generate_self_signed_cert<'a>() -> Result<(Vec<CertificateDer<'a>>, PrivateKeyDer<'a>), QuicError>
{
let certificate = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
let certificate_der = certificate.cert.der();
let private_key = certificate.key_pair.serialize_der();
let private_key = PrivateKeyDer::try_from(private_key)
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to parse private key")
})
.map_err(|_| QuicError::CertGenerationError)?;
let cert_chain = vec![certificate_der.clone()];
Ok((cert_chain, private_key))
}
fn load_certificates(
cert_file: &str,
key_file: &str,
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), QuicError> {
let mut cert_chain_reader = BufReader::new(
File::open(cert_file)
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to open cert file: {cert_file}")
})
.map_err(|_| QuicError::CertLoadError)?,
);
let certs = rustls_pemfile::certs(&mut cert_chain_reader)
.map(|x| CertificateDer::from(x.unwrap().to_vec()))
.collect();
let mut key_reader = BufReader::new(
File::open(key_file)
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to open key file: {key_file}")
})
.map_err(|_| QuicError::CertLoadError)?,
);
let mut keys = rustls_pemfile::rsa_private_keys(&mut key_reader)
.filter(|key| key.is_ok())
.map(|key| PrivateKeyDer::try_from(key.unwrap().secret_pkcs1_der().to_vec()))
.collect::<Result<Vec<_>, _>>()
.with_error_context(|error| {
format!("{COMPONENT} (error: {error}) - failed to parse private key")
})
.map_err(|_| QuicError::CertLoadError)?;
let key = keys.remove(0);
Ok((certs, key))
}