Skip to main content

net_io/server/
mod.rs

1//! The server: listeners, workers, the door, drain, and shutdown.
2
3mod engine;
4#[cfg(feature = "reactor")]
5mod reactor;
6mod source;
7
8use std::any::TypeId;
9use std::fmt;
10use std::net::{SocketAddr, ToSocketAddrs};
11use std::path::PathBuf;
12use std::sync::Arc;
13use std::thread::JoinHandle;
14use std::time::{Duration, Instant};
15
16use crate::control::ControlLine;
17use crate::driver::DriverKind;
18use crate::error::{CloseReason, ConfigReason, KillReason, NetError, RefusalCause};
19use crate::events::{EventSink, NoopSink};
20use crate::gate::Gate;
21use crate::handoff::ListenerHandle;
22use crate::id::{ConnectionId, ListenerId, WorkerId};
23use crate::limits::Limits;
24use crate::opts::{ListenOptions, LocalOptions};
25use crate::proxy::ProxyMode;
26use crate::session::SessionFactory;
27use crate::tcp::{ListenerInfo, TcpConnection};
28use crate::time::Clock;
29use crate::tls::ErasedAcceptor;
30use crate::tls::{NoTls, TlsAcceptor};
31use crate::trusted::TrustedProxies;
32
33pub(crate) use engine::Shared;
34
35/// Whether the server is accepting.
36///
37/// ```
38/// assert_ne!(net_io::DoorState::Open, net_io::DoorState::Closed);
39/// ```
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum DoorState {
42    /// Accepting new connections.
43    Open,
44    /// Not accepting; listening sockets stay open.
45    Closed,
46}
47
48/// What a drain did.
49///
50/// ```
51/// let r = net_io::DrainReport { graceful: 3, killed: 1, took: std::time::Duration::from_millis(40) };
52/// assert_eq!(r.graceful + r.killed, 4);
53/// ```
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub struct DrainReport {
56    /// Connections that finished before the deadline.
57    pub graceful: u32,
58    /// Connections killed at the deadline.
59    pub killed: u32,
60    /// How long the drain took.
61    pub took: Duration,
62}
63
64/// Counters summed over the workers.
65///
66/// ```no_run
67/// let server = net_io::serve("127.0.0.1:0", |_c| Ok(()))?;
68/// let stats = server.stats();
69/// println!("{} open, {} accepted", stats.open, stats.accepted);
70/// # Ok::<(), net_io::NetError>(())
71/// ```
72#[non_exhaustive]
73#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
74pub struct Stats {
75    /// Connections open now.
76    pub open: u64,
77    /// Connections accepted.
78    pub accepted: u64,
79    /// Connections refused.
80    pub refused: u64,
81    /// Connections closed.
82    pub closed: u64,
83    /// Bytes received.
84    pub bytes_in: u64,
85    /// Bytes sent.
86    pub bytes_out: u64,
87    /// Writes the gate denied.
88    pub egress_denied: u64,
89    /// Connections killed.
90    pub killed: u64,
91    /// Connections closed for the minimum rate.
92    pub slow_peers: u64,
93    /// Connections closed by a timeout.
94    pub timeouts: u64,
95    /// Times the process ran out of descriptors.
96    pub descriptor_pressure: u64,
97    /// Completions for connections that had closed.
98    pub stale_completions: u64,
99    /// Sessions that panicked.
100    pub session_panics: u64,
101    refused_by: [u64; RefusalCause::COUNT],
102    closed_by: [u64; CloseReason::COUNT],
103}
104
105impl Stats {
106    /// Refusals with this cause (gate codes summed).
107    #[must_use]
108    pub fn refused_for(&self, cause: RefusalCause) -> u64 {
109        self.refused_by[cause.index()]
110    }
111
112    /// Closes with this reason's variant (inner values ignored).
113    #[must_use]
114    pub fn closed_for(&self, reason: CloseReason) -> u64 {
115        self.closed_by[reason.index()]
116    }
117
118    /// Every close reason with a non-zero count, one entry per variant (inner
119    /// values are not kept: `Killed` carries reason 0, `Io` class `Other(0)`).
120    ///
121    /// ```no_run
122    /// let server = net_io::serve("127.0.0.1:0", |_c| Ok(()))?;
123    /// for (reason, n) in server.stats().closes() {
124    ///     println!("{}: {n}", reason.as_str());
125    /// }
126    /// # Ok::<(), net_io::NetError>(())
127    /// ```
128    pub fn closes(&self) -> impl Iterator<Item = (CloseReason, u64)> + '_ {
129        CloseReason::BY_INDEX
130            .iter()
131            .zip(self.closed_by.iter())
132            .filter(|(_, n)| **n > 0)
133            .map(|(r, n)| (*r, *n))
134    }
135
136    /// Every refusal cause with a non-zero count (gate codes summed under `Gate(0)`).
137    pub fn refusals(&self) -> impl Iterator<Item = (RefusalCause, u64)> + '_ {
138        RefusalCause::BY_INDEX
139            .iter()
140            .zip(self.refused_by.iter())
141            .filter(|(_, n)| **n > 0)
142            .map(|(r, n)| (*r, *n))
143    }
144}
145
146/// One listener of a server.
147///
148/// ```
149/// use net_io::{ListenerSpec, Limits};
150/// let spec = ListenerSpec::tcp("127.0.0.1:0")
151///     .name("admin")
152///     .limits(Limits::builder().max_per_listener(10).build()?);
153/// # let _ = spec;
154/// # Ok::<(), net_io::NetError>(())
155/// ```
156#[must_use]
157#[derive(Debug)]
158pub struct ListenerSpec {
159    pub(crate) addrs: Result<Vec<SocketAddr>, String>,
160    pub(crate) options: Option<ListenOptions>,
161    pub(crate) name: Option<String>,
162    pub(crate) limits: Limits,
163    pub(crate) proxy: ProxyMode,
164    pub(crate) trusted: Option<Arc<TrustedProxies>>,
165    pub(crate) tls: bool,
166    pub(crate) unix: Option<(PathBuf, LocalOptions)>,
167    #[cfg(all(windows, feature = "local"))]
168    pub(crate) pipe: Option<(String, crate::pipe::PipeOptions)>,
169    #[cfg(feature = "udp")]
170    pub(crate) udp: Option<crate::udp::UdpOptions>,
171    pub(crate) adopt: Option<ListenerHandle>,
172    pub(crate) lockdown_allowed: bool,
173}
174
175impl ListenerSpec {
176    /// A TCP listener on `addr` (resolved now; a failure is reported by `build`).
177    pub fn tcp<A: ToSocketAddrs>(addr: A) -> ListenerSpec {
178        ListenerSpec {
179            addrs: addr
180                .to_socket_addrs()
181                .map(|i| i.collect())
182                .map_err(|e| e.to_string()),
183            options: None,
184            name: None,
185            limits: Limits::default(),
186            proxy: ProxyMode::Off,
187            trusted: None,
188            tls: false,
189            unix: None,
190            #[cfg(all(windows, feature = "local"))]
191            pipe: None,
192            #[cfg(feature = "udp")]
193            udp: None,
194            adopt: None,
195            lockdown_allowed: false,
196        }
197    }
198
199    /// Keeps admitting under `ControlState::Lockdown`, for the listener an operator
200    /// comes in through while everything else is refused.
201    pub fn lockdown_allowed(mut self, on: bool) -> ListenerSpec {
202        self.lockdown_allowed = on;
203        self
204    }
205
206    /// A TCP listener with explicit options (their backlog wins over the limits').
207    pub fn tcp_with<A: ToSocketAddrs>(addr: A, options: ListenOptions) -> ListenerSpec {
208        ListenerSpec {
209            options: Some(options),
210            ..ListenerSpec::tcp(addr)
211        }
212    }
213
214    /// A UDP socket served by the [`UdpSession`](crate::UdpSession) that
215    /// `ServerBuilder::udp_sessions` makes (feature `udp`). A thread of its own reads
216    /// it, with the door and a stop like any listener, and the socket's budgets and
217    /// amplification guard apply.
218    ///
219    /// ```
220    /// use net_io::{ListenerSpec, UdpOptions};
221    /// let spec = ListenerSpec::udp("0.0.0.0:5353", UdpOptions::new());
222    /// # let _ = spec;
223    /// ```
224    #[cfg(feature = "udp")]
225    pub fn udp<A: ToSocketAddrs>(addr: A, options: crate::udp::UdpOptions) -> ListenerSpec {
226        ListenerSpec {
227            udp: Some(options),
228            ..ListenerSpec::tcp(addr)
229        }
230    }
231
232    /// A named pipe listener on `\\\\.\\pipe\\<name>` (feature `local`, Windows).
233    /// Remote clients are always rejected, and connections carry `Transport::Pipe`,
234    /// the client's pid, and no IP address: the per-source cap does not apply. With
235    /// `proxy`, every peer is trusted: the pipe's security decides who may connect.
236    ///
237    /// ```no_run
238    /// use net_io::{ListenerSpec, PipeOptions};
239    /// let spec = ListenerSpec::pipe("myapp-control", PipeOptions::new());
240    /// # let _ = spec;
241    /// ```
242    #[cfg(all(windows, feature = "local"))]
243    pub fn pipe(name: &str, options: crate::pipe::PipeOptions) -> ListenerSpec {
244        ListenerSpec {
245            pipe: Some((name.to_owned(), options)),
246            ..ListenerSpec::tcp(std::net::SocketAddr::from(([127, 0, 0, 1], 0)))
247        }
248    }
249
250    /// A Unix domain socket listener at `path` (feature `local`; on Windows, AF_UNIX,
251    /// where NTFS ACLs replace `options`' mode and owner). The socket file gets
252    /// `options`' mode and owner before it listens, and is removed at shutdown if it
253    /// is still the file this server created. Connections carry `Transport::Unix`, the peer's
254    /// credentials, and no IP address: the per-source cap does not apply, and a
255    /// `BlockingHandler` receives them as a `TcpConnection` whose `peer_addr` is
256    /// unspecified. With `proxy`, every peer is trusted: the socket file's
257    /// permissions decide who may connect.
258    ///
259    /// ```
260    /// use net_io::{ListenerSpec, LocalOptions};
261    /// let spec = ListenerSpec::unix("/run/myapp/api.sock", LocalOptions::new().group_access(33));
262    /// # let _ = spec;
263    /// ```
264    pub fn unix(path: impl Into<PathBuf>, options: LocalOptions) -> ListenerSpec {
265        ListenerSpec {
266            addrs: Ok(Vec::new()),
267            options: None,
268            name: None,
269            limits: Limits::default(),
270            proxy: ProxyMode::Off,
271            trusted: None,
272            tls: false,
273            unix: Some((path.into(), options)),
274            lockdown_allowed: false,
275            #[cfg(all(windows, feature = "local"))]
276            pipe: None,
277            #[cfg(feature = "udp")]
278            udp: None,
279            adopt: None,
280        }
281    }
282
283    /// A listener this process was given: inherited from systemd or a FastCGI
284    /// manager, received in a hand-off, or released by another server. Its name
285    /// is the handle's unless [`ListenerSpec::name`] sets one. The socket is not
286    /// bound again; options set at bind time stay as they are, and the backlog is
287    /// reported as unknown. An adopted Unix socket's file is left in place at
288    /// shutdown (the next bind removes it as stale).
289    ///
290    /// ```no_run
291    /// use net_io::ListenerSpec;
292    /// for inherited in net_io::systemd()? {
293    ///     let spec = ListenerSpec::adopt(inherited.handle);
294    ///     # let _ = spec;
295    /// }
296    /// # Ok::<(), net_io::InheritError>(())
297    /// ```
298    pub fn adopt(handle: ListenerHandle) -> ListenerSpec {
299        ListenerSpec {
300            addrs: Ok(Vec::new()),
301            options: None,
302            name: None,
303            limits: Limits::default(),
304            proxy: ProxyMode::Off,
305            trusted: None,
306            tls: false,
307            unix: None,
308            #[cfg(all(windows, feature = "local"))]
309            pipe: None,
310            #[cfg(feature = "udp")]
311            udp: None,
312            adopt: Some(handle),
313            lockdown_allowed: false,
314        }
315    }
316
317    /// A name (up to 64 bytes) for events and hand-off.
318    pub fn name(mut self, name: &str) -> ListenerSpec {
319        self.name = Some(name.to_owned());
320        self
321    }
322
323    /// Per-listener caps and deadlines; values set here override the server's.
324    pub fn limits(mut self, limits: Limits) -> ListenerSpec {
325        self.limits = limits;
326        self
327    }
328
329    /// Requires a PROXY protocol header on every connection (feature `proxy`).
330    /// Peers outside the trusted proxies are closed before any byte is read.
331    ///
332    /// ```
333    /// use net_io::{ListenerSpec, ProxyMode, ProxyVersions};
334    /// let spec = ListenerSpec::tcp("127.0.0.1:0").proxy(ProxyMode::Required { versions: ProxyVersions::Both });
335    /// # let _ = spec;
336    /// ```
337    pub fn proxy(mut self, mode: ProxyMode) -> ListenerSpec {
338        self.proxy = mode;
339        self
340    }
341
342    /// Serves TLS on this listener through the builder's acceptor
343    /// ([`ServerBuilder::tls`], feature `tls`).
344    pub fn tls(mut self, on: bool) -> ListenerSpec {
345        self.tls = on;
346        self
347    }
348
349    /// The proxies trusted on this listener, instead of the server's list.
350    pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> ListenerSpec {
351        self.trusted = Some(Arc::new(proxies));
352        self
353    }
354}
355
356/// What runs per connection; the unset state (no `build` exists for it).
357#[derive(Clone, Copy, Debug, Default)]
358pub struct NoWork;
359
360/// What `ServerBuilder::udp_sessions` produces when a server has no TCP work; programs
361/// never name it.
362#[cfg(feature = "udp")]
363#[derive(Debug)]
364pub struct UdpOnly;
365
366/// The unset gate (no `build` exists for it): name `AllowAll` to run without a gate.
367#[derive(Clone, Copy, Debug, Default)]
368pub struct NoGate;
369
370/// Where workers run.
371///
372/// ```
373/// let pinned = net_io::Placement::Explicit(vec![0, 2, 4, 6]);
374/// # let _ = pinned;
375/// ```
376#[non_exhaustive]
377#[derive(Clone, Debug, Default, PartialEq, Eq)]
378pub enum Placement {
379    /// The OS decides.
380    #[default]
381    Off,
382    /// Worker `n` on CPU `n`, wrapping around.
383    PinPerCore,
384    /// Worker `n` on `cpus[n % cpus.len()]`.
385    Explicit(Vec<usize>),
386}
387
388/// What `ServerBuilder::sessions` produces; programs never name it.
389#[derive(Debug)]
390pub struct Sessions<F> {
391    pub(crate) factory: F,
392}
393
394#[cfg(feature = "reactor")]
395impl<F> Sessions<F> {
396    pub(crate) fn factory(&self) -> &F {
397        &self.factory
398    }
399}
400
401/// What `ServerBuilder::handler` produces; programs never name it.
402pub struct BlockingHandler<H> {
403    pub(crate) handler: H,
404}
405
406impl<H> fmt::Debug for BlockingHandler<H> {
407    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408        f.write_str("BlockingHandler")
409    }
410}
411
412pub(crate) mod sealed {
413    pub trait Sealed {}
414}
415
416/// What runs per connection: [`Sessions`] or a [`BlockingHandler`]. Sealed.
417pub trait Workload: sealed::Sealed + engine::Serve + Send + Sync + 'static {}
418
419#[cfg(feature = "udp")]
420impl sealed::Sealed for UdpOnly {}
421#[cfg(feature = "udp")]
422impl Workload for UdpOnly {}
423
424impl<F: SessionFactory> sealed::Sealed for Sessions<F> {}
425impl<F: SessionFactory> Workload for Sessions<F> {}
426
427impl<H> sealed::Sealed for BlockingHandler<H> where
428    H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
429{
430}
431impl<H> Workload for BlockingHandler<H> where
432    H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
433{
434}
435
436/// Builds a [`Server`]. A builder without a gate or without `sessions`/`handler`
437/// has no `build` method: forgetting either is a compile error.
438///
439/// # Examples
440///
441/// ```no_run
442/// use net_io::{AllowAll, DriverKind, Limits, ListenerSpec, ServerBuilder};
443/// use std::time::{Duration, Instant};
444///
445/// let server = ServerBuilder::new()
446///     .listener(ListenerSpec::tcp("0.0.0.0:8080").name("public"))
447///     .listener(ListenerSpec::tcp("127.0.0.1:9090").name("admin"))
448///     .driver(DriverKind::Blocking)
449///     .workers(64)
450///     .limits(Limits::builder().idle_timeout(Duration::from_secs(5)).build()?)
451///     .handler(|conn| { conn.send_all(b"hello\n")?; Ok(()) })
452///     .gate(AllowAll)
453///     .build()?;              // listeners bound, workers started, door closed
454/// // ... drop privileges here ...
455/// server.open_door()?;
456/// let report = server.shutdown(Instant::now() + Duration::from_secs(30));
457/// println!("{report:?}");
458/// # Ok::<(), net_io::NetError>(())
459/// ```
460#[must_use]
461pub struct ServerBuilder<W = NoWork, G = NoGate, S = NoopSink, T = NoTls> {
462    listeners: Vec<ListenerSpec>,
463    driver: DriverKind,
464    workers: Option<u16>,
465    limits: Limits,
466    work: W,
467    gate: G,
468    sink: S,
469    tls: T,
470    control: Option<Arc<dyn ControlLine>>,
471    wipe: bool,
472    clock: Option<Arc<dyn Clock>>,
473    trusted: Option<Arc<TrustedProxies>>,
474    placement: Placement,
475    #[cfg(feature = "udp")]
476    udp: Option<Arc<dyn crate::udp::UdpSessionFactory>>,
477}
478
479impl ServerBuilder {
480    /// An empty builder.
481    pub fn new() -> ServerBuilder {
482        ServerBuilder {
483            listeners: Vec::new(),
484            driver: DriverKind::Auto,
485            workers: None,
486            limits: Limits::default(),
487            work: NoWork,
488            gate: NoGate,
489            sink: NoopSink,
490            tls: NoTls,
491            control: None,
492            wipe: true,
493            clock: None,
494            trusted: None,
495            placement: Placement::Off,
496            #[cfg(feature = "udp")]
497            udp: None,
498        }
499    }
500}
501
502impl Default for ServerBuilder {
503    fn default() -> ServerBuilder {
504        ServerBuilder::new()
505    }
506}
507
508impl<W, G, S, T> ServerBuilder<W, G, S, T> {
509    fn map<W2, G2, S2, T2>(
510        self,
511        f: impl FnOnce(W, G, S, T) -> (W2, G2, S2, T2),
512    ) -> ServerBuilder<W2, G2, S2, T2> {
513        let ServerBuilder {
514            listeners,
515            driver,
516            workers,
517            limits,
518            work,
519            gate,
520            sink,
521            tls,
522            control,
523            wipe,
524            clock,
525            trusted,
526            placement,
527            #[cfg(feature = "udp")]
528            udp,
529        } = self;
530        let (work, gate, sink, tls) = f(work, gate, sink, tls);
531        ServerBuilder {
532            listeners,
533            driver,
534            workers,
535            limits,
536            work,
537            gate,
538            sink,
539            tls,
540            control,
541            wipe,
542            clock,
543            trusted,
544            placement,
545            #[cfg(feature = "udp")]
546            udp,
547        }
548    }
549
550    /// The proxies whose PROXY headers are believed, for every listener that
551    /// requires one and has no list of its own.
552    pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> Self {
553        self.trusted = Some(Arc::new(proxies));
554        self
555    }
556
557    /// Adds a listener (at most 64).
558    pub fn listener(mut self, spec: ListenerSpec) -> Self {
559        self.listeners.push(spec);
560        self
561    }
562
563    /// The driver (default `Auto`).
564    pub fn driver(mut self, kind: DriverKind) -> Self {
565        self.driver = kind;
566        self
567    }
568
569    /// Pins workers to CPUs (`Unsupported` on macOS). A worker that stays on one CPU
570    /// keeps its cache; the cost is that the OS can no longer move it off a busy CPU.
571    pub fn placement(mut self, placement: Placement) -> Self {
572        self.placement = placement;
573        self
574    }
575
576    /// Worker threads (default 128 on the blocking driver; 1 to 4,096).
577    pub fn workers(mut self, n: u16) -> Self {
578        self.workers = Some(n);
579        self
580    }
581
582    /// The server's limits; unset values take the driver's defaults.
583    pub fn limits(mut self, limits: Limits) -> Self {
584        self.limits = limits;
585        self
586    }
587
588    /// Runs a sans-IO session per connection.
589    pub fn sessions<F: SessionFactory>(self, factory: F) -> ServerBuilder<Sessions<F>, G, S, T> {
590        self.map(|_, g, s, t| (Sessions { factory }, g, s, t))
591    }
592
593    /// Runs a blocking handler per connection (on the blocking driver).
594    pub fn handler<H>(self, handler: H) -> ServerBuilder<BlockingHandler<H>, G, S, T>
595    where
596        H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static,
597    {
598        self.map(|_, g, s, t| (BlockingHandler { handler }, g, s, t))
599    }
600
601    /// The TLS engine for listeners with `ListenerSpec::tls(true)` (feature `tls`).
602    pub fn tls<T2: TlsAcceptor>(self, acceptor: T2) -> ServerBuilder<W, G, S, T2> {
603        self.map(|w, g, s, _| (w, g, s, acceptor))
604    }
605
606    /// The connection gate (required; `AllowAll` for none).
607    pub fn gate<G2: Gate>(self, gate: G2) -> ServerBuilder<W, G2, S, T> {
608        self.map(|w, _, s, t| (w, gate, s, t))
609    }
610
611    /// The event sink (default `NoopSink`).
612    pub fn events<S2: EventSink>(self, sink: S2) -> ServerBuilder<W, G, S2, T> {
613        self.map(|w, g, _, t| (w, g, sink, t))
614    }
615
616    /// The control line (default: none).
617    pub fn control<C: ControlLine>(mut self, line: Arc<C>) -> Self {
618        self.control = Some(line);
619        self
620    }
621
622    /// Zero the used part of every buffer when it returns to a pool (default on).
623    pub fn wipe_buffers(mut self, on: bool) -> Self {
624        self.wipe = on;
625        self
626    }
627
628    /// The clock deadlines read (tests inject a `ManualClock`).
629    pub fn clock<K: Clock>(mut self, clock: Arc<K>) -> Self {
630        self.clock = Some(clock);
631        self
632    }
633}
634
635#[cfg(feature = "udp")]
636impl<G, S, T> ServerBuilder<NoWork, G, S, T> {
637    /// Serves UDP listeners only; a TCP listener then fails `build`. One thread per
638    /// listener, and no worker pool.
639    ///
640    /// ```no_run
641    /// use std::net::SocketAddr;
642    /// use net_io::{AllowAll, ListenerInfo, ListenerSpec, ServerBuilder, UdpContext, UdpOptions, UdpSession};
643    /// struct Echo;
644    /// impl UdpSession for Echo {
645    ///     fn on_datagram(&mut self, cx: &mut UdpContext<'_>, from: SocketAddr, bytes: &[u8]) {
646    ///         let _ = cx.send_to(bytes, from);
647    ///     }
648    /// }
649    /// let server = ServerBuilder::new()
650    ///     .listener(ListenerSpec::udp("0.0.0.0:7000", UdpOptions::new()))
651    ///     .udp_sessions(|_: &ListenerInfo| Echo)
652    ///     .gate(AllowAll)
653    ///     .build()?;
654    /// server.open_door()?;
655    /// # Ok::<(), net_io::NetError>(())
656    /// ```
657    pub fn udp_sessions<F>(self, factory: F) -> ServerBuilder<UdpOnly, G, S, T>
658    where
659        F: crate::udp::UdpSessionFactory,
660    {
661        let mut b = self.map(|_, g, s, t| (UdpOnly, g, s, t));
662        b.udp = Some(Arc::new(factory));
663        b.workers.get_or_insert(1);
664        b
665    }
666}
667
668#[cfg(feature = "udp")]
669impl<W: Workload, G, S, T> ServerBuilder<W, G, S, T> {
670    /// Serves the UDP listeners beside this server's TCP work.
671    pub fn udp_sessions<F>(mut self, factory: F) -> Self
672    where
673        F: crate::udp::UdpSessionFactory,
674    {
675        self.udp = Some(Arc::new(factory));
676        self
677    }
678}
679
680impl<W, G, S, T> ServerBuilder<W, G, S, T>
681where
682    W: Workload,
683    G: Gate,
684    S: EventSink,
685    T: TlsAcceptor,
686{
687    /// Validates everything, binds the listeners, starts the workers, and returns
688    /// the server with the door **closed**.
689    ///
690    /// # Errors
691    ///
692    /// `InvalidConfig` (`field` names the method), bind errors, `Unsupported` for a
693    /// driver this version does not have.
694    pub fn build(self) -> Result<Server, NetError> {
695        // A handler holds its worker for the whole connection (blocking pool only).
696        let requested = match self.driver {
697            DriverKind::Auto if <W as engine::Serve>::BLOCKING_ONLY => DriverKind::Blocking,
698            other => other,
699        };
700        let driver = match requested.resolve() {
701            DriverKind::Reactor if <W as engine::Serve>::BLOCKING_ONLY => {
702                return Err(invalid("driver", ConfigReason::Inconsistent));
703            }
704            DriverKind::Reactor if !DriverKind::reactor_built() => {
705                return Err(NetError::Unsupported {
706                    feature: "the reactor driver",
707                    platform: std::env::consts::OS,
708                });
709            }
710            DriverKind::Uring => {
711                return Err(NetError::Unsupported {
712                    feature: "the io_uring driver (after 1.0.0)",
713                    platform: std::env::consts::OS,
714                });
715            }
716            kind => kind,
717        };
718        if self.listeners.is_empty() {
719            return Err(invalid("listener", ConfigReason::Missing));
720        }
721        if self.listeners.len() > 64 {
722            return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
723        }
724        let workers = self.workers.unwrap_or_else(|| {
725            if driver == DriverKind::Reactor {
726                std::thread::available_parallelism()
727                    .map_or(4, |n| u16::try_from(n.get()).unwrap_or(4096).min(4096))
728            } else {
729                128
730            }
731        });
732        if workers == 0 {
733            return Err(invalid("workers", ConfigReason::Zero));
734        }
735        if workers > 4096 {
736            return Err(invalid("workers", ConfigReason::TooLarge { max: 4096 }));
737        }
738        let mut listeners = self.listeners;
739        let has_tls = TypeId::of::<T>() != TypeId::of::<NoTls>();
740        let mut names = Vec::new();
741        #[cfg(feature = "udp")]
742        for spec in &listeners {
743            if (spec.udp.is_some() && self.udp.is_none())
744                || (spec.udp.is_none() && <W as engine::Serve>::UDP_ONLY)
745            {
746                return Err(invalid("udp_sessions", ConfigReason::Inconsistent));
747            }
748            if spec.udp.is_some() && (spec.tls || spec.proxy != ProxyMode::Off) {
749                return Err(invalid("udp", ConfigReason::Inconsistent));
750            }
751        }
752        for spec in &mut listeners {
753            check_spec(spec, self.trusted.as_ref(), has_tls, &names)?;
754            if let Some(n) = &spec.name {
755                names.push(n.clone());
756            }
757        }
758        // On the blocking driver an unset global cap is one connection per worker;
759        // on the reactor the default, but never more than the descriptors allow.
760        let limits = if self.limits.max_connections().is_none() {
761            let cap = if driver == DriverKind::Reactor {
762                reactor_default_cap(workers)
763            } else {
764                u32::from(workers)
765            };
766            self.limits.to_builder().max_connections(cap).build()?
767        } else {
768            self.limits.clone()
769        };
770        limits.validate(workers, crate::sys::descriptor_limit())?;
771        for spec in &listeners {
772            limits.overlay(&spec.limits).validate(workers, None)?;
773        }
774        if self.placement != Placement::Off && !crate::sys::CAN_PIN {
775            return Err(NetError::Unsupported {
776                feature: "worker placement",
777                platform: std::env::consts::OS,
778            });
779        }
780        if self.placement == Placement::Explicit(Vec::new()) {
781            return Err(invalid("placement", ConfigReason::Zero));
782        }
783        let tls: Option<Arc<dyn ErasedAcceptor>> = if has_tls {
784            Some(Arc::new(self.tls))
785        } else {
786            None
787        };
788        engine::start(engine::Config {
789            tls,
790            trusted: self.trusted,
791            listeners,
792            driver,
793            workers,
794            limits,
795            work: self.work,
796            gate: self.gate,
797            sink: self.sink,
798            control: self.control,
799            wipe: self.wipe,
800            clock: self.clock,
801            placement: self.placement,
802            #[cfg(feature = "udp")]
803            udp: self.udp,
804        })
805    }
806}
807
808/// The reactor's default global cap: 10,000, less where the process's descriptor
809/// limit would not hold it.
810fn reactor_default_cap(workers: u16) -> u32 {
811    let wanted = 10_000u32;
812    match crate::sys::descriptor_limit() {
813        Some(have) => {
814            let spare = u64::from(workers).saturating_mul(2) + 64;
815            let room = have.saturating_sub(spare).clamp(16, u64::from(wanted));
816            u32::try_from(room).unwrap_or(wanted)
817        }
818        None => wanted,
819    }
820}
821
822fn invalid(field: &'static str, reason: ConfigReason) -> NetError {
823    NetError::InvalidConfig { field, reason }
824}
825
826/// Where `Server::adopt` registers a connection: the listener (by name) whose
827/// limits and caps apply, and an optional starting lane (the gate may change it).
828///
829/// ```
830/// let spec = net_io::AdoptSpec::new("main").lane(net_io::Lane(1));
831/// # let _ = spec;
832/// ```
833#[must_use]
834#[derive(Clone, Debug, PartialEq, Eq)]
835pub struct AdoptSpec {
836    listener: String,
837    lane: Option<crate::info::Lane>,
838}
839
840impl AdoptSpec {
841    /// Registers on the listener named `listener`.
842    pub fn new(listener: &str) -> AdoptSpec {
843        AdoptSpec {
844            listener: listener.to_owned(),
845            lane: None,
846        }
847    }
848
849    /// The lane the connection starts in, before the gate's admission.
850    pub fn lane(mut self, lane: crate::info::Lane) -> AdoptSpec {
851        self.lane = Some(lane);
852        self
853    }
854}
855
856/// The checks `build` and `add_listener` run on one listener: the features it
857/// needs, a TLS engine, trusted proxies (resolved into the spec), and its name.
858fn check_spec(
859    spec: &mut ListenerSpec,
860    server_trusted: Option<&Arc<TrustedProxies>>,
861    has_tls: bool,
862    taken: &[String],
863) -> Result<(), NetError> {
864    if spec.name.is_none() {
865        spec.name = spec
866            .adopt
867            .as_ref()
868            .and_then(|h| h.name())
869            .map(str::to_owned);
870    }
871    let unix = spec.unix.is_some()
872        || spec
873            .adopt
874            .as_ref()
875            .is_some_and(|h| h.kind() == crate::info::Transport::Unix);
876    if unix && !cfg!(feature = "local") {
877        return Err(NetError::Unsupported {
878            feature: "Unix domain sockets (the `local` feature)",
879            platform: std::env::consts::OS,
880        });
881    }
882    if spec.tls {
883        if !cfg!(feature = "tls") {
884            return Err(NetError::Unsupported {
885                feature: "TLS (the `tls` feature)",
886                platform: std::env::consts::OS,
887            });
888        }
889        if !has_tls {
890            return Err(invalid("tls", ConfigReason::Missing));
891        }
892    }
893    if spec.proxy != ProxyMode::Off {
894        if !cfg!(feature = "proxy") {
895            return Err(NetError::Unsupported {
896                feature: "PROXY protocol (the `proxy` feature)",
897                platform: std::env::consts::OS,
898            });
899        }
900        // On a Unix socket the file's permissions decide who may connect.
901        if !unix {
902            let trusted = spec.trusted.clone().or_else(|| server_trusted.cloned());
903            match trusted {
904                Some(t) if !t.is_empty() => spec.trusted = Some(t),
905                // Required without anyone to trust would refuse every connection.
906                _ => return Err(invalid("trusted_proxies", ConfigReason::Missing)),
907            }
908        }
909    }
910    if let Some(n) = &spec.name {
911        if n.len() > 64 {
912            return Err(invalid("name", ConfigReason::TooLarge { max: 64 }));
913        }
914        if taken.contains(n) {
915            return Err(invalid("name", ConfigReason::Inconsistent));
916        }
917    }
918    Ok(())
919}
920
921/// A running server. Dropping it stops it (with a drain), so keep it and call
922/// [`Server::wait_for_stop`] to run until a stop is requested.
923#[must_use = "dropping a Server stops it; call wait_for_stop() to run until a stop is requested"]
924pub struct Server {
925    pub(crate) shared: Arc<Shared>,
926    pub(crate) threads: Vec<JoinHandle<()>>,
927    pub(crate) listeners: Vec<ListenerInfo>,
928    pub(crate) stopped: bool,
929}
930
931impl Server {
932    /// Starts accepting on every listener; a second call is a no-op.
933    ///
934    /// # Errors
935    ///
936    /// `ShuttingDown` while draining or after shutdown; `ForkedChild`.
937    pub fn open_door(&self) -> Result<(), NetError> {
938        self.shared.open_door()
939    }
940
941    /// Stops accepting within one loop iteration; listening sockets stay open. Idempotent.
942    pub fn close_door(&self) {
943        self.shared.close_door();
944    }
945
946    /// Whether the server is accepting.
947    #[must_use]
948    pub fn door(&self) -> DoorState {
949        self.shared.door()
950    }
951
952    /// Closes the door, tells sessions to finish, closes idle connections at once,
953    /// waits for the rest until `deadline`, then kills them with `DrainDeadline`.
954    pub fn drain(&self, deadline: Instant) -> DrainReport {
955        self.shared.drain(deadline)
956    }
957
958    /// Drains, then closes the listening sockets and joins every thread.
959    pub fn shutdown(mut self, deadline: Instant) -> DrainReport {
960        self.stop(deadline)
961    }
962
963    /// Blocks until a stop is requested (`ServerHandle::request_stop`, or the
964    /// control line moves to `Draining` or `Stopping`), then shuts down.
965    pub fn wait_for_stop(mut self) -> DrainReport {
966        let deadline = self.shared.wait_for_stop_request();
967        self.stop(deadline)
968    }
969
970    fn stop(&mut self, deadline: Instant) -> DrainReport {
971        if self.stopped {
972            return DrainReport {
973                graceful: 0,
974                killed: 0,
975                took: Duration::ZERO,
976            };
977        }
978        self.stopped = true;
979        let report = self.shared.drain(deadline);
980        self.shared.stop_threads();
981        for t in self.threads.drain(..) {
982            let _ = t.join();
983        }
984        self.shared.join_listeners();
985        report
986    }
987
988    /// Registers a dialed connection exactly like an accepted one on the
989    /// listener named in `spec`: a new id, the caps, `Gate::admit` with
990    /// `AdmitStage::Adopt`, that listener's limits, the server's handler or
991    /// sessions, its kill handle, and its events. For back-channels and outbound
992    /// connections a server should run and revoke like its own. A gate the
993    /// connection had from `set_gate` is closed (`SessionClosed`) first.
994    ///
995    /// # Errors
996    ///
997    /// `Refused { cause }` (caps, the gate, `Busy`; the connection was reset),
998    /// `InvalidConfig { field: "listener" }` (no listener with that name),
999    /// `InvalidConfig { field: "connection" }` (a TLS connection, or bytes read
1000    /// ahead), `ShuttingDown`, `ForkedChild`, `Closed`.
1001    ///
1002    /// ```no_run
1003    /// use net_io::{AdoptSpec, AllowAll, ListenerSpec, ServerBuilder};
1004    /// let server = ServerBuilder::new()
1005    ///     .listener(ListenerSpec::tcp("127.0.0.1:7000").name("main"))
1006    ///     .handler(|conn| { conn.send_all(b"hello, upstream\n")?; Ok(()) })
1007    ///     .gate(AllowAll)
1008    ///     .build()?;
1009    /// let upstream = net_io::connect("10.0.0.9:9000")?;
1010    /// let id = server.adopt(upstream, AdoptSpec::new("main"))?;
1011    /// # let _ = id;
1012    /// # Ok::<(), net_io::NetError>(())
1013    /// ```
1014    pub fn adopt(&self, conn: TcpConnection, spec: AdoptSpec) -> Result<ConnectionId, NetError> {
1015        let mut conn = conn;
1016        let link = conn.take_link().ok_or(NetError::Closed)?;
1017        let (Some(peer), Some(local)) =
1018            (link.info.peer.socket_addr(), link.info.local.socket_addr())
1019        else {
1020            return Err(invalid("connection", ConfigReason::Inconsistent));
1021        };
1022        let stream = link
1023            .into_stream(CloseReason::SessionClosed)
1024            .and_then(crate::sys::Stream::into_tcp)
1025            .ok_or(invalid("connection", ConfigReason::Inconsistent))?;
1026        self.shared
1027            .adopt(stream, peer, local, &spec.listener, spec.lane)
1028    }
1029
1030    /// Owned duplicates of every listening socket, for a hand-off to the next
1031    /// process (`send_listeners`, Unix). This server keeps
1032    /// accepting meanwhile, so the new process can start before this one stops
1033    /// (decision D-042); a later `shutdown` closes only this server's copies, and
1034    /// a Unix socket file stays in place for the new process.
1035    ///
1036    /// # Errors
1037    ///
1038    /// `Os` when a socket cannot be duplicated, `ForkedChild`.
1039    pub fn release_listeners(&self) -> Result<Vec<ListenerHandle>, NetError> {
1040        self.shared.release_listeners()
1041    }
1042
1043    /// Binds one more listener on the running server and starts its accept
1044    /// thread. Its door is closed until the next [`Server::open_door`] (which
1045    /// opens every listener's door); the same checks as `build` apply. The id is
1046    /// new: ids of removed listeners are never reused.
1047    ///
1048    /// # Errors
1049    ///
1050    /// As `build` for the listener; `InvalidConfig { field: "listener" }` past 64
1051    /// listeners, `ShuttingDown`, `ForkedChild`.
1052    ///
1053    /// ```no_run
1054    /// use net_io::{AllowAll, ListenerSpec, ServerBuilder};
1055    /// let mut server = ServerBuilder::new()
1056    ///     .listener(ListenerSpec::tcp("127.0.0.1:8080"))
1057    ///     .handler(|conn| { conn.send_all(b"hi\n")?; Ok(()) })
1058    ///     .gate(AllowAll)
1059    ///     .build()?;
1060    /// server.open_door()?;
1061    /// let added = server.add_listener(ListenerSpec::tcp("127.0.0.1:8081").name("extra"))?;
1062    /// server.open_door()?; // opens the new listener's door
1063    /// # let _ = added;
1064    /// # Ok::<(), net_io::NetError>(())
1065    /// ```
1066    pub fn add_listener(&mut self, spec: ListenerSpec) -> Result<ListenerId, NetError> {
1067        let mut spec = spec;
1068        if self.listeners.len() >= 64 {
1069            return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
1070        }
1071        let names: Vec<String> = self
1072            .listeners
1073            .iter()
1074            .filter_map(|l| l.name.clone())
1075            .collect();
1076        check_spec(
1077            &mut spec,
1078            self.shared.trusted.as_ref(),
1079            self.shared.tls.is_some(),
1080            &names,
1081        )?;
1082        let workers = u16::try_from(self.shared.worker_count()).unwrap_or(u16::MAX);
1083        self.shared
1084            .base_limits
1085            .overlay(&spec.limits)
1086            .validate(workers, None)?;
1087        let info = self.shared.add_listener(spec)?;
1088        let id = info.id;
1089        self.listeners.push(info);
1090        Ok(id)
1091    }
1092
1093    /// Closes one listener's socket at once (its connections keep running),
1094    /// then drains them: idle ones close now, the rest may finish until
1095    /// `deadline` and are then killed (`DrainDeadline`). Other listeners and
1096    /// their connections are not touched.
1097    ///
1098    /// # Errors
1099    ///
1100    /// `InvalidConfig { field: "listener", reason: Missing }` for an unknown id,
1101    /// `ForkedChild`.
1102    pub fn remove_listener(
1103        &mut self,
1104        id: ListenerId,
1105        deadline: Instant,
1106    ) -> Result<DrainReport, NetError> {
1107        let report = self.shared.remove_listener(id, deadline)?;
1108        self.listeners.retain(|l| l.id != id);
1109        Ok(report)
1110    }
1111
1112    /// A cloneable handle for other threads.
1113    #[must_use]
1114    pub fn handle(&self) -> ServerHandle {
1115        ServerHandle {
1116            shared: self.shared.clone(),
1117        }
1118    }
1119
1120    /// Counters summed over the workers.
1121    #[must_use]
1122    pub fn stats(&self) -> Stats {
1123        self.shared.stats()
1124    }
1125
1126    /// Facts about each listener.
1127    #[must_use]
1128    pub fn listeners(&self) -> &[ListenerInfo] {
1129        &self.listeners
1130    }
1131}
1132
1133impl Drop for Server {
1134    fn drop(&mut self) {
1135        let deadline = Instant::now() + self.shared.drain_timeout;
1136        self.stop(deadline);
1137    }
1138}
1139
1140impl fmt::Debug for Server {
1141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1142        f.debug_struct("Server")
1143            .field("listeners", &self.listeners)
1144            .field("door", &self.door())
1145            .finish()
1146    }
1147}
1148
1149/// A cloneable handle to a running server, safe to use from any thread.
1150///
1151/// ```no_run
1152/// let server = net_io::serve("127.0.0.1:7000", |conn| { conn.send_all(b"hi\n")?; Ok(()) })?;
1153/// let handle = server.handle();
1154/// std::thread::spawn(move || {
1155///     // ... wait for a signal from the application's signal library ...
1156///     handle.request_stop();
1157/// });
1158/// let report = server.wait_for_stop();
1159/// println!("drained: {} graceful, {} killed in {:?}", report.graceful, report.killed, report.took);
1160/// # Ok::<(), net_io::NetError>(())
1161/// ```
1162#[derive(Clone)]
1163pub struct ServerHandle {
1164    pub(crate) shared: Arc<Shared>,
1165}
1166
1167impl ServerHandle {
1168    /// Aborts the connection `id`; `false` if it already closed or belongs to another server.
1169    pub fn kill(&self, id: ConnectionId, reason: KillReason) -> bool {
1170        self.shared.kill(id, reason)
1171    }
1172
1173    /// Stops accepting.
1174    pub fn close_door(&self) {
1175        self.shared.close_door();
1176    }
1177
1178    /// Makes `Server::wait_for_stop` return after the drain. Does not block.
1179    pub fn request_stop(&self) {
1180        self.shared.request_stop(None);
1181    }
1182
1183    /// Interrupts every worker's and acceptor's wait so a control-line change is seen at once.
1184    pub fn wake_all(&self) {
1185        self.shared.wake_all();
1186    }
1187
1188    /// The completion queue of `worker`.
1189    #[must_use]
1190    pub fn completer(&self, worker: WorkerId) -> Option<crate::completer::Completer> {
1191        self.shared.completer(worker)
1192    }
1193
1194    /// Counters summed over the workers.
1195    #[must_use]
1196    pub fn stats(&self) -> Stats {
1197        self.shared.stats()
1198    }
1199
1200    /// Whether the server is accepting.
1201    #[must_use]
1202    pub fn door(&self) -> DoorState {
1203        self.shared.door()
1204    }
1205}
1206
1207impl fmt::Debug for ServerHandle {
1208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1209        f.debug_struct("ServerHandle")
1210            .field("door", &self.door())
1211            .finish()
1212    }
1213}
1214
1215impl Stats {
1216    pub(crate) fn from_parts(
1217        mut base: Stats,
1218        refused_by: [u64; RefusalCause::COUNT],
1219        closed_by: [u64; CloseReason::COUNT],
1220    ) -> Stats {
1221        base.refused_by = refused_by;
1222        base.closed_by = closed_by;
1223        base
1224    }
1225}