use super::{BoxRecv, BoxSend, Transport};
use crate::error::{Error, Result};
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
#[derive(Clone)]
pub struct QuicTransport {
conn: quinn::Connection,
}
impl QuicTransport {
pub fn from_connection(conn: quinn::Connection) -> Self {
Self { conn }
}
pub fn connection(&self) -> &quinn::Connection {
&self.conn
}
}
#[async_trait::async_trait]
impl Transport for QuicTransport {
async fn open_uni(&self) -> Result<BoxSend> {
let s = self.conn.open_uni().await.map_err(Error::transport)?;
Ok(Box::new(s))
}
async fn accept_uni(&self) -> Result<BoxRecv> {
let s = self.conn.accept_uni().await.map_err(Error::transport)?;
Ok(Box::new(s))
}
async fn open_bi(&self) -> Result<(BoxSend, BoxRecv)> {
let (w, r) = self.conn.open_bi().await.map_err(Error::transport)?;
Ok((Box::new(w), Box::new(r)))
}
async fn accept_bi(&self) -> Result<(BoxSend, BoxRecv)> {
let (w, r) = self.conn.accept_bi().await.map_err(Error::transport)?;
Ok((Box::new(w), Box::new(r)))
}
fn close(&self, code: u32, reason: &[u8]) {
self.conn.close(code.into(), reason);
}
fn peer_label(&self) -> String {
self.conn.remote_address().to_string()
}
fn bytes_sent(&self) -> Option<u64> {
Some(self.conn.stats().udp_tx.bytes)
}
}
pub fn bulk_transport_config() -> quinn::TransportConfig {
let mut t = quinn::TransportConfig::default();
t.receive_window(quinn::VarInt::from_u32(64 * 1024 * 1024));
t.stream_receive_window(quinn::VarInt::from_u32(16 * 1024 * 1024));
t.send_window(64 * 1024 * 1024);
t.max_concurrent_uni_streams(quinn::VarInt::from_u32(256));
t.max_concurrent_bidi_streams(quinn::VarInt::from_u32(16));
t.keep_alive_interval(Some(Duration::from_secs(5)));
t.max_idle_timeout(Some(Duration::from_secs(60).try_into().unwrap()));
t
}
pub fn server_endpoint(
addr: SocketAddr,
cert_chain: Vec<rustls::pki_types::CertificateDer<'static>>,
key: rustls::pki_types::PrivateKeyDer<'static>,
) -> Result<quinn::Endpoint> {
let mut server_crypto = rustls::ServerConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])
.map_err(Error::transport)?
.with_no_client_auth()
.with_single_cert(cert_chain, key)
.map_err(Error::transport)?;
server_crypto.alpn_protocols = vec![ALPN.to_vec()];
let mut cfg = quinn::ServerConfig::with_crypto(Arc::new(
quinn::crypto::rustls::QuicServerConfig::try_from(server_crypto)
.map_err(Error::transport)?,
));
cfg.transport_config(Arc::new(bulk_transport_config()));
quinn::Endpoint::server(cfg, addr).map_err(Error::from)
}
pub fn client_endpoint(
bind: SocketAddr,
server_cert: rustls::pki_types::CertificateDer<'static>,
) -> Result<quinn::Endpoint> {
let mut roots = rustls::RootCertStore::empty();
roots.add(server_cert).map_err(Error::transport)?;
let mut client_crypto = rustls::ClientConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])
.map_err(Error::transport)?
.with_root_certificates(roots)
.with_no_client_auth();
client_crypto.alpn_protocols = vec![ALPN.to_vec()];
let mut cfg = quinn::ClientConfig::new(Arc::new(
quinn::crypto::rustls::QuicClientConfig::try_from(client_crypto)
.map_err(Error::transport)?,
));
cfg.transport_config(Arc::new(bulk_transport_config()));
let mut ep = quinn::Endpoint::client(bind).map_err(Error::from)?;
ep.set_default_client_config(cfg);
Ok(ep)
}
pub const ALPN: &[u8] = b"runsync-transfer/1";
#[cfg(feature = "test-certs")]
pub fn self_signed(
names: Vec<String>,
) -> Result<(
rustls::pki_types::CertificateDer<'static>,
rustls::pki_types::PrivateKeyDer<'static>,
)> {
let c = rcgen::generate_simple_self_signed(names).map_err(Error::transport)?;
let cert = rustls::pki_types::CertificateDer::from(c.cert);
let key = rustls::pki_types::PrivateKeyDer::try_from(c.key_pair.serialize_der())
.map_err(Error::transport)?;
Ok((cert, key))
}