use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; pub use open_ssl::ssl::{SslAcceptor, SslAcceptorBuilder, AlpnError}; pub use tokio_openssl::{HandshakeError, SslStream}; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; use futures::future::{ok, FutureExt, LocalBoxFuture, Ready}; use crate::MAX_CONN_COUNTER; /// Support `TLS` server connections via openssl package /// /// `openssl` feature enables `Acceptor` type pub struct Acceptor { acceptor: SslAcceptor, io: PhantomData, } impl Acceptor { /// Create default `OpensslAcceptor` pub fn new(acceptor: SslAcceptor) -> Self { Acceptor { acceptor, io: PhantomData, } } } impl Clone for Acceptor { fn clone(&self) -> Self { Self { acceptor: self.acceptor.clone(), io: PhantomData, } } } impl ServiceFactory for Acceptor { type Request = T; type Response = SslStream; type Error = HandshakeError; type Config = (); type Service = AcceptorService; type InitError = (); type Future = Ready>; fn new_service(&self, _: ()) -> Self::Future { MAX_CONN_COUNTER.with(|conns| { ok(AcceptorService { acceptor: self.acceptor.clone(), conns: conns.clone(), io: PhantomData, }) }) } } pub struct AcceptorService { acceptor: SslAcceptor, conns: Counter, io: PhantomData, } impl Service for AcceptorService { type Request = T; type Response = SslStream; type Error = HandshakeError; type Future = AcceptorServiceResponse; fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll> { if self.conns.available(ctx) { Poll::Ready(Ok(())) } else { Poll::Pending } } fn call(&mut self, req: Self::Request) -> Self::Future { let acc = self.acceptor.clone(); AcceptorServiceResponse { _guard: self.conns.get(), fut: async move { let acc = acc; tokio_openssl::accept(&acc, req).await } .boxed_local(), } } } pub struct AcceptorServiceResponse where T: AsyncRead + AsyncWrite, { fut: LocalBoxFuture<'static, Result, HandshakeError>>, _guard: CounterGuard, } impl Future for AcceptorServiceResponse { type Output = Result, HandshakeError>; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let io = futures::ready!(Pin::new(&mut self.fut).poll(cx))?; Poll::Ready(Ok(io)) } }