From 7e7df2f9316900acc258bbe56485a07c138deaf5 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Tue, 16 Nov 2021 08:22:24 +0800 Subject: [PATCH] add timeout for accepting tls connections (#393) Co-authored-by: Rob Ede --- .cargo/config.toml | 2 +- actix-tls/CHANGES.md | 5 ++ actix-tls/Cargo.toml | 3 + actix-tls/src/accept/mod.rs | 18 ++-- actix-tls/src/accept/native_tls.rs | 50 ++++++++--- actix-tls/src/accept/openssl.rs | 67 +++++++++++---- actix-tls/src/accept/rustls.rs | 51 ++++++++--- actix-tls/tests/accept-openssl.rs | 130 +++++++++++++++++++++++++++++ actix-tls/tests/accept-rustls.rs | 104 +++++++++++++++++++++++ actix-utils/src/counter.rs | 2 +- 10 files changed, 382 insertions(+), 50 deletions(-) create mode 100644 actix-tls/tests/accept-openssl.rs create mode 100644 actix-tls/tests/accept-rustls.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 1c282baf..a1bc5198 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -14,7 +14,7 @@ ci-check = "hack --workspace --feature-powerset --exclude-features=io-uring chec ci-check-linux = "hack --workspace --feature-powerset check --tests --examples" # tests avoiding io-uring feature -ci-test = "hack test --workspace --exclude=actix-rt --exclude=actix-server --all-features --lib --tests --no-fail-fast -- --nocapture" +ci-test = " hack --feature-powerset --exclude=actix-rt --exclude=actix-server --exclude-features=io-uring test --workspace --lib --tests --no-fail-fast -- --nocapture" ci-test-rt = " hack --feature-powerset --exclude-features=io-uring test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture" ci-test-server = "hack --feature-powerset --exclude-features=io-uring test --package=actix-server --lib --tests --no-fail-fast -- --nocapture" diff --git a/actix-tls/CHANGES.md b/actix-tls/CHANGES.md index ae52fd0f..fde3c460 100644 --- a/actix-tls/CHANGES.md +++ b/actix-tls/CHANGES.md @@ -1,6 +1,11 @@ # Changes ## Unreleased - 2021-xx-xx +* Add configurable timeout for accepting TLS connection. [#393] +* Added `TlsError::Timeout` variant. [#393] +* All TLS acceptor services now use `TlsError` for their error types. [#393] + +[#393]: https://github.com/actix/actix-net/pull/393 ## 3.0.0-beta.8 - 2021-11-15 diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index 9abe10af..7cd87c55 100755 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -47,6 +47,7 @@ derive_more = "0.99.5" futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] } http = { version = "0.2.3", optional = true } log = "0.4" +pin-project-lite = "0.2.7" tokio-util = { version = "0.6.3", default-features = false } # openssl @@ -67,7 +68,9 @@ bytes = "1" env_logger = "0.9" futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } log = "0.4" +rcgen = "0.8" rustls-pemfile = "0.2.1" +tokio-rustls = { version = "0.23", features = ["dangerous_configuration"] } trust-dns-resolver = "0.20.0" [[example]] diff --git a/actix-tls/src/accept/mod.rs b/actix-tls/src/accept/mod.rs index dd939e4a..ead7927f 100644 --- a/actix-tls/src/accept/mod.rs +++ b/actix-tls/src/accept/mod.rs @@ -1,9 +1,4 @@ -//! TLS acceptor services for Actix ecosystem. -//! -//! ## Crate Features -//! * `openssl` - TLS acceptor using the `openssl` crate. -//! * `rustls` - TLS acceptor using the `rustls` crate. -//! * `native-tls` - TLS acceptor using the `native-tls` crate. +//! TLS acceptor services. use std::sync::atomic::{AtomicUsize, Ordering}; @@ -20,6 +15,10 @@ pub mod native_tls; pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256); +#[cfg(any(feature = "openssl", feature = "rustls", feature = "native-tls"))] +pub(crate) const DEFAULT_TLS_HANDSHAKE_TIMEOUT: std::time::Duration = + std::time::Duration::from_secs(3); + thread_local! { static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed)); } @@ -36,7 +35,8 @@ pub fn max_concurrent_tls_connect(num: usize) { /// TLS error combined with service error. #[derive(Debug)] -pub enum TlsError { - Tls(E1), - Service(E2), +pub enum TlsError { + Tls(TlsErr), + Timeout, + Service(SvcErr), } diff --git a/actix-tls/src/accept/native_tls.rs b/actix-tls/src/accept/native_tls.rs index 53294384..a115b5fa 100644 --- a/actix-tls/src/accept/native_tls.rs +++ b/actix-tls/src/accept/native_tls.rs @@ -1,20 +1,24 @@ use std::{ + convert::Infallible, io::{self, IoSlice}, ops::{Deref, DerefMut}, pin::Pin, task::{Context, Poll}, + time::Duration, }; use actix_codec::{AsyncRead, AsyncWrite, ReadBuf}; -use actix_rt::net::{ActixStream, Ready}; +use actix_rt::{ + net::{ActixStream, Ready}, + time::timeout, +}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::Counter; use futures_core::future::LocalBoxFuture; -pub use tokio_native_tls::native_tls::Error; -pub use tokio_native_tls::TlsAcceptor; +pub use tokio_native_tls::{native_tls::Error, TlsAcceptor}; -use super::MAX_CONN_COUNTER; +use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; /// Wrapper type for `tokio_native_tls::TlsStream` in order to impl `ActixStream` trait. pub struct TlsStream(tokio_native_tls::TlsStream); @@ -94,13 +98,25 @@ impl ActixStream for TlsStream { /// `native-tls` feature enables this `Acceptor` type. pub struct Acceptor { acceptor: TlsAcceptor, + handshake_timeout: Duration, } impl Acceptor { /// Create `native-tls` based `Acceptor` service factory. #[inline] pub fn new(acceptor: TlsAcceptor) -> Self { - Acceptor { acceptor } + Acceptor { + acceptor, + handshake_timeout: DEFAULT_TLS_HANDSHAKE_TIMEOUT, + } + } + + /// Limit the amount of time that the acceptor will wait for a TLS handshake to complete. + /// + /// Default timeout is 3 seconds. + pub fn set_handshake_timeout(&mut self, handshake_timeout: Duration) -> &mut Self { + self.handshake_timeout = handshake_timeout; + self } } @@ -109,13 +125,14 @@ impl Clone for Acceptor { fn clone(&self) -> Self { Self { acceptor: self.acceptor.clone(), + handshake_timeout: self.handshake_timeout, } } } impl ServiceFactory for Acceptor { type Response = TlsStream; - type Error = Error; + type Error = TlsError; type Config = (); type Service = NativeTlsAcceptorService; @@ -127,8 +144,10 @@ impl ServiceFactory for Acceptor { Ok(NativeTlsAcceptorService { acceptor: self.acceptor.clone(), conns: conns.clone(), + handshake_timeout: self.handshake_timeout, }) }); + Box::pin(async { res }) } } @@ -136,12 +155,13 @@ impl ServiceFactory for Acceptor { pub struct NativeTlsAcceptorService { acceptor: TlsAcceptor, conns: Counter, + handshake_timeout: Duration, } impl Service for NativeTlsAcceptorService { type Response = TlsStream; - type Error = Error; - type Future = LocalBoxFuture<'static, Result, Error>>; + type Error = TlsError; + type Future = LocalBoxFuture<'static, Result>; fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { if self.conns.available(cx) { @@ -154,10 +174,18 @@ impl Service for NativeTlsAcceptorService { fn call(&self, io: T) -> Self::Future { let guard = self.conns.get(); let acceptor = self.acceptor.clone(); + + let dur = self.handshake_timeout; + Box::pin(async move { - let io = acceptor.accept(io).await; - drop(guard); - io.map(Into::into) + match timeout(dur, acceptor.accept(io)).await { + Ok(Ok(io)) => { + drop(guard); + Ok(TlsStream(io)) + } + Ok(Err(err)) => Err(TlsError::Tls(err)), + Err(_timeout) => Err(TlsError::Timeout), + } }) } } diff --git a/actix-tls/src/accept/openssl.rs b/actix-tls/src/accept/openssl.rs index 4afcdcab..cb1887ea 100644 --- a/actix-tls/src/accept/openssl.rs +++ b/actix-tls/src/accept/openssl.rs @@ -1,22 +1,28 @@ use std::{ + convert::Infallible, future::Future, io::{self, IoSlice}, ops::{Deref, DerefMut}, pin::Pin, task::{Context, Poll}, + time::Duration, }; use actix_codec::{AsyncRead, AsyncWrite, ReadBuf}; -use actix_rt::net::{ActixStream, Ready}; +use actix_rt::{ + net::{ActixStream, Ready}, + time::{sleep, Sleep}, +}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; -use futures_core::{future::LocalBoxFuture, ready}; +use futures_core::future::LocalBoxFuture; pub use openssl::ssl::{ AlpnError, Error as SslError, HandshakeError, Ssl, SslAcceptor, SslAcceptorBuilder, }; +use pin_project_lite::pin_project; -use super::MAX_CONN_COUNTER; +use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; /// Wrapper type for `tokio_openssl::SslStream` in order to impl `ActixStream` trait. pub struct TlsStream(tokio_openssl::SslStream); @@ -96,13 +102,25 @@ impl ActixStream for TlsStream { /// `openssl` feature enables this `Acceptor` type. pub struct Acceptor { acceptor: SslAcceptor, + handshake_timeout: Duration, } impl Acceptor { /// Create OpenSSL based `Acceptor` service factory. #[inline] pub fn new(acceptor: SslAcceptor) -> Self { - Acceptor { acceptor } + Acceptor { + acceptor, + handshake_timeout: DEFAULT_TLS_HANDSHAKE_TIMEOUT, + } + } + + /// Limit the amount of time that the acceptor will wait for a TLS handshake to complete. + /// + /// Default timeout is 3 seconds. + pub fn set_handshake_timeout(&mut self, handshake_timeout: Duration) -> &mut Self { + self.handshake_timeout = handshake_timeout; + self } } @@ -111,13 +129,14 @@ impl Clone for Acceptor { fn clone(&self) -> Self { Self { acceptor: self.acceptor.clone(), + handshake_timeout: self.handshake_timeout, } } } impl ServiceFactory for Acceptor { type Response = TlsStream; - type Error = SslError; + type Error = TlsError; type Config = (); type Service = AcceptorService; type InitError = (); @@ -128,8 +147,10 @@ impl ServiceFactory for Acceptor { Ok(AcceptorService { acceptor: self.acceptor.clone(), conns: conns.clone(), + handshake_timeout: self.handshake_timeout, }) }); + Box::pin(async { res }) } } @@ -137,11 +158,12 @@ impl ServiceFactory for Acceptor { pub struct AcceptorService { acceptor: SslAcceptor, conns: Counter, + handshake_timeout: Duration, } impl Service for AcceptorService { type Response = TlsStream; - type Error = SslError; + type Error = TlsError; type Future = AcceptorServiceResponse; fn poll_ready(&self, ctx: &mut Context<'_>) -> Poll> { @@ -155,27 +177,38 @@ impl Service for AcceptorService { fn call(&self, io: T) -> Self::Future { let ssl_ctx = self.acceptor.context(); let ssl = Ssl::new(ssl_ctx).expect("Provided SSL acceptor was invalid."); + AcceptorServiceResponse { _guard: self.conns.get(), + timeout: sleep(self.handshake_timeout), stream: Some(tokio_openssl::SslStream::new(ssl, io).unwrap()), } } } -pub struct AcceptorServiceResponse { - stream: Option>, - _guard: CounterGuard, +pin_project! { + pub struct AcceptorServiceResponse { + stream: Option>, + #[pin] + timeout: Sleep, + _guard: CounterGuard, + } } impl Future for AcceptorServiceResponse { - type Output = Result, SslError>; + type Output = Result, TlsError>; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - ready!(Pin::new(self.stream.as_mut().unwrap()).poll_accept(cx))?; - Poll::Ready(Ok(self - .stream - .take() - .expect("SSL connect has resolved.") - .into())) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = self.project(); + + match Pin::new(this.stream.as_mut().unwrap()).poll_accept(cx) { + Poll::Ready(Ok(())) => Poll::Ready(Ok(this + .stream + .take() + .expect("Acceptor should not be polled after it has completed.") + .into())), + Poll::Ready(Err(err)) => Poll::Ready(Err(TlsError::Tls(err))), + Poll::Pending => this.timeout.poll(cx).map(|_| Err(TlsError::Timeout)), + } } } diff --git a/actix-tls/src/accept/rustls.rs b/actix-tls/src/accept/rustls.rs index 50c4b3ab..04d77ae3 100644 --- a/actix-tls/src/accept/rustls.rs +++ b/actix-tls/src/accept/rustls.rs @@ -1,22 +1,28 @@ use std::{ + convert::Infallible, future::Future, io::{self, IoSlice}, ops::{Deref, DerefMut}, pin::Pin, sync::Arc, task::{Context, Poll}, + time::Duration, }; use actix_codec::{AsyncRead, AsyncWrite, ReadBuf}; -use actix_rt::net::{ActixStream, Ready}; +use actix_rt::{ + net::{ActixStream, Ready}, + time::{sleep, Sleep}, +}; use actix_service::{Service, ServiceFactory}; use actix_utils::counter::{Counter, CounterGuard}; use futures_core::future::LocalBoxFuture; +use pin_project_lite::pin_project; use tokio_rustls::{Accept, TlsAcceptor}; pub use tokio_rustls::rustls::ServerConfig; -use super::MAX_CONN_COUNTER; +use super::{TlsError, DEFAULT_TLS_HANDSHAKE_TIMEOUT, MAX_CONN_COUNTER}; /// Wrapper type for `tokio_openssl::SslStream` in order to impl `ActixStream` trait. pub struct TlsStream(tokio_rustls::server::TlsStream); @@ -96,6 +102,7 @@ impl ActixStream for TlsStream { /// `rustls` feature enables this `Acceptor` type. pub struct Acceptor { config: Arc, + handshake_timeout: Duration, } impl Acceptor { @@ -104,8 +111,17 @@ impl Acceptor { pub fn new(config: ServerConfig) -> Self { Acceptor { config: Arc::new(config), + handshake_timeout: DEFAULT_TLS_HANDSHAKE_TIMEOUT, } } + + /// Limit the amount of time that the acceptor will wait for a TLS handshake to complete. + /// + /// Default timeout is 3 seconds. + pub fn set_handshake_timeout(&mut self, handshake_timeout: Duration) -> &mut Self { + self.handshake_timeout = handshake_timeout; + self + } } impl Clone for Acceptor { @@ -113,13 +129,14 @@ impl Clone for Acceptor { fn clone(&self) -> Self { Self { config: self.config.clone(), + handshake_timeout: self.handshake_timeout, } } } impl ServiceFactory for Acceptor { type Response = TlsStream; - type Error = io::Error; + type Error = TlsError; type Config = (); type Service = AcceptorService; @@ -131,8 +148,10 @@ impl ServiceFactory for Acceptor { Ok(AcceptorService { acceptor: self.config.clone().into(), conns: conns.clone(), + handshake_timeout: self.handshake_timeout, }) }); + Box::pin(async { res }) } } @@ -141,11 +160,12 @@ impl ServiceFactory for Acceptor { pub struct AcceptorService { acceptor: TlsAcceptor, conns: Counter, + handshake_timeout: Duration, } impl Service for AcceptorService { type Response = TlsStream; - type Error = io::Error; + type Error = TlsError; type Future = AcceptorServiceFut; fn poll_ready(&self, cx: &mut Context<'_>) -> Poll> { @@ -158,22 +178,31 @@ impl Service for AcceptorService { fn call(&self, req: T) -> Self::Future { AcceptorServiceFut { - _guard: self.conns.get(), fut: self.acceptor.accept(req), + timeout: sleep(self.handshake_timeout), + _guard: self.conns.get(), } } } -pub struct AcceptorServiceFut { - fut: Accept, - _guard: CounterGuard, +pin_project! { + pub struct AcceptorServiceFut { + fut: Accept, + #[pin] + timeout: Sleep, + _guard: CounterGuard, + } } impl Future for AcceptorServiceFut { - type Output = Result, io::Error>; + type Output = Result, TlsError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.get_mut(); - Pin::new(&mut this.fut).poll(cx).map_ok(TlsStream) + let mut this = self.project(); + match Pin::new(&mut this.fut).poll(cx) { + Poll::Ready(Ok(stream)) => Poll::Ready(Ok(TlsStream(stream))), + Poll::Ready(Err(err)) => Poll::Ready(Err(TlsError::Tls(err))), + Poll::Pending => this.timeout.poll(cx).map(|_| Err(TlsError::Timeout)), + } } } diff --git a/actix-tls/tests/accept-openssl.rs b/actix-tls/tests/accept-openssl.rs new file mode 100644 index 00000000..3d195b04 --- /dev/null +++ b/actix-tls/tests/accept-openssl.rs @@ -0,0 +1,130 @@ +//! Use Rustls connector to test OpenSSL acceptor. + +#![cfg(all( + feature = "accept", + feature = "connect", + feature = "rustls", + feature = "openssl" +))] + +use std::{convert::TryFrom, io::Write, sync::Arc}; + +use actix_rt::net::TcpStream; +use actix_server::TestServer; +use actix_service::ServiceFactoryExt as _; +use actix_tls::accept::openssl::{Acceptor, TlsStream}; +use actix_utils::future::ok; +use tokio_rustls::rustls::{Certificate, ClientConfig, RootCertStore, ServerName}; + +fn new_cert_and_key() -> (String, String) { + let cert = rcgen::generate_simple_self_signed(vec![ + "127.0.0.1".to_owned(), + "localhost".to_owned(), + ]) + .unwrap(); + + let key = cert.serialize_private_key_pem(); + let cert = cert.serialize_pem().unwrap(); + + (cert, key) +} + +fn openssl_acceptor(cert: String, key: String) -> tls_openssl::ssl::SslAcceptor { + use tls_openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslMethod}, + x509::X509, + }; + + let cert = X509::from_pem(cert.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key.as_bytes()).unwrap(); + + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + builder.set_alpn_select_callback(|_, _protocols| Ok(b"http/1.1")); + builder.set_alpn_protos(b"\x08http/1.1").unwrap(); + builder.build() +} + +#[allow(dead_code)] +mod danger { + use std::time::SystemTime; + + use super::*; + + use tokio_rustls::rustls::{ + self, + client::{ServerCertVerified, ServerCertVerifier}, + }; + + pub struct NoCertificateVerification; + + impl ServerCertVerifier for NoCertificateVerification { + fn verify_server_cert( + &self, + _end_entity: &Certificate, + _intermediates: &[Certificate], + _server_name: &ServerName, + _scts: &mut dyn Iterator, + _ocsp_response: &[u8], + _now: SystemTime, + ) -> Result { + Ok(ServerCertVerified::assertion()) + } + } +} + +#[allow(dead_code)] +fn rustls_connector(_cert: String, _key: String) -> ClientConfig { + let mut config = ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(RootCertStore::empty()) + .with_no_client_auth(); + + config + .dangerous() + .set_certificate_verifier(Arc::new(danger::NoCertificateVerification)); + + config.alpn_protocols = vec![b"http/1.1".to_vec()]; + config +} + +#[actix_rt::test] +async fn accepts_connections() { + let (cert, key) = new_cert_and_key(); + + let srv = TestServer::with({ + let cert = cert.clone(); + let key = key.clone(); + + move || { + let openssl_acceptor = openssl_acceptor(cert.clone(), key.clone()); + let tls_acceptor = Acceptor::new(openssl_acceptor); + + tls_acceptor + .map_err(|err| println!("OpenSSL error: {:?}", err)) + .and_then(move |_stream: TlsStream| ok(())) + } + }); + + let mut sock = srv + .connect() + .expect("cannot connect to test server") + .into_std() + .unwrap(); + sock.set_nonblocking(false).unwrap(); + + let config = rustls_connector(cert, key); + let config = Arc::new(config); + + let mut conn = tokio_rustls::rustls::ClientConnection::new( + config, + ServerName::try_from("localhost").unwrap(), + ) + .unwrap(); + + let mut stream = tokio_rustls::rustls::Stream::new(&mut conn, &mut sock); + + stream.flush().expect("TLS handshake failed"); +} diff --git a/actix-tls/tests/accept-rustls.rs b/actix-tls/tests/accept-rustls.rs new file mode 100644 index 00000000..a083ebba --- /dev/null +++ b/actix-tls/tests/accept-rustls.rs @@ -0,0 +1,104 @@ +//! Use OpenSSL connector to test Rustls acceptor. + +#![cfg(all( + feature = "accept", + feature = "connect", + feature = "rustls", + feature = "openssl" +))] + +use std::io::{BufReader, Write}; + +use actix_rt::net::TcpStream; +use actix_server::TestServer; +use actix_service::ServiceFactoryExt as _; +use actix_tls::accept::rustls::{Acceptor, TlsStream}; +use actix_tls::connect::tls::openssl::SslConnector; +use actix_utils::future::ok; +use rustls_pemfile::{certs, pkcs8_private_keys}; +use tls_openssl::ssl::SslVerifyMode; +use tokio_rustls::rustls::{self, Certificate, PrivateKey, ServerConfig}; + +fn new_cert_and_key() -> (String, String) { + let cert = rcgen::generate_simple_self_signed(vec![ + "127.0.0.1".to_owned(), + "localhost".to_owned(), + ]) + .unwrap(); + + let key = cert.serialize_private_key_pem(); + let cert = cert.serialize_pem().unwrap(); + + (cert, key) +} + +fn rustls_server_config(cert: String, key: String) -> rustls::ServerConfig { + // Load TLS key and cert files + + let cert = &mut BufReader::new(cert.as_bytes()); + let key = &mut BufReader::new(key.as_bytes()); + + let cert_chain = certs(cert).unwrap().into_iter().map(Certificate).collect(); + let mut keys = pkcs8_private_keys(key).unwrap(); + + let mut config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(cert_chain, PrivateKey(keys.remove(0))) + .unwrap(); + + config.alpn_protocols = vec![b"http/1.1".to_vec()]; + + config +} + +fn openssl_connector(cert: String, key: String) -> SslConnector { + use actix_tls::connect::tls::openssl::{SslConnector as OpensslConnector, SslMethod}; + use tls_openssl::{pkey::PKey, x509::X509}; + + let cert = X509::from_pem(cert.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key.as_bytes()).unwrap(); + + let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap(); + ssl.set_verify(SslVerifyMode::NONE); + ssl.set_certificate(&cert).unwrap(); + ssl.set_private_key(&key).unwrap(); + ssl.set_alpn_protos(b"\x08http/1.1").unwrap(); + + ssl.build() +} + +#[actix_rt::test] +async fn accepts_connections() { + let (cert, key) = new_cert_and_key(); + + let srv = TestServer::with({ + let cert = cert.clone(); + let key = key.clone(); + + move || { + let tls_acceptor = Acceptor::new(rustls_server_config(cert.clone(), key.clone())); + + tls_acceptor + .map_err(|err| println!("Rustls error: {:?}", err)) + .and_then(move |_stream: TlsStream| ok(())) + } + }); + + let sock = srv + .connect() + .expect("cannot connect to test server") + .into_std() + .unwrap(); + sock.set_nonblocking(false).unwrap(); + + let connector = openssl_connector(cert, key); + + let mut stream = connector + .connect("localhost", sock) + .expect("TLS handshake failed"); + + stream.do_handshake().expect("TLS handshake failed"); + + stream.flush().expect("TLS handshake failed"); +} diff --git a/actix-utils/src/counter.rs b/actix-utils/src/counter.rs index 7a87fa3d..51e0afae 100644 --- a/actix-utils/src/counter.rs +++ b/actix-utils/src/counter.rs @@ -26,7 +26,7 @@ impl Counter { CounterGuard::new(self.0.clone()) } - /// Notify current task and return true if counter is at capacity. + /// Returns true if counter is below capacity. Otherwise, register to wake task when it is. pub fn available(&self, cx: &mut task::Context<'_>) -> bool { self.0.available(cx) }