use std::{net::SocketAddr, sync::Arc};
use anyhow::Result;
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::{
rustls::{self, ServerConfig},
TlsAcceptor, TlsStream,
};
use crate::certificates::{load_certificates, load_keys};
use crate::resolve_address;
pub struct TlsServer {
config: Arc<ServerConfig>,
address: SocketAddr,
interface: String,
}
impl TlsServer {
pub async fn new<T, U, V>(interface: T, cert_file: U, key_file: V) -> Result<Self>
where
T: ToString,
U: ToString,
V: ToString,
{
let interface = interface.to_string();
let cert_file = cert_file.to_string();
let key_file = key_file.to_string();
let certificates = load_certificates(cert_file).await?;
let mut keys = load_keys(key_file).await?;
let address = resolve_address(interface.as_str()).await?;
let config = rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(certificates, keys.remove(0))?;
Ok(TlsServer {
config: Arc::new(config),
address,
interface,
})
}
pub async fn listen(&self) -> Result<TlsListener> {
Ok(TlsListener::new(&self.address, &self.config).await?)
}
pub fn get_interface(&self) -> &String {
&self.interface
}
}
pub struct TlsListener {
listener: TcpListener,
acceptor: TlsAcceptor,
}
impl TlsListener {
async fn new(address: &SocketAddr, config: &Arc<ServerConfig>) -> Result<Self> {
let acceptor = TlsAcceptor::from(config.clone());
let listener = TcpListener::bind(address).await?;
Ok(TlsListener { listener, acceptor })
}
pub async fn stream_accept(&self) -> Result<(TcpClientStream, SocketAddr)> {
let (stream, address) = self.listener.accept().await?;
let acceptor = self.acceptor.clone();
Ok((TcpClientStream { stream, acceptor }, address))
}
}
pub struct TcpClientStream {
stream: TcpStream,
acceptor: TlsAcceptor,
}
impl TcpClientStream {
pub async fn tls_accept(self) -> Result<TlsStream<TcpStream>> {
let stream = self.acceptor.accept(self.stream).await?;
let stream = tokio_rustls::TlsStream::Server(stream);
Ok(stream)
}
}