mod engine;
mod source;
use std::fmt;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::{Duration, Instant};
use crate::control::ControlLine;
use crate::driver::DriverKind;
use crate::error::{CloseReason, ConfigReason, KillReason, NetError, RefusalCause};
use crate::events::{EventSink, NoopSink};
use crate::gate::Gate;
use crate::id::{ConnectionId, WorkerId};
use crate::limits::Limits;
use crate::opts::ListenOptions;
use crate::session::SessionFactory;
use crate::tcp::{ListenerInfo, TcpConnection};
use crate::time::Clock;
use crate::tls::{NoTls, TlsAcceptor};
pub(crate) use engine::Shared;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DoorState {
Open,
Closed,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DrainReport {
pub graceful: u32,
pub killed: u32,
pub took: Duration,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Stats {
pub open: u64,
pub accepted: u64,
pub refused: u64,
pub closed: u64,
pub bytes_in: u64,
pub bytes_out: u64,
pub egress_denied: u64,
pub killed: u64,
pub slow_peers: u64,
pub timeouts: u64,
pub descriptor_pressure: u64,
pub stale_completions: u64,
pub session_panics: u64,
refused_by: [u64; RefusalCause::COUNT],
closed_by: [u64; CloseReason::COUNT],
}
impl Stats {
#[must_use]
pub fn refused_for(&self, cause: RefusalCause) -> u64 {
self.refused_by[cause.index()]
}
#[must_use]
pub fn closed_for(&self, reason: CloseReason) -> u64 {
self.closed_by[reason.index()]
}
}
#[must_use]
#[derive(Debug)]
pub struct ListenerSpec {
pub(crate) addrs: Result<Vec<SocketAddr>, String>,
pub(crate) options: Option<ListenOptions>,
pub(crate) name: Option<String>,
pub(crate) limits: Limits,
}
impl ListenerSpec {
pub fn tcp<A: ToSocketAddrs>(addr: A) -> ListenerSpec {
ListenerSpec {
addrs: addr
.to_socket_addrs()
.map(|i| i.collect())
.map_err(|e| e.to_string()),
options: None,
name: None,
limits: Limits::default(),
}
}
pub fn tcp_with<A: ToSocketAddrs>(addr: A, options: ListenOptions) -> ListenerSpec {
ListenerSpec {
options: Some(options),
..ListenerSpec::tcp(addr)
}
}
pub fn name(mut self, name: &str) -> ListenerSpec {
self.name = Some(name.to_owned());
self
}
pub fn limits(mut self, limits: Limits) -> ListenerSpec {
self.limits = limits;
self
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct NoWork;
#[derive(Clone, Copy, Debug, Default)]
pub struct NoGate;
#[derive(Debug)]
pub struct Sessions<F> {
pub(crate) factory: F,
}
pub struct BlockingHandler<H> {
pub(crate) handler: H,
}
impl<H> fmt::Debug for BlockingHandler<H> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("BlockingHandler")
}
}
pub(crate) mod sealed {
pub trait Sealed {}
}
pub trait Workload: sealed::Sealed + engine::Serve + Send + Sync + 'static {}
impl<F: SessionFactory> sealed::Sealed for Sessions<F> {}
impl<F: SessionFactory> Workload for Sessions<F> {}
impl<H> sealed::Sealed for BlockingHandler<H> where
H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
{
}
impl<H> Workload for BlockingHandler<H> where
H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
{
}
#[must_use]
pub struct ServerBuilder<W = NoWork, G = NoGate, S = NoopSink, T = NoTls> {
listeners: Vec<ListenerSpec>,
driver: DriverKind,
workers: Option<u16>,
limits: Limits,
work: W,
gate: G,
sink: S,
tls: T,
control: Option<Arc<dyn ControlLine>>,
wipe: bool,
clock: Option<Arc<dyn Clock>>,
}
impl ServerBuilder {
pub fn new() -> ServerBuilder {
ServerBuilder {
listeners: Vec::new(),
driver: DriverKind::Auto,
workers: None,
limits: Limits::default(),
work: NoWork,
gate: NoGate,
sink: NoopSink,
tls: NoTls,
control: None,
wipe: true,
clock: None,
}
}
}
impl Default for ServerBuilder {
fn default() -> ServerBuilder {
ServerBuilder::new()
}
}
impl<W, G, S, T> ServerBuilder<W, G, S, T> {
fn map<W2, G2, S2, T2>(
self,
f: impl FnOnce(W, G, S, T) -> (W2, G2, S2, T2),
) -> ServerBuilder<W2, G2, S2, T2> {
let ServerBuilder {
listeners,
driver,
workers,
limits,
work,
gate,
sink,
tls,
control,
wipe,
clock,
} = self;
let (work, gate, sink, tls) = f(work, gate, sink, tls);
ServerBuilder {
listeners,
driver,
workers,
limits,
work,
gate,
sink,
tls,
control,
wipe,
clock,
}
}
pub fn listener(mut self, spec: ListenerSpec) -> Self {
self.listeners.push(spec);
self
}
pub fn driver(mut self, kind: DriverKind) -> Self {
self.driver = kind;
self
}
pub fn workers(mut self, n: u16) -> Self {
self.workers = Some(n);
self
}
pub fn limits(mut self, limits: Limits) -> Self {
self.limits = limits;
self
}
pub fn sessions<F: SessionFactory>(self, factory: F) -> ServerBuilder<Sessions<F>, G, S, T> {
self.map(|_, g, s, t| (Sessions { factory }, g, s, t))
}
pub fn handler<H>(self, handler: H) -> ServerBuilder<BlockingHandler<H>, G, S, T>
where
H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static,
{
self.map(|_, g, s, t| (BlockingHandler { handler }, g, s, t))
}
pub fn gate<G2: Gate>(self, gate: G2) -> ServerBuilder<W, G2, S, T> {
self.map(|w, _, s, t| (w, gate, s, t))
}
pub fn events<S2: EventSink>(self, sink: S2) -> ServerBuilder<W, G, S2, T> {
self.map(|w, g, _, t| (w, g, sink, t))
}
pub fn control<C: ControlLine>(mut self, line: Arc<C>) -> Self {
self.control = Some(line);
self
}
pub fn wipe_buffers(mut self, on: bool) -> Self {
self.wipe = on;
self
}
pub fn clock<K: Clock>(mut self, clock: Arc<K>) -> Self {
self.clock = Some(clock);
self
}
}
impl<W, G, S, T> ServerBuilder<W, G, S, T>
where
W: Workload,
G: Gate,
S: EventSink,
T: TlsAcceptor,
{
pub fn build(self) -> Result<Server, NetError> {
let driver = match self.driver.resolve() {
DriverKind::Blocking => DriverKind::Blocking,
other => {
return Err(NetError::Unsupported {
feature: match other {
DriverKind::Uring => "the io_uring driver (after 1.0.0)",
_ => "the reactor driver (0.5.0)",
},
platform: std::env::consts::OS,
});
}
};
if self.listeners.is_empty() {
return Err(invalid("listener", ConfigReason::Missing));
}
if self.listeners.len() > 64 {
return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
}
let workers = self.workers.unwrap_or(128);
if workers == 0 {
return Err(invalid("workers", ConfigReason::Zero));
}
if workers > 4096 {
return Err(invalid("workers", ConfigReason::TooLarge { max: 4096 }));
}
let mut names = Vec::new();
for spec in &self.listeners {
if let Some(n) = &spec.name {
if n.len() > 64 {
return Err(invalid("name", ConfigReason::TooLarge { max: 64 }));
}
if names.contains(n) {
return Err(invalid("name", ConfigReason::Inconsistent));
}
names.push(n.clone());
}
}
let limits = if self.limits.max_connections().is_none() {
self.limits
.to_builder()
.max_connections(u32::from(workers))
.build()?
} else {
self.limits.clone()
};
limits.validate(workers, crate::sys::descriptor_limit())?;
for spec in &self.listeners {
limits.overlay(&spec.limits).validate(workers, None)?;
}
let _ = &self.tls;
engine::start(engine::Config {
listeners: self.listeners,
driver,
workers,
limits,
work: self.work,
gate: self.gate,
sink: self.sink,
control: self.control,
wipe: self.wipe,
clock: self.clock,
})
}
}
fn invalid(field: &'static str, reason: ConfigReason) -> NetError {
NetError::InvalidConfig { field, reason }
}
#[must_use = "dropping a Server stops it; call wait_for_stop() to run until a stop is requested"]
pub struct Server {
pub(crate) shared: Arc<Shared>,
pub(crate) threads: Vec<JoinHandle<()>>,
pub(crate) listeners: Vec<ListenerInfo>,
pub(crate) stopped: bool,
}
impl Server {
pub fn open_door(&self) -> Result<(), NetError> {
self.shared.open_door()
}
pub fn close_door(&self) {
self.shared.close_door();
}
#[must_use]
pub fn door(&self) -> DoorState {
self.shared.door()
}
pub fn drain(&self, deadline: Instant) -> DrainReport {
self.shared.drain(deadline)
}
pub fn shutdown(mut self, deadline: Instant) -> DrainReport {
self.stop(deadline)
}
pub fn wait_for_stop(mut self) -> DrainReport {
let deadline = self.shared.wait_for_stop_request();
self.stop(deadline)
}
fn stop(&mut self, deadline: Instant) -> DrainReport {
if self.stopped {
return DrainReport {
graceful: 0,
killed: 0,
took: Duration::ZERO,
};
}
self.stopped = true;
let report = self.shared.drain(deadline);
self.shared.stop_threads();
for t in self.threads.drain(..) {
let _ = t.join();
}
report
}
#[must_use]
pub fn handle(&self) -> ServerHandle {
ServerHandle {
shared: self.shared.clone(),
}
}
#[must_use]
pub fn stats(&self) -> Stats {
self.shared.stats()
}
#[must_use]
pub fn listeners(&self) -> &[ListenerInfo] {
&self.listeners
}
}
impl Drop for Server {
fn drop(&mut self) {
let deadline = Instant::now() + self.shared.drain_timeout;
self.stop(deadline);
}
}
impl fmt::Debug for Server {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Server")
.field("listeners", &self.listeners)
.field("door", &self.door())
.finish()
}
}
#[derive(Clone)]
pub struct ServerHandle {
pub(crate) shared: Arc<Shared>,
}
impl ServerHandle {
pub fn kill(&self, id: ConnectionId, reason: KillReason) -> bool {
self.shared.kill(id, reason)
}
pub fn close_door(&self) {
self.shared.close_door();
}
pub fn request_stop(&self) {
self.shared.request_stop(None);
}
pub fn wake_all(&self) {
self.shared.wake_all();
}
#[must_use]
pub fn completer(&self, worker: WorkerId) -> Option<crate::completer::Completer> {
self.shared.completer(worker)
}
#[must_use]
pub fn stats(&self) -> Stats {
self.shared.stats()
}
#[must_use]
pub fn door(&self) -> DoorState {
self.shared.door()
}
}
impl fmt::Debug for ServerHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ServerHandle")
.field("door", &self.door())
.finish()
}
}
impl Stats {
pub(crate) fn from_parts(
mut base: Stats,
refused_by: [u64; RefusalCause::COUNT],
closed_by: [u64; CloseReason::COUNT],
) -> Stats {
base.refused_by = refused_by;
base.closed_by = closed_by;
base
}
}