use std::io; use std::marker::PhantomData; use std::sync::Arc; use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use rustls::{ServerConfig, ServerSession}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_rustls::{AcceptAsync, ServerConfigExt, TlsStream}; use super::MAX_CONN_COUNTER; use counter::{Counter, CounterGuard}; use service::{NewService, Service}; /// Support `SSL` connections via rustls package /// /// `rust-tls` feature enables `RustlsAcceptor` type pub struct RustlsAcceptor { config: Arc, io: PhantomData, } impl RustlsAcceptor { /// Create `RustlsAcceptor` new service pub fn new(config: ServerConfig) -> Self { RustlsAcceptor { config: Arc::new(config), io: PhantomData, } } } impl Clone for RustlsAcceptor { fn clone(&self) -> Self { Self { config: self.config.clone(), io: PhantomData, } } } impl NewService for RustlsAcceptor { type Request = T; type Response = TlsStream; type Error = io::Error; type Service = RustlsAcceptorService; type InitError = (); type Future = FutureResult; fn new_service(&self) -> Self::Future { MAX_CONN_COUNTER.with(|conns| { ok(RustlsAcceptorService { config: self.config.clone(), conns: conns.clone(), io: PhantomData, }) }) } } pub struct RustlsAcceptorService { config: Arc, io: PhantomData, conns: Counter, } impl Service for RustlsAcceptorService { type Request = T; type Response = TlsStream; type Error = io::Error; type Future = RustlsAcceptorServiceFut; fn poll_ready(&mut self) -> Poll<(), Self::Error> { if self.conns.available() { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } fn call(&mut self, req: Self::Request) -> Self::Future { RustlsAcceptorServiceFut { _guard: self.conns.get(), fut: ServerConfigExt::accept_async(&self.config, req), } } } pub struct RustlsAcceptorServiceFut where T: AsyncRead + AsyncWrite, { fut: AcceptAsync, _guard: CounterGuard, } impl Future for RustlsAcceptorServiceFut { type Item = TlsStream; type Error = io::Error; fn poll(&mut self) -> Poll { self.fut.poll() } }