use std::sync::Arc;
use tokio::net::TcpStream;
use tokio_rustls::TlsAcceptor as RustlsAcceptor;
use hotaru_core::connection::Accepter;
use super::stream::TlsStream;
use crate::config::server::TlsConfig;
#[derive(Clone)]
pub struct TlsAccepter {
acceptor: RustlsAcceptor,
}
impl TlsAccepter {
pub fn new(config: TlsConfig) -> Result<Self, TlsAccepterError> {
let server_config = config
.build_server_config()
.map_err(|e| TlsAccepterError::ConfigError(e.to_string()))?;
Ok(Self {
acceptor: RustlsAcceptor::from(Arc::new(server_config)),
})
}
pub fn inner(&self) -> &RustlsAcceptor {
&self.acceptor
}
}
impl Accepter for TlsAccepter {
type Raw = TcpStream;
type Stream = TlsStream;
type Error = TlsUpgradeError;
async fn upgrade(&self, raw: Self::Raw) -> Result<Self::Stream, Self::Error> {
self.acceptor
.accept(raw)
.await
.map(TlsStream::Server)
.map_err(TlsUpgradeError::Handshake)
}
}
#[derive(Debug)]
pub enum TlsUpgradeError {
Handshake(std::io::Error),
}
impl std::fmt::Display for TlsUpgradeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Handshake(e) => write!(f, "TLS handshake failed: {}", e),
}
}
}
impl std::error::Error for TlsUpgradeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Handshake(e) => Some(e),
}
}
}
impl From<TlsUpgradeError> for std::io::Error {
fn from(err: TlsUpgradeError) -> Self {
match err {
TlsUpgradeError::Handshake(e) => e,
}
}
}
#[derive(Debug)]
pub enum TlsAccepterError {
ConfigError(String),
}
impl std::fmt::Display for TlsAccepterError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ConfigError(e) => write!(f, "TLS accepter configuration error: {}", e),
}
}
}
impl std::error::Error for TlsAccepterError {}