use crate::datagram::Datagram;
use crate::driver::utils::varint_w2q;
use crate::driver::Driver;
use crate::error::ConnectionError;
use crate::error::ExportKeyingMaterialError;
use crate::error::SendDatagramError;
use crate::stream::OpeningBiStream;
use crate::stream::OpeningUniStream;
use crate::stream::RecvStream;
use crate::stream::SendStream;
use crate::tls::Certificate;
use crate::tls::CertificateChain;
use crate::tls::HandshakeData;
use crate::SessionId;
use crate::VarInt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
#[derive(Clone, Debug)]
pub struct Connection {
quic_connection: quinn::Connection,
driver: Arc<Driver>,
session_id: SessionId,
}
impl Connection {
pub(crate) fn new(
quic_connection: quinn::Connection,
driver: Driver,
session_id: SessionId,
) -> Self {
Self {
quic_connection,
driver: Arc::new(driver),
session_id,
}
}
pub async fn accept_uni(&self) -> Result<RecvStream, ConnectionError> {
let stream = self
.driver
.accept_uni(self.session_id)
.await
.map_err(|driver_error| {
ConnectionError::with_driver_error(driver_error, &self.quic_connection)
})?
.into_stream();
Ok(RecvStream::new(stream))
}
pub async fn accept_bi(&self) -> Result<(SendStream, RecvStream), ConnectionError> {
let stream = self
.driver
.accept_bi(self.session_id)
.await
.map_err(|driver_error| {
ConnectionError::with_driver_error(driver_error, &self.quic_connection)
})?
.into_stream();
Ok((SendStream::new(stream.0), RecvStream::new(stream.1)))
}
pub async fn open_uni(&self) -> Result<OpeningUniStream, ConnectionError> {
self.driver
.open_uni(self.session_id)
.await
.map_err(|driver_error| {
ConnectionError::with_driver_error(driver_error, &self.quic_connection)
})
}
pub async fn open_bi(&self) -> Result<OpeningBiStream, ConnectionError> {
self.driver
.open_bi(self.session_id)
.await
.map_err(|driver_error| {
ConnectionError::with_driver_error(driver_error, &self.quic_connection)
})
}
pub async fn receive_datagram(&self) -> Result<Datagram, ConnectionError> {
self.driver
.receive_datagram(self.session_id)
.await
.map_err(|driver_error| {
ConnectionError::with_driver_error(driver_error, &self.quic_connection)
})
}
pub fn send_datagram<D>(&self, payload: D) -> Result<(), SendDatagramError>
where
D: AsRef<[u8]>,
{
self.driver.send_datagram(self.session_id, payload.as_ref())
}
pub fn close(&self, error_code: VarInt, reason: &[u8]) {
self.quic_connection.close(varint_w2q(error_code), reason);
}
pub async fn closed(&self) -> ConnectionError {
self.quic_connection.closed().await.into()
}
#[inline(always)]
pub fn session_id(&self) -> SessionId {
self.session_id
}
#[inline(always)]
pub fn remote_address(&self) -> SocketAddr {
self.quic_connection.remote_address()
}
#[inline(always)]
pub fn stable_id(&self) -> usize {
self.quic_connection.stable_id()
}
#[inline(always)]
pub fn max_datagram_size(&self) -> Option<usize> {
self.quic_connection
.max_datagram_size()
.map(|quic_max_size| quic_max_size - Datagram::header_size(self.session_id))
}
#[inline(always)]
pub fn rtt(&self) -> Duration {
self.quic_connection.rtt()
}
pub fn export_keying_material(
&self,
output: &mut [u8],
label: &[u8],
context: &[u8],
) -> Result<(), ExportKeyingMaterialError> {
self.quic_connection
.export_keying_material(output, label, context)
.map_err(|_: quinn::crypto::ExportKeyingMaterialError| ExportKeyingMaterialError)
}
pub fn peer_identity(&self) -> Option<CertificateChain> {
self.quic_connection.peer_identity().map(|any| {
any.downcast::<Vec<rustls_pki_types::CertificateDer<'static>>>()
.expect("rustls certificate vector")
.into_iter()
.map(Certificate::from_rustls_pki)
.collect()
})
}
pub fn handshake_data(&self) -> HandshakeData {
let hd = self
.quic_connection
.handshake_data()
.expect("fully established connection")
.downcast::<quinn::crypto::rustls::HandshakeData>()
.expect("valid downcast");
HandshakeData {
alpn: hd.protocol,
server_name: hd.server_name,
}
}
#[cfg(feature = "quinn")]
#[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
#[inline(always)]
pub fn quic_connection(&self) -> &quinn::Connection {
&self.quic_connection
}
#[cfg(feature = "quinn")]
#[cfg_attr(docsrs, doc(cfg(feature = "quinn")))]
#[inline(always)]
pub fn quic_connection_mut(&mut self) -> &mut quinn::Connection {
&mut self.quic_connection
}
}