use std::future::Future; use std::io; use std::marker::PhantomData; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; use futures_util::future::{ok, Ready}; use tokio_rustls::{Accept, TlsAcceptor}; pub use rust_tls::{ServerConfig, Session}; pub use tokio_rustls::server::TlsStream; pub use webpki_roots::TLS_SERVER_ROOTS; use crate::MAX_CONN_COUNTER; /// Accept TLS connections via `rustls` package. /// /// `rustls` feature enables this `Acceptor` type. pub struct Acceptor { config: Arc, io: PhantomData, } impl Acceptor { /// Create Rustls based `Acceptor` service factory. #[inline] pub fn new(config: ServerConfig) -> Self { Acceptor { config: Arc::new(config), io: PhantomData, } } } impl Clone for Acceptor { #[inline] fn clone(&self) -> Self { Self { config: self.config.clone(), io: PhantomData, } } } impl ServiceFactory for Acceptor { type Request = T; type Response = TlsStream; type Error = io::Error; type Service = AcceptorService; type Config = (); type InitError = (); type Future = Ready>; fn new_service(&self, _: ()) -> Self::Future { MAX_CONN_COUNTER.with(|conns| { ok(AcceptorService { acceptor: self.config.clone().into(), conns: conns.clone(), io: PhantomData, }) }) } } /// Rustls based `Acceptor` service pub struct AcceptorService { acceptor: TlsAcceptor, io: PhantomData, conns: Counter, } impl Service for AcceptorService { type Request = T; type Response = TlsStream; type Error = io::Error; type Future = AcceptorServiceFut; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { if self.conns.available(cx) { Poll::Ready(Ok(())) } else { Poll::Pending } } fn call(&mut self, req: Self::Request) -> Self::Future { AcceptorServiceFut { _guard: self.conns.get(), fut: self.acceptor.accept(req), } } } pub struct AcceptorServiceFut where T: AsyncRead + AsyncWrite + Unpin, { fut: Accept, _guard: CounterGuard, } impl Future for AcceptorServiceFut { type Output = Result, io::Error>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); let res = futures_util::ready!(Pin::new(&mut this.fut).poll(cx)); match res { Ok(io) => Poll::Ready(Ok(io)), Err(e) => Poll::Ready(Err(e)), } } }