web_transport_quinn/
server.rsuse std::sync::Arc;
use crate::{CongestionControl, Connect, ServerError, Session, Settings};
use futures::{future::BoxFuture, stream::FuturesUnordered, StreamExt};
use rustls::pki_types::{CertificateDer, PrivateKeyDer};
use url::Url;
pub struct ServerBuilder {
addr: std::net::SocketAddr,
congestion_controller:
Option<Arc<dyn quinn::congestion::ControllerFactory + Send + Sync + 'static>>,
}
impl Default for ServerBuilder {
fn default() -> Self {
Self::new()
}
}
impl ServerBuilder {
pub fn new() -> Self {
Self {
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::BbrConfig::default()))
}
CongestionControl::Throughput => {
Some(Arc::new(quinn::congestion::CubicConfig::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(Arc::new(
rustls::crypto::aws_lc_rs::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])?
.with_no_client_auth()
.with_single_cert(chain, key)?;
config.alpn_protocols = vec![crate::ALPN.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, quinn::WriteError> {
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<(), quinn::WriteError> {
self.connect.respond(status).await?;
Ok(())
}
}