diff --git a/.travis.yml b/.travis.yml index a2321cdd..c815db85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,10 @@ script: if [[ "$TRAVIS_RUST_VERSION" != "nightly" ]]; then cargo clean cargo test --features="ssl,tls,rust-tls" -- --nocapture + cd actix-codec && cargo test cd actix-service && cargo test + cd actix-server && cargo test --features="ssl,tls,rust-tls" -- --nocapture + cd actix-rt && cargo test fi - | if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then diff --git a/Cargo.toml b/Cargo.toml index 574ec314..e7b40ec3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ members = [ "./", "actix-codec", "actix-service", + "actix-server", "actix-rt", ] @@ -36,15 +37,9 @@ path = "src/lib.rs" [features] default = [] -# tls -tls = ["native-tls"] - # openssl ssl = ["openssl", "tokio-openssl"] -# rustls -rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] - cell = [] [dependencies] @@ -70,18 +65,9 @@ tokio-signal = "0.2" trust-dns-proto = "^0.5.0" trust-dns-resolver = "^0.10.0" -# native-tls -native-tls = { version="0.2", optional = true } - # openssl openssl = { version="0.10", optional = true } -tokio-openssl = { version="0.2", optional = true } - -#rustls -rustls = { version = "^0.14", optional = true } -tokio-rustls = { version = "^0.8", optional = true } -webpki = { version = "0.18", optional = true } -webpki-roots = { version = "0.15", optional = true } +tokio-openssl = { version="0.3", optional = true } [dev-dependencies] env_logger = "0.5" diff --git a/actix-rt/CHANGES.md b/actix-rt/CHANGES.md index aefde3cd..14e1cde7 100644 --- a/actix-rt/CHANGES.md +++ b/actix-rt/CHANGES.md @@ -2,4 +2,4 @@ ## [0.1.0] - 2018-12-09 -* Move codec to separate crate +* Initial release diff --git a/actix-rt/src/arbiter.rs b/actix-rt/src/arbiter.rs index 36a5b9c6..fab71c64 100644 --- a/actix-rt/src/arbiter.rs +++ b/actix-rt/src/arbiter.rs @@ -1,7 +1,3 @@ -#![allow( - clippy::borrow_interior_mutable_const, - clippy::declare_interior_mutable_const -)] use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -21,7 +17,7 @@ thread_local!( static Q: RefCell>>> = RefCell::new(Vec::new()); ); -pub(crate) const COUNT: AtomicUsize = AtomicUsize::new(0); +pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0); pub(crate) enum ArbiterCommand { Stop, diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md new file mode 100644 index 00000000..953441ef --- /dev/null +++ b/actix-server/CHANGES.md @@ -0,0 +1,5 @@ +# Changes + +## [0.1.0] - 2018-12-09 + +* Move server to separate crate diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml new file mode 100644 index 00000000..0cb16ff3 --- /dev/null +++ b/actix-server/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "actix-server" +version = "0.1.0" +authors = ["Nikolay Kim "] +description = "Actix server - General purpose tcp server" +readme = "README.md" +keywords = ["network", "framework", "async", "futures"] +homepage = "https://actix.rs" +repository = "https://github.com/actix/actix-net.git" +documentation = "https://docs.rs/actix-server/" +categories = ["network-programming", "asynchronous"] +license = "MIT/Apache-2.0" +exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"] +edition = "2018" +workspace = "../" + +[package.metadata.docs.rs] +features = ["ssl", "tls", "rust-tls"] + +[lib] +name = "actix_server" +path = "src/lib.rs" + +[features] +default = [] + +# tls +tls = ["native-tls"] + +# openssl +ssl = ["openssl", "tokio-openssl"] + +# rustls +rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] + +[dependencies] +actix-service = "0.1.1" +actix-rt = { path = "../actix-rt" } + +log = "0.4" +num_cpus = "1.0" + +# io +mio = "^0.6.13" +net2 = "0.2" +bytes = "0.4" +futures = "0.1" +slab = "0.4" +tokio-io = "0.1" +tokio-tcp = "0.1" +tokio-timer = "0.2" +tokio-reactor = "0.1" +tokio-signal = "0.2" + +# native-tls +native-tls = { version="0.2", optional = true } + +# openssl +openssl = { version="0.10", optional = true } +tokio-openssl = { version="0.3", optional = true } + +#rustls +rustls = { version = "^0.14", optional = true } +tokio-rustls = { version = "^0.8", optional = true } +webpki = { version = "0.18", optional = true } +webpki-roots = { version = "0.15", optional = true } + +[dev-dependencies] +env_logger = "0.5" + +[profile.release] +lto = true +opt-level = 3 +codegen-units = 1 diff --git a/src/server/accept.rs b/actix-server/src/accept.rs similarity index 98% rename from src/server/accept.rs rename to actix-server/src/accept.rs index 9426a7e3..ca726501 100644 --- a/src/server/accept.rs +++ b/actix-server/src/accept.rs @@ -371,7 +371,7 @@ impl Accept { match self.workers[self.next].send(msg) { Ok(_) => (), Err(tmp) => { - let _ = self.srv.worker_died(self.workers[self.next].idx); + self.srv.worker_died(self.workers[self.next].idx); msg = tmp; self.workers.swap_remove(self.next); if self.workers.is_empty() { @@ -397,7 +397,7 @@ impl Accept { return; } Err(tmp) => { - let _ = self.srv.worker_died(self.workers[self.next].idx); + self.srv.worker_died(self.workers[self.next].idx); msg = tmp; self.workers.swap_remove(self.next); if self.workers.is_empty() { diff --git a/src/server/builder.rs b/actix-server/src/builder.rs similarity index 100% rename from src/server/builder.rs rename to actix-server/src/builder.rs diff --git a/src/server/config.rs b/actix-server/src/config.rs similarity index 100% rename from src/server/config.rs rename to actix-server/src/config.rs diff --git a/actix-server/src/counter.rs b/actix-server/src/counter.rs new file mode 100644 index 00000000..1302c91c --- /dev/null +++ b/actix-server/src/counter.rs @@ -0,0 +1,78 @@ +use std::cell::Cell; +use std::rc::Rc; + +use futures::task::AtomicTask; + +#[derive(Clone)] +/// Simple counter with ability to notify task on reaching specific number +/// +/// Counter could be cloned, total ncount is shared across all clones. +pub struct Counter(Rc); + +struct CounterInner { + count: Cell, + capacity: usize, + task: AtomicTask, +} + +impl Counter { + /// Create `Counter` instance and set max value. + pub fn new(capacity: usize) -> Self { + Counter(Rc::new(CounterInner { + capacity, + count: Cell::new(0), + task: AtomicTask::new(), + })) + } + + pub fn get(&self) -> CounterGuard { + CounterGuard::new(self.0.clone()) + } + + /// Check if counter is not at capacity + pub fn available(&self) -> bool { + self.0.available() + } + + /// Get total number of acquired counts + pub fn total(&self) -> usize { + self.0.count.get() + } +} + +pub struct CounterGuard(Rc); + +impl CounterGuard { + fn new(inner: Rc) -> Self { + inner.inc(); + CounterGuard(inner) + } +} + +impl Drop for CounterGuard { + fn drop(&mut self) { + self.0.dec(); + } +} + +impl CounterInner { + fn inc(&self) { + let num = self.count.get() + 1; + self.count.set(num); + if num == self.capacity { + self.task.register(); + } + } + + fn dec(&self) { + let num = self.count.get(); + self.count.set(num - 1); + if num == self.capacity { + self.task.notify(); + } + } + + fn available(&self) -> bool { + self.count.get() < self.capacity + } +} diff --git a/src/server/mod.rs b/actix-server/src/lib.rs similarity index 95% rename from src/server/mod.rs rename to actix-server/src/lib.rs index 4ceb8ddf..2485793c 100644 --- a/src/server/mod.rs +++ b/actix-server/src/lib.rs @@ -3,8 +3,10 @@ mod accept; mod builder; mod config; +mod counter; mod server; mod services; +pub mod ssl; mod worker; pub use self::builder::ServerBuilder; diff --git a/src/server/server.rs b/actix-server/src/server.rs similarity index 100% rename from src/server/server.rs rename to actix-server/src/server.rs diff --git a/src/server/services.rs b/actix-server/src/services.rs similarity index 100% rename from src/server/services.rs rename to actix-server/src/services.rs diff --git a/actix-server/src/ssl/mod.rs b/actix-server/src/ssl/mod.rs new file mode 100644 index 00000000..f91e2377 --- /dev/null +++ b/actix-server/src/ssl/mod.rs @@ -0,0 +1,35 @@ +//! SSL Services +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crate::counter::Counter; + +#[cfg(feature = "ssl")] +mod openssl; +#[cfg(feature = "ssl")] +pub use self::openssl::OpensslAcceptor; + +#[cfg(feature = "tls")] +mod nativetls; +#[cfg(feature = "tls")] +pub use self::nativetls::{NativeTlsAcceptor, TlsStream}; + +#[cfg(feature = "rust-tls")] +mod rustls; +#[cfg(feature = "rust-tls")] +pub use self::rustls::RustlsAcceptor; + +/// Sets the maximum per-worker concurrent ssl connection establish process. +/// +/// All listeners will stop accepting connections when this limit is +/// reached. It can be used to limit the global SSL CPU usage. +/// +/// By default max connections is set to a 256. +pub fn max_concurrent_ssl_connect(num: usize) { + MAX_CONN.store(num, Ordering::Relaxed); +} + +pub(crate) static MAX_CONN: AtomicUsize = AtomicUsize::new(256); + +thread_local! { + static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed)); +} diff --git a/src/ssl/nativetls.rs b/actix-server/src/ssl/nativetls.rs similarity index 99% rename from src/ssl/nativetls.rs rename to actix-server/src/ssl/nativetls.rs index a2c8c95d..76527bb3 100644 --- a/src/ssl/nativetls.rs +++ b/actix-server/src/ssl/nativetls.rs @@ -21,7 +21,7 @@ impl NativeTlsAcceptor { /// Create `NativeTlsAcceptor` instance pub fn new(acceptor: TlsAcceptor) -> Self { NativeTlsAcceptor { - acceptor: acceptor.into(), + acceptor, io: PhantomData, } } diff --git a/actix-server/src/ssl/openssl.rs b/actix-server/src/ssl/openssl.rs new file mode 100644 index 00000000..e45152e7 --- /dev/null +++ b/actix-server/src/ssl/openssl.rs @@ -0,0 +1,99 @@ +use std::marker::PhantomData; + +use actix_service::{NewService, Service}; +use futures::{future::ok, future::FutureResult, Async, Future, Poll}; +use openssl::ssl::{HandshakeError, SslAcceptor}; +use tokio_io::{AsyncRead, AsyncWrite}; +use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream}; + +use super::MAX_CONN_COUNTER; +use crate::counter::{Counter, CounterGuard}; + +/// Support `SSL` connections via openssl package +/// +/// `ssl` feature enables `OpensslAcceptor` type +pub struct OpensslAcceptor { + acceptor: SslAcceptor, + io: PhantomData, +} + +impl OpensslAcceptor { + /// Create default `OpensslAcceptor` + pub fn new(acceptor: SslAcceptor) -> Self { + OpensslAcceptor { + acceptor, + io: PhantomData, + } + } +} + +impl Clone for OpensslAcceptor { + fn clone(&self) -> Self { + Self { + acceptor: self.acceptor.clone(), + io: PhantomData, + } + } +} + +impl NewService for OpensslAcceptor { + type Response = SslStream; + type Error = HandshakeError; + type Service = OpensslAcceptorService; + type InitError = (); + type Future = FutureResult; + + fn new_service(&self) -> Self::Future { + MAX_CONN_COUNTER.with(|conns| { + ok(OpensslAcceptorService { + acceptor: self.acceptor.clone(), + conns: conns.clone(), + io: PhantomData, + }) + }) + } +} + +pub struct OpensslAcceptorService { + acceptor: SslAcceptor, + io: PhantomData, + conns: Counter, +} + +impl Service for OpensslAcceptorService { + type Response = SslStream; + type Error = HandshakeError; + type Future = OpensslAcceptorServiceFut; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + if self.conns.available() { + Ok(Async::Ready(())) + } else { + Ok(Async::NotReady) + } + } + + fn call(&mut self, req: T) -> Self::Future { + OpensslAcceptorServiceFut { + _guard: self.conns.get(), + fut: SslAcceptorExt::accept_async(&self.acceptor, req), + } + } +} + +pub struct OpensslAcceptorServiceFut +where + T: AsyncRead + AsyncWrite, +{ + fut: AcceptAsync, + _guard: CounterGuard, +} + +impl Future for OpensslAcceptorServiceFut { + type Item = SslStream; + type Error = HandshakeError; + + fn poll(&mut self) -> Poll { + self.fut.poll() + } +} diff --git a/src/ssl/rustls.rs b/actix-server/src/ssl/rustls.rs similarity index 100% rename from src/ssl/rustls.rs rename to actix-server/src/ssl/rustls.rs diff --git a/src/server/worker.rs b/actix-server/src/worker.rs similarity index 98% rename from src/server/worker.rs rename to actix-server/src/worker.rs index 0a944c7b..ec8934b9 100644 --- a/src/server/worker.rs +++ b/actix-server/src/worker.rs @@ -9,10 +9,10 @@ use futures::{future, Async, Future, Poll, Stream}; use log::{error, info, trace}; use tokio_timer::{sleep, Delay}; -use super::accept::AcceptNotify; -use super::services::{BoxedServerService, InternalServiceFactory, ServerMessage}; -use super::Token; +use crate::accept::AcceptNotify; use crate::counter::Counter; +use crate::services::{BoxedServerService, InternalServiceFactory, ServerMessage}; +use crate::Token; pub(crate) struct WorkerCommand(Conn); @@ -30,7 +30,7 @@ pub(crate) struct Conn { pub peer: Option, } -const MAX_CONNS: AtomicUsize = AtomicUsize::new(25600); +static MAX_CONNS: AtomicUsize = AtomicUsize::new(25600); /// Sets the maximum per-worker number of concurrent connections. /// diff --git a/src/lib.rs b/src/lib.rs index fa0fe04f..0e618c19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ pub mod framed; pub mod inflight; pub mod keepalive; pub mod resolver; -pub mod server; pub mod ssl; pub mod stream; pub mod time; diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 906ee615..ecbd0a88 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -1,35 +1,6 @@ //! SSL Services -use std::sync::atomic::{AtomicUsize, Ordering}; - -use super::counter::Counter; #[cfg(feature = "ssl")] mod openssl; #[cfg(feature = "ssl")] -pub use self::openssl::{OpensslAcceptor, OpensslConnector}; - -#[cfg(feature = "tls")] -mod nativetls; -#[cfg(feature = "tls")] -pub use self::nativetls::{NativeTlsAcceptor, TlsStream}; - -#[cfg(feature = "rust-tls")] -mod rustls; -#[cfg(feature = "rust-tls")] -pub use self::rustls::RustlsAcceptor; - -/// Sets the maximum per-worker concurrent ssl connection establish process. -/// -/// All listeners will stop accepting connections when this limit is -/// reached. It can be used to limit the global SSL CPU usage. -/// -/// By default max connections is set to a 256. -pub fn max_concurrent_ssl_connect(num: usize) { - MAX_CONN.store(num, Ordering::Relaxed); -} - -pub(crate) const MAX_CONN: AtomicUsize = AtomicUsize::new(256); - -thread_local! { - static MAX_CONN_COUNTER: Counter = Counter::new(MAX_CONN.load(Ordering::Relaxed)); -} +pub use self::openssl::OpensslConnector; diff --git a/src/ssl/openssl.rs b/src/ssl/openssl.rs index aea3f129..caaa18a5 100644 --- a/src/ssl/openssl.rs +++ b/src/ssl/openssl.rs @@ -10,95 +10,6 @@ use super::MAX_CONN_COUNTER; use crate::counter::{Counter, CounterGuard}; use crate::resolver::RequestHost; -/// Support `SSL` connections via openssl package -/// -/// `ssl` feature enables `OpensslAcceptor` type -pub struct OpensslAcceptor { - acceptor: SslAcceptor, - io: PhantomData, -} - -impl OpensslAcceptor { - /// Create default `OpensslAcceptor` - pub fn new(acceptor: SslAcceptor) -> Self { - OpensslAcceptor { - acceptor, - io: PhantomData, - } - } -} - -impl Clone for OpensslAcceptor { - fn clone(&self) -> Self { - Self { - acceptor: self.acceptor.clone(), - io: PhantomData, - } - } -} - -impl NewService for OpensslAcceptor { - type Response = SslStream; - type Error = Error; - type Service = OpensslAcceptorService; - type InitError = (); - type Future = FutureResult; - - fn new_service(&self) -> Self::Future { - MAX_CONN_COUNTER.with(|conns| { - ok(OpensslAcceptorService { - acceptor: self.acceptor.clone(), - conns: conns.clone(), - io: PhantomData, - }) - }) - } -} - -pub struct OpensslAcceptorService { - acceptor: SslAcceptor, - io: PhantomData, - conns: Counter, -} - -impl Service for OpensslAcceptorService { - type Response = SslStream; - type Error = Error; - type Future = OpensslAcceptorServiceFut; - - fn poll_ready(&mut self) -> Poll<(), Self::Error> { - if self.conns.available() { - Ok(Async::Ready(())) - } else { - Ok(Async::NotReady) - } - } - - fn call(&mut self, req: T) -> Self::Future { - OpensslAcceptorServiceFut { - _guard: self.conns.get(), - fut: SslAcceptorExt::accept_async(&self.acceptor, req), - } - } -} - -pub struct OpensslAcceptorServiceFut -where - T: AsyncRead + AsyncWrite, -{ - fut: AcceptAsync, - _guard: CounterGuard, -} - -impl Future for OpensslAcceptorServiceFut { - type Item = SslStream; - type Error = Error; - - fn poll(&mut self) -> Poll { - self.fut.poll() - } -} - /// Openssl connector factory pub struct OpensslConnector { connector: SslConnector,