1mod engine;
4mod source;
5
6use std::any::TypeId;
7use std::fmt;
8use std::net::{SocketAddr, ToSocketAddrs};
9use std::path::PathBuf;
10use std::sync::Arc;
11use std::thread::JoinHandle;
12use std::time::{Duration, Instant};
13
14use crate::control::ControlLine;
15use crate::driver::DriverKind;
16use crate::error::{CloseReason, ConfigReason, KillReason, NetError, RefusalCause};
17use crate::events::{EventSink, NoopSink};
18use crate::gate::Gate;
19use crate::handoff::ListenerHandle;
20use crate::id::{ConnectionId, ListenerId, WorkerId};
21use crate::limits::Limits;
22use crate::opts::{ListenOptions, LocalOptions};
23use crate::proxy::ProxyMode;
24use crate::session::SessionFactory;
25use crate::tcp::{ListenerInfo, TcpConnection};
26use crate::time::Clock;
27use crate::tls::ErasedAcceptor;
28use crate::tls::{NoTls, TlsAcceptor};
29use crate::trusted::TrustedProxies;
30
31pub(crate) use engine::Shared;
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39pub enum DoorState {
40 Open,
42 Closed,
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
53pub struct DrainReport {
54 pub graceful: u32,
56 pub killed: u32,
58 pub took: Duration,
60}
61
62#[non_exhaustive]
71#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
72pub struct Stats {
73 pub open: u64,
75 pub accepted: u64,
77 pub refused: u64,
79 pub closed: u64,
81 pub bytes_in: u64,
83 pub bytes_out: u64,
85 pub egress_denied: u64,
87 pub killed: u64,
89 pub slow_peers: u64,
91 pub timeouts: u64,
93 pub descriptor_pressure: u64,
95 pub stale_completions: u64,
97 pub session_panics: u64,
99 refused_by: [u64; RefusalCause::COUNT],
100 closed_by: [u64; CloseReason::COUNT],
101}
102
103impl Stats {
104 #[must_use]
106 pub fn refused_for(&self, cause: RefusalCause) -> u64 {
107 self.refused_by[cause.index()]
108 }
109
110 #[must_use]
112 pub fn closed_for(&self, reason: CloseReason) -> u64 {
113 self.closed_by[reason.index()]
114 }
115
116 pub fn closes(&self) -> impl Iterator<Item = (CloseReason, u64)> + '_ {
127 CloseReason::BY_INDEX
128 .iter()
129 .zip(self.closed_by.iter())
130 .filter(|(_, n)| **n > 0)
131 .map(|(r, n)| (*r, *n))
132 }
133
134 pub fn refusals(&self) -> impl Iterator<Item = (RefusalCause, u64)> + '_ {
136 RefusalCause::BY_INDEX
137 .iter()
138 .zip(self.refused_by.iter())
139 .filter(|(_, n)| **n > 0)
140 .map(|(r, n)| (*r, *n))
141 }
142}
143
144#[must_use]
155#[derive(Debug)]
156pub struct ListenerSpec {
157 pub(crate) addrs: Result<Vec<SocketAddr>, String>,
158 pub(crate) options: Option<ListenOptions>,
159 pub(crate) name: Option<String>,
160 pub(crate) limits: Limits,
161 pub(crate) proxy: ProxyMode,
162 pub(crate) trusted: Option<Arc<TrustedProxies>>,
163 pub(crate) tls: bool,
164 pub(crate) unix: Option<(PathBuf, LocalOptions)>,
165 pub(crate) adopt: Option<ListenerHandle>,
166}
167
168impl ListenerSpec {
169 pub fn tcp<A: ToSocketAddrs>(addr: A) -> ListenerSpec {
171 ListenerSpec {
172 addrs: addr
173 .to_socket_addrs()
174 .map(|i| i.collect())
175 .map_err(|e| e.to_string()),
176 options: None,
177 name: None,
178 limits: Limits::default(),
179 proxy: ProxyMode::Off,
180 trusted: None,
181 tls: false,
182 unix: None,
183 adopt: None,
184 }
185 }
186
187 pub fn tcp_with<A: ToSocketAddrs>(addr: A, options: ListenOptions) -> ListenerSpec {
189 ListenerSpec {
190 options: Some(options),
191 ..ListenerSpec::tcp(addr)
192 }
193 }
194
195 pub fn unix(path: impl Into<PathBuf>, options: LocalOptions) -> ListenerSpec {
210 ListenerSpec {
211 addrs: Ok(Vec::new()),
212 options: None,
213 name: None,
214 limits: Limits::default(),
215 proxy: ProxyMode::Off,
216 trusted: None,
217 tls: false,
218 unix: Some((path.into(), options)),
219 adopt: None,
220 }
221 }
222
223 pub fn adopt(handle: ListenerHandle) -> ListenerSpec {
239 ListenerSpec {
240 addrs: Ok(Vec::new()),
241 options: None,
242 name: None,
243 limits: Limits::default(),
244 proxy: ProxyMode::Off,
245 trusted: None,
246 tls: false,
247 unix: None,
248 adopt: Some(handle),
249 }
250 }
251
252 pub fn name(mut self, name: &str) -> ListenerSpec {
254 self.name = Some(name.to_owned());
255 self
256 }
257
258 pub fn limits(mut self, limits: Limits) -> ListenerSpec {
260 self.limits = limits;
261 self
262 }
263
264 pub fn proxy(mut self, mode: ProxyMode) -> ListenerSpec {
273 self.proxy = mode;
274 self
275 }
276
277 pub fn tls(mut self, on: bool) -> ListenerSpec {
280 self.tls = on;
281 self
282 }
283
284 pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> ListenerSpec {
286 self.trusted = Some(Arc::new(proxies));
287 self
288 }
289}
290
291#[derive(Clone, Copy, Debug, Default)]
293pub struct NoWork;
294
295#[derive(Clone, Copy, Debug, Default)]
297pub struct NoGate;
298
299#[derive(Debug)]
301pub struct Sessions<F> {
302 pub(crate) factory: F,
303}
304
305pub struct BlockingHandler<H> {
307 pub(crate) handler: H,
308}
309
310impl<H> fmt::Debug for BlockingHandler<H> {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 f.write_str("BlockingHandler")
313 }
314}
315
316pub(crate) mod sealed {
317 pub trait Sealed {}
318}
319
320pub trait Workload: sealed::Sealed + engine::Serve + Send + Sync + 'static {}
322
323impl<F: SessionFactory> sealed::Sealed for Sessions<F> {}
324impl<F: SessionFactory> Workload for Sessions<F> {}
325
326impl<H> sealed::Sealed for BlockingHandler<H> where
327 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
328{
329}
330impl<H> Workload for BlockingHandler<H> where
331 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
332{
333}
334
335#[must_use]
360pub struct ServerBuilder<W = NoWork, G = NoGate, S = NoopSink, T = NoTls> {
361 listeners: Vec<ListenerSpec>,
362 driver: DriverKind,
363 workers: Option<u16>,
364 limits: Limits,
365 work: W,
366 gate: G,
367 sink: S,
368 tls: T,
369 control: Option<Arc<dyn ControlLine>>,
370 wipe: bool,
371 clock: Option<Arc<dyn Clock>>,
372 trusted: Option<Arc<TrustedProxies>>,
373}
374
375impl ServerBuilder {
376 pub fn new() -> ServerBuilder {
378 ServerBuilder {
379 listeners: Vec::new(),
380 driver: DriverKind::Auto,
381 workers: None,
382 limits: Limits::default(),
383 work: NoWork,
384 gate: NoGate,
385 sink: NoopSink,
386 tls: NoTls,
387 control: None,
388 wipe: true,
389 clock: None,
390 trusted: None,
391 }
392 }
393}
394
395impl Default for ServerBuilder {
396 fn default() -> ServerBuilder {
397 ServerBuilder::new()
398 }
399}
400
401impl<W, G, S, T> ServerBuilder<W, G, S, T> {
402 fn map<W2, G2, S2, T2>(
403 self,
404 f: impl FnOnce(W, G, S, T) -> (W2, G2, S2, T2),
405 ) -> ServerBuilder<W2, G2, S2, T2> {
406 let ServerBuilder {
407 listeners,
408 driver,
409 workers,
410 limits,
411 work,
412 gate,
413 sink,
414 tls,
415 control,
416 wipe,
417 clock,
418 trusted,
419 } = self;
420 let (work, gate, sink, tls) = f(work, gate, sink, tls);
421 ServerBuilder {
422 listeners,
423 driver,
424 workers,
425 limits,
426 work,
427 gate,
428 sink,
429 tls,
430 control,
431 wipe,
432 clock,
433 trusted,
434 }
435 }
436
437 pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> Self {
440 self.trusted = Some(Arc::new(proxies));
441 self
442 }
443
444 pub fn listener(mut self, spec: ListenerSpec) -> Self {
446 self.listeners.push(spec);
447 self
448 }
449
450 pub fn driver(mut self, kind: DriverKind) -> Self {
452 self.driver = kind;
453 self
454 }
455
456 pub fn workers(mut self, n: u16) -> Self {
458 self.workers = Some(n);
459 self
460 }
461
462 pub fn limits(mut self, limits: Limits) -> Self {
464 self.limits = limits;
465 self
466 }
467
468 pub fn sessions<F: SessionFactory>(self, factory: F) -> ServerBuilder<Sessions<F>, G, S, T> {
470 self.map(|_, g, s, t| (Sessions { factory }, g, s, t))
471 }
472
473 pub fn handler<H>(self, handler: H) -> ServerBuilder<BlockingHandler<H>, G, S, T>
475 where
476 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static,
477 {
478 self.map(|_, g, s, t| (BlockingHandler { handler }, g, s, t))
479 }
480
481 pub fn tls<T2: TlsAcceptor>(self, acceptor: T2) -> ServerBuilder<W, G, S, T2> {
483 self.map(|w, g, s, _| (w, g, s, acceptor))
484 }
485
486 pub fn gate<G2: Gate>(self, gate: G2) -> ServerBuilder<W, G2, S, T> {
488 self.map(|w, _, s, t| (w, gate, s, t))
489 }
490
491 pub fn events<S2: EventSink>(self, sink: S2) -> ServerBuilder<W, G, S2, T> {
493 self.map(|w, g, _, t| (w, g, sink, t))
494 }
495
496 pub fn control<C: ControlLine>(mut self, line: Arc<C>) -> Self {
498 self.control = Some(line);
499 self
500 }
501
502 pub fn wipe_buffers(mut self, on: bool) -> Self {
504 self.wipe = on;
505 self
506 }
507
508 pub fn clock<K: Clock>(mut self, clock: Arc<K>) -> Self {
510 self.clock = Some(clock);
511 self
512 }
513}
514
515impl<W, G, S, T> ServerBuilder<W, G, S, T>
516where
517 W: Workload,
518 G: Gate,
519 S: EventSink,
520 T: TlsAcceptor,
521{
522 pub fn build(self) -> Result<Server, NetError> {
530 let driver = match self.driver.resolve() {
531 DriverKind::Blocking => DriverKind::Blocking,
532 other => {
533 return Err(NetError::Unsupported {
534 feature: match other {
535 DriverKind::Uring => "the io_uring driver (after 1.0.0)",
536 _ => "the reactor driver (0.5.0)",
537 },
538 platform: std::env::consts::OS,
539 });
540 }
541 };
542 if self.listeners.is_empty() {
543 return Err(invalid("listener", ConfigReason::Missing));
544 }
545 if self.listeners.len() > 64 {
546 return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
547 }
548 let workers = self.workers.unwrap_or(128);
549 if workers == 0 {
550 return Err(invalid("workers", ConfigReason::Zero));
551 }
552 if workers > 4096 {
553 return Err(invalid("workers", ConfigReason::TooLarge { max: 4096 }));
554 }
555 let mut listeners = self.listeners;
556 let has_tls = TypeId::of::<T>() != TypeId::of::<NoTls>();
557 let mut names = Vec::new();
558 for spec in &mut listeners {
559 check_spec(spec, self.trusted.as_ref(), has_tls, &names)?;
560 if let Some(n) = &spec.name {
561 names.push(n.clone());
562 }
563 }
564 let limits = if self.limits.max_connections().is_none() {
566 self.limits
567 .to_builder()
568 .max_connections(u32::from(workers))
569 .build()?
570 } else {
571 self.limits.clone()
572 };
573 limits.validate(workers, crate::sys::descriptor_limit())?;
574 for spec in &listeners {
575 limits.overlay(&spec.limits).validate(workers, None)?;
576 }
577 let tls: Option<Arc<dyn ErasedAcceptor>> = if has_tls {
578 Some(Arc::new(self.tls))
579 } else {
580 None
581 };
582 engine::start(engine::Config {
583 tls,
584 trusted: self.trusted,
585 listeners,
586 driver,
587 workers,
588 limits,
589 work: self.work,
590 gate: self.gate,
591 sink: self.sink,
592 control: self.control,
593 wipe: self.wipe,
594 clock: self.clock,
595 })
596 }
597}
598
599fn invalid(field: &'static str, reason: ConfigReason) -> NetError {
600 NetError::InvalidConfig { field, reason }
601}
602
603#[must_use]
611#[derive(Clone, Debug, PartialEq, Eq)]
612pub struct AdoptSpec {
613 listener: String,
614 lane: Option<crate::info::Lane>,
615}
616
617impl AdoptSpec {
618 pub fn new(listener: &str) -> AdoptSpec {
620 AdoptSpec {
621 listener: listener.to_owned(),
622 lane: None,
623 }
624 }
625
626 pub fn lane(mut self, lane: crate::info::Lane) -> AdoptSpec {
628 self.lane = Some(lane);
629 self
630 }
631}
632
633fn check_spec(
636 spec: &mut ListenerSpec,
637 server_trusted: Option<&Arc<TrustedProxies>>,
638 has_tls: bool,
639 taken: &[String],
640) -> Result<(), NetError> {
641 if spec.name.is_none() {
642 spec.name = spec
643 .adopt
644 .as_ref()
645 .and_then(|h| h.name())
646 .map(str::to_owned);
647 }
648 let unix = spec.unix.is_some()
649 || spec
650 .adopt
651 .as_ref()
652 .is_some_and(|h| h.kind() == crate::info::Transport::Unix);
653 if unix && !cfg!(all(unix, feature = "local")) {
654 return Err(NetError::Unsupported {
655 feature: if cfg!(unix) {
656 "Unix domain sockets (the `local` feature)"
657 } else {
658 "Unix domain sockets on Windows (0.5.0)"
659 },
660 platform: std::env::consts::OS,
661 });
662 }
663 if spec.tls {
664 if !cfg!(feature = "tls") {
665 return Err(NetError::Unsupported {
666 feature: "TLS (the `tls` feature)",
667 platform: std::env::consts::OS,
668 });
669 }
670 if !has_tls {
671 return Err(invalid("tls", ConfigReason::Missing));
672 }
673 }
674 if spec.proxy != ProxyMode::Off {
675 if !cfg!(feature = "proxy") {
676 return Err(NetError::Unsupported {
677 feature: "PROXY protocol (the `proxy` feature)",
678 platform: std::env::consts::OS,
679 });
680 }
681 if !unix {
683 let trusted = spec.trusted.clone().or_else(|| server_trusted.cloned());
684 match trusted {
685 Some(t) if !t.is_empty() => spec.trusted = Some(t),
686 _ => return Err(invalid("trusted_proxies", ConfigReason::Missing)),
688 }
689 }
690 }
691 if let Some(n) = &spec.name {
692 if n.len() > 64 {
693 return Err(invalid("name", ConfigReason::TooLarge { max: 64 }));
694 }
695 if taken.contains(n) {
696 return Err(invalid("name", ConfigReason::Inconsistent));
697 }
698 }
699 Ok(())
700}
701
702#[must_use = "dropping a Server stops it; call wait_for_stop() to run until a stop is requested"]
705pub struct Server {
706 pub(crate) shared: Arc<Shared>,
707 pub(crate) threads: Vec<JoinHandle<()>>,
708 pub(crate) listeners: Vec<ListenerInfo>,
709 pub(crate) stopped: bool,
710}
711
712impl Server {
713 pub fn open_door(&self) -> Result<(), NetError> {
719 self.shared.open_door()
720 }
721
722 pub fn close_door(&self) {
724 self.shared.close_door();
725 }
726
727 #[must_use]
729 pub fn door(&self) -> DoorState {
730 self.shared.door()
731 }
732
733 pub fn drain(&self, deadline: Instant) -> DrainReport {
736 self.shared.drain(deadline)
737 }
738
739 pub fn shutdown(mut self, deadline: Instant) -> DrainReport {
741 self.stop(deadline)
742 }
743
744 pub fn wait_for_stop(mut self) -> DrainReport {
747 let deadline = self.shared.wait_for_stop_request();
748 self.stop(deadline)
749 }
750
751 fn stop(&mut self, deadline: Instant) -> DrainReport {
752 if self.stopped {
753 return DrainReport {
754 graceful: 0,
755 killed: 0,
756 took: Duration::ZERO,
757 };
758 }
759 self.stopped = true;
760 let report = self.shared.drain(deadline);
761 self.shared.stop_threads();
762 for t in self.threads.drain(..) {
763 let _ = t.join();
764 }
765 self.shared.join_listeners();
766 report
767 }
768
769 pub fn adopt(&self, conn: TcpConnection, spec: AdoptSpec) -> Result<ConnectionId, NetError> {
796 let mut conn = conn;
797 let link = conn.take_link().ok_or(NetError::Closed)?;
798 let (Some(peer), Some(local)) =
799 (link.info.peer.socket_addr(), link.info.local.socket_addr())
800 else {
801 return Err(invalid("connection", ConfigReason::Inconsistent));
802 };
803 let stream = link
804 .into_stream(CloseReason::SessionClosed)
805 .and_then(crate::sys::Stream::into_tcp)
806 .ok_or(invalid("connection", ConfigReason::Inconsistent))?;
807 self.shared
808 .adopt(stream, peer, local, &spec.listener, spec.lane)
809 }
810
811 pub fn release_listeners(&self) -> Result<Vec<ListenerHandle>, NetError> {
821 self.shared.release_listeners()
822 }
823
824 pub fn add_listener(&mut self, spec: ListenerSpec) -> Result<ListenerId, NetError> {
848 let mut spec = spec;
849 if self.listeners.len() >= 64 {
850 return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
851 }
852 let names: Vec<String> = self
853 .listeners
854 .iter()
855 .filter_map(|l| l.name.clone())
856 .collect();
857 check_spec(
858 &mut spec,
859 self.shared.trusted.as_ref(),
860 self.shared.tls.is_some(),
861 &names,
862 )?;
863 let workers = u16::try_from(self.shared.worker_count()).unwrap_or(u16::MAX);
864 self.shared
865 .base_limits
866 .overlay(&spec.limits)
867 .validate(workers, None)?;
868 let info = self.shared.add_listener(spec)?;
869 let id = info.id;
870 self.listeners.push(info);
871 Ok(id)
872 }
873
874 pub fn remove_listener(
884 &mut self,
885 id: ListenerId,
886 deadline: Instant,
887 ) -> Result<DrainReport, NetError> {
888 let report = self.shared.remove_listener(id, deadline)?;
889 self.listeners.retain(|l| l.id != id);
890 Ok(report)
891 }
892
893 #[must_use]
895 pub fn handle(&self) -> ServerHandle {
896 ServerHandle {
897 shared: self.shared.clone(),
898 }
899 }
900
901 #[must_use]
903 pub fn stats(&self) -> Stats {
904 self.shared.stats()
905 }
906
907 #[must_use]
909 pub fn listeners(&self) -> &[ListenerInfo] {
910 &self.listeners
911 }
912}
913
914impl Drop for Server {
915 fn drop(&mut self) {
916 let deadline = Instant::now() + self.shared.drain_timeout;
917 self.stop(deadline);
918 }
919}
920
921impl fmt::Debug for Server {
922 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
923 f.debug_struct("Server")
924 .field("listeners", &self.listeners)
925 .field("door", &self.door())
926 .finish()
927 }
928}
929
930#[derive(Clone)]
944pub struct ServerHandle {
945 pub(crate) shared: Arc<Shared>,
946}
947
948impl ServerHandle {
949 pub fn kill(&self, id: ConnectionId, reason: KillReason) -> bool {
951 self.shared.kill(id, reason)
952 }
953
954 pub fn close_door(&self) {
956 self.shared.close_door();
957 }
958
959 pub fn request_stop(&self) {
961 self.shared.request_stop(None);
962 }
963
964 pub fn wake_all(&self) {
966 self.shared.wake_all();
967 }
968
969 #[must_use]
971 pub fn completer(&self, worker: WorkerId) -> Option<crate::completer::Completer> {
972 self.shared.completer(worker)
973 }
974
975 #[must_use]
977 pub fn stats(&self) -> Stats {
978 self.shared.stats()
979 }
980
981 #[must_use]
983 pub fn door(&self) -> DoorState {
984 self.shared.door()
985 }
986}
987
988impl fmt::Debug for ServerHandle {
989 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
990 f.debug_struct("ServerHandle")
991 .field("door", &self.door())
992 .finish()
993 }
994}
995
996impl Stats {
997 pub(crate) fn from_parts(
998 mut base: Stats,
999 refused_by: [u64; RefusalCause::COUNT],
1000 closed_by: [u64; CloseReason::COUNT],
1001 ) -> Stats {
1002 base.refused_by = refused_by;
1003 base.closed_by = closed_by;
1004 base
1005 }
1006}