#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
use std::sync::Arc;
use futures::{StreamExt, future::BoxFuture, stream::FuturesUnordered};
#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use url::Url;
#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
use crate::{CongestionControl, crypto};
use crate::{Connect, ServerError, Session, Settings};
#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
pub struct ServerBuilder {
provider: crypto::Provider,
addr: std::net::SocketAddr,
congestion_controller:
Option<Arc<dyn quinn::congestion::ControllerFactory + Send + Sync + 'static>>,
}
#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
impl Default for ServerBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
impl ServerBuilder {
pub fn new() -> Self {
Self {
provider: crypto::default_provider(),
addr: "[::]:443".parse().unwrap(),
congestion_controller: None,
}
}
pub fn with_addr(self, addr: std::net::SocketAddr) -> Self {
Self { addr, ..self }
}
pub fn with_congestion_control(mut self, algorithm: CongestionControl) -> Self {
self.congestion_controller = match algorithm {
CongestionControl::LowLatency => {
Some(Arc::new(quinn::congestion::NewRenoConfig::default()))
}
CongestionControl::Throughput => {
Some(Arc::new(quinn::congestion::BbrConfig::default()))
}
CongestionControl::Default => None,
};
self
}
pub fn with_certificate(
self,
chain: Vec<CertificateDer<'static>>,
key: PrivateKeyDer<'static>,
) -> Result<Server, ServerError> {
let mut config = rustls::ServerConfig::builder_with_provider(self.provider.clone())
.with_protocol_versions(&[&rustls::version::TLS13])?
.with_no_client_auth()
.with_single_cert(chain, key)?;
config.alpn_protocols = vec![crate::ALPN.as_bytes().to_vec()];
let config: quinn::crypto::rustls::QuicServerConfig = config.try_into().unwrap();
let config = quinn::ServerConfig::with_crypto(Arc::new(config));
let server = quinn::Endpoint::server(config, self.addr)
.map_err(|e| ServerError::IoError(e.into()))?;
Ok(Server::new(server))
}
pub fn with_certificates(
self,
certificates: Vec<(String, Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)>,
) -> Result<Server, ServerError> {
let mut resolver = rustls::server::ResolvesServerCertUsingSni::new();
for (name, chain, key) in certificates {
let certified = rustls::sign::CertifiedKey::from_der(chain, key, &self.provider)?;
resolver.add(&name, certified)?;
}
let mut config = rustls::ServerConfig::builder_with_provider(self.provider.clone())
.with_protocol_versions(&[&rustls::version::TLS13])?
.with_no_client_auth()
.with_cert_resolver(Arc::new(resolver));
config.alpn_protocols = vec![crate::ALPN.as_bytes().to_vec()];
let config: quinn::crypto::rustls::QuicServerConfig = config.try_into().unwrap();
let config = quinn::ServerConfig::with_crypto(Arc::new(config));
let server = quinn::Endpoint::server(config, self.addr)
.map_err(|e| ServerError::IoError(e.into()))?;
Ok(Server::new(server))
}
}
pub struct Server {
endpoint: quinn::Endpoint,
accept: FuturesUnordered<BoxFuture<'static, Result<Request, ServerError>>>,
}
impl Server {
pub fn new(endpoint: quinn::Endpoint) -> Self {
Self {
endpoint,
accept: Default::default(),
}
}
pub async fn accept(&mut self) -> Option<Request> {
loop {
tokio::select! {
res = self.endpoint.accept() => {
let conn = res?;
self.accept.push(Box::pin(async move {
let conn = conn.await?;
Request::accept(conn).await
}));
}
Some(res) = self.accept.next() => {
if let Ok(session) = res {
return Some(session)
}
}
}
}
}
}
pub struct Request {
conn: quinn::Connection,
settings: Settings,
connect: Connect,
}
impl Request {
pub async fn accept(conn: quinn::Connection) -> Result<Self, ServerError> {
let settings = Settings::connect(&conn).await?;
let connect = Connect::accept(&conn).await?;
Ok(Self {
conn,
settings,
connect,
})
}
pub fn url(&self) -> &Url {
self.connect.url()
}
pub async fn ok(mut self) -> Result<Session, ServerError> {
self.connect.respond(http::StatusCode::OK).await?;
Ok(Session::new(self.conn, self.settings, self.connect))
}
pub async fn close(mut self, status: http::StatusCode) -> Result<(), ServerError> {
self.connect.respond(status).await?;
Ok(())
}
}