pub mod client;
pub mod endpoint;
#[cfg(feature = "qlog")]
pub mod qlog;
pub mod server;
pub mod web;
mod noq;
pub use endpoint::Endpoint;
pub use noq::{Connection, RecvStream, SendStream};
pub(crate) const SEGMENT: usize = 1350;
#[derive(Clone)]
pub struct Identity {
cert: Vec<u8>,
key: Vec<u8>,
}
impl Identity {
pub fn open(cert: impl AsRef<std::path::Path>, key: impl AsRef<std::path::Path>) -> Result<Self, Error> {
let read = |path: &std::path::Path| {
std::fs::read(path).map_err(|err| Error::Tls(format!("{}: {err}", path.display())))
};
Ok(Self {
cert: read(cert.as_ref())?,
key: read(key.as_ref())?,
})
}
pub fn from_pem(cert: impl Into<Vec<u8>>, key: impl Into<Vec<u8>>) -> Self {
Self {
cert: cert.into(),
key: key.into(),
}
}
pub fn cert(&self) -> &[u8] {
&self.cert
}
pub(crate) fn key(&self) -> &[u8] {
&self.key
}
}
impl std::fmt::Debug for Identity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Identity")
.field("cert", &format_args!("{} PEM bytes", self.cert.len()))
.finish_non_exhaustive()
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Transport {
pub idle_timeout: std::time::Duration,
pub max_streams: u64,
pub congestion: Congestion,
pub keep_alive: Option<std::time::Duration>,
#[cfg(feature = "qlog")]
pub qlog: Option<qlog::Sink>,
}
impl Default for Transport {
fn default() -> Self {
Self {
idle_timeout: std::time::Duration::from_secs(10),
max_streams: 1024,
congestion: Congestion::default(),
keep_alive: None,
#[cfg(feature = "qlog")]
qlog: None,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum Congestion {
#[default]
Loss,
Delay,
}
#[derive(Clone, Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("application closed: code={code} reason={reason:?}")]
App {
code: u64,
reason: String,
},
#[error("transport closed: code={code} reason={reason:?}")]
Transport {
code: u64,
reason: String,
},
#[error("connection timed out")]
TimedOut,
#[error("stream reset: {0}")]
Reset(u64),
#[error("stream stopped: {0}")]
Stop(u64),
#[error("tls error: {0}")]
Tls(String),
#[error("socket error: {0}")]
Io(String),
#[error("quic error: {0}")]
Quic(String),
#[error("endpoint has no server configuration")]
NotServer,
#[error("webtransport error: {0}")]
Web(String),
#[error("http/3 closed: code={code} reason={reason:?}")]
Http3 {
code: u64,
reason: String,
},
#[error("qlog error: {0}")]
Qlog(String),
}
impl web_transport_trait::Error for Error {
fn session_error(&self) -> Option<(u32, String)> {
match self {
Self::App { code, reason } => Some((u32::try_from(*code).unwrap_or(u32::MAX), reason.clone())),
_ => None,
}
}
fn stream_error(&self) -> Option<u32> {
match self {
Self::Reset(code) | Self::Stop(code) => Some(u32::try_from(*code).unwrap_or(u32::MAX)),
_ => None,
}
}
}