1mod 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum DoorState {
42 Open,
44 Closed,
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub struct DrainReport {
56 pub graceful: u32,
58 pub killed: u32,
60 pub took: Duration,
62}
63
64#[non_exhaustive]
73#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
74pub struct Stats {
75 pub open: u64,
77 pub accepted: u64,
79 pub refused: u64,
81 pub closed: u64,
83 pub bytes_in: u64,
85 pub bytes_out: u64,
87 pub egress_denied: u64,
89 pub killed: u64,
91 pub slow_peers: u64,
93 pub timeouts: u64,
95 pub descriptor_pressure: u64,
97 pub stale_completions: u64,
99 pub session_panics: u64,
101 refused_by: [u64; RefusalCause::COUNT],
102 closed_by: [u64; CloseReason::COUNT],
103}
104
105impl Stats {
106 #[must_use]
108 pub fn refused_for(&self, cause: RefusalCause) -> u64 {
109 self.refused_by[cause.index()]
110 }
111
112 #[must_use]
114 pub fn closed_for(&self, reason: CloseReason) -> u64 {
115 self.closed_by[reason.index()]
116 }
117
118 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 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#[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 pub(crate) adopt: Option<ListenerHandle>,
170}
171
172impl ListenerSpec {
173 pub fn tcp<A: ToSocketAddrs>(addr: A) -> ListenerSpec {
175 ListenerSpec {
176 addrs: addr
177 .to_socket_addrs()
178 .map(|i| i.collect())
179 .map_err(|e| e.to_string()),
180 options: None,
181 name: None,
182 limits: Limits::default(),
183 proxy: ProxyMode::Off,
184 trusted: None,
185 tls: false,
186 unix: None,
187 #[cfg(all(windows, feature = "local"))]
188 pipe: None,
189 adopt: None,
190 }
191 }
192
193 pub fn tcp_with<A: ToSocketAddrs>(addr: A, options: ListenOptions) -> ListenerSpec {
195 ListenerSpec {
196 options: Some(options),
197 ..ListenerSpec::tcp(addr)
198 }
199 }
200
201 #[cfg(all(windows, feature = "local"))]
212 pub fn pipe(name: &str, options: crate::pipe::PipeOptions) -> ListenerSpec {
213 ListenerSpec {
214 pipe: Some((name.to_owned(), options)),
215 ..ListenerSpec::tcp(std::net::SocketAddr::from(([127, 0, 0, 1], 0)))
216 }
217 }
218
219 pub fn unix(path: impl Into<PathBuf>, options: LocalOptions) -> ListenerSpec {
234 ListenerSpec {
235 addrs: Ok(Vec::new()),
236 options: None,
237 name: None,
238 limits: Limits::default(),
239 proxy: ProxyMode::Off,
240 trusted: None,
241 tls: false,
242 unix: Some((path.into(), options)),
243 #[cfg(all(windows, feature = "local"))]
244 pipe: None,
245 adopt: None,
246 }
247 }
248
249 pub fn adopt(handle: ListenerHandle) -> 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: None,
274 #[cfg(all(windows, feature = "local"))]
275 pipe: None,
276 adopt: Some(handle),
277 }
278 }
279
280 pub fn name(mut self, name: &str) -> ListenerSpec {
282 self.name = Some(name.to_owned());
283 self
284 }
285
286 pub fn limits(mut self, limits: Limits) -> ListenerSpec {
288 self.limits = limits;
289 self
290 }
291
292 pub fn proxy(mut self, mode: ProxyMode) -> ListenerSpec {
301 self.proxy = mode;
302 self
303 }
304
305 pub fn tls(mut self, on: bool) -> ListenerSpec {
308 self.tls = on;
309 self
310 }
311
312 pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> ListenerSpec {
314 self.trusted = Some(Arc::new(proxies));
315 self
316 }
317}
318
319#[derive(Clone, Copy, Debug, Default)]
321pub struct NoWork;
322
323#[derive(Clone, Copy, Debug, Default)]
325pub struct NoGate;
326
327#[derive(Debug)]
329pub struct Sessions<F> {
330 pub(crate) factory: F,
331}
332
333#[cfg(feature = "reactor")]
334impl<F> Sessions<F> {
335 pub(crate) fn factory(&self) -> &F {
336 &self.factory
337 }
338}
339
340pub struct BlockingHandler<H> {
342 pub(crate) handler: H,
343}
344
345impl<H> fmt::Debug for BlockingHandler<H> {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 f.write_str("BlockingHandler")
348 }
349}
350
351pub(crate) mod sealed {
352 pub trait Sealed {}
353}
354
355pub trait Workload: sealed::Sealed + engine::Serve + Send + Sync + 'static {}
357
358impl<F: SessionFactory> sealed::Sealed for Sessions<F> {}
359impl<F: SessionFactory> Workload for Sessions<F> {}
360
361impl<H> sealed::Sealed for BlockingHandler<H> where
362 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
363{
364}
365impl<H> Workload for BlockingHandler<H> where
366 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static
367{
368}
369
370#[must_use]
395pub struct ServerBuilder<W = NoWork, G = NoGate, S = NoopSink, T = NoTls> {
396 listeners: Vec<ListenerSpec>,
397 driver: DriverKind,
398 workers: Option<u16>,
399 limits: Limits,
400 work: W,
401 gate: G,
402 sink: S,
403 tls: T,
404 control: Option<Arc<dyn ControlLine>>,
405 wipe: bool,
406 clock: Option<Arc<dyn Clock>>,
407 trusted: Option<Arc<TrustedProxies>>,
408}
409
410impl ServerBuilder {
411 pub fn new() -> ServerBuilder {
413 ServerBuilder {
414 listeners: Vec::new(),
415 driver: DriverKind::Auto,
416 workers: None,
417 limits: Limits::default(),
418 work: NoWork,
419 gate: NoGate,
420 sink: NoopSink,
421 tls: NoTls,
422 control: None,
423 wipe: true,
424 clock: None,
425 trusted: None,
426 }
427 }
428}
429
430impl Default for ServerBuilder {
431 fn default() -> ServerBuilder {
432 ServerBuilder::new()
433 }
434}
435
436impl<W, G, S, T> ServerBuilder<W, G, S, T> {
437 fn map<W2, G2, S2, T2>(
438 self,
439 f: impl FnOnce(W, G, S, T) -> (W2, G2, S2, T2),
440 ) -> ServerBuilder<W2, G2, S2, T2> {
441 let ServerBuilder {
442 listeners,
443 driver,
444 workers,
445 limits,
446 work,
447 gate,
448 sink,
449 tls,
450 control,
451 wipe,
452 clock,
453 trusted,
454 } = self;
455 let (work, gate, sink, tls) = f(work, gate, sink, tls);
456 ServerBuilder {
457 listeners,
458 driver,
459 workers,
460 limits,
461 work,
462 gate,
463 sink,
464 tls,
465 control,
466 wipe,
467 clock,
468 trusted,
469 }
470 }
471
472 pub fn trusted_proxies(mut self, proxies: TrustedProxies) -> Self {
475 self.trusted = Some(Arc::new(proxies));
476 self
477 }
478
479 pub fn listener(mut self, spec: ListenerSpec) -> Self {
481 self.listeners.push(spec);
482 self
483 }
484
485 pub fn driver(mut self, kind: DriverKind) -> Self {
487 self.driver = kind;
488 self
489 }
490
491 pub fn workers(mut self, n: u16) -> Self {
493 self.workers = Some(n);
494 self
495 }
496
497 pub fn limits(mut self, limits: Limits) -> Self {
499 self.limits = limits;
500 self
501 }
502
503 pub fn sessions<F: SessionFactory>(self, factory: F) -> ServerBuilder<Sessions<F>, G, S, T> {
505 self.map(|_, g, s, t| (Sessions { factory }, g, s, t))
506 }
507
508 pub fn handler<H>(self, handler: H) -> ServerBuilder<BlockingHandler<H>, G, S, T>
510 where
511 H: Fn(&mut TcpConnection) -> Result<(), NetError> + Send + Sync + 'static,
512 {
513 self.map(|_, g, s, t| (BlockingHandler { handler }, g, s, t))
514 }
515
516 pub fn tls<T2: TlsAcceptor>(self, acceptor: T2) -> ServerBuilder<W, G, S, T2> {
518 self.map(|w, g, s, _| (w, g, s, acceptor))
519 }
520
521 pub fn gate<G2: Gate>(self, gate: G2) -> ServerBuilder<W, G2, S, T> {
523 self.map(|w, _, s, t| (w, gate, s, t))
524 }
525
526 pub fn events<S2: EventSink>(self, sink: S2) -> ServerBuilder<W, G, S2, T> {
528 self.map(|w, g, _, t| (w, g, sink, t))
529 }
530
531 pub fn control<C: ControlLine>(mut self, line: Arc<C>) -> Self {
533 self.control = Some(line);
534 self
535 }
536
537 pub fn wipe_buffers(mut self, on: bool) -> Self {
539 self.wipe = on;
540 self
541 }
542
543 pub fn clock<K: Clock>(mut self, clock: Arc<K>) -> Self {
545 self.clock = Some(clock);
546 self
547 }
548}
549
550impl<W, G, S, T> ServerBuilder<W, G, S, T>
551where
552 W: Workload,
553 G: Gate,
554 S: EventSink,
555 T: TlsAcceptor,
556{
557 pub fn build(self) -> Result<Server, NetError> {
565 let requested = match self.driver {
567 DriverKind::Auto if <W as engine::Serve>::BLOCKING_ONLY => DriverKind::Blocking,
568 other => other,
569 };
570 let driver = match requested.resolve() {
571 DriverKind::Reactor if <W as engine::Serve>::BLOCKING_ONLY => {
572 return Err(invalid("driver", ConfigReason::Inconsistent));
573 }
574 DriverKind::Reactor if !DriverKind::reactor_built() => {
575 return Err(NetError::Unsupported {
576 feature: "the reactor driver",
577 platform: std::env::consts::OS,
578 });
579 }
580 DriverKind::Uring => {
581 return Err(NetError::Unsupported {
582 feature: "the io_uring driver (after 1.0.0)",
583 platform: std::env::consts::OS,
584 });
585 }
586 kind => kind,
587 };
588 if self.listeners.is_empty() {
589 return Err(invalid("listener", ConfigReason::Missing));
590 }
591 if self.listeners.len() > 64 {
592 return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
593 }
594 let workers = self.workers.unwrap_or_else(|| {
595 if driver == DriverKind::Reactor {
596 std::thread::available_parallelism()
597 .map_or(4, |n| u16::try_from(n.get()).unwrap_or(4096).min(4096))
598 } else {
599 128
600 }
601 });
602 if workers == 0 {
603 return Err(invalid("workers", ConfigReason::Zero));
604 }
605 if workers > 4096 {
606 return Err(invalid("workers", ConfigReason::TooLarge { max: 4096 }));
607 }
608 let mut listeners = self.listeners;
609 let has_tls = TypeId::of::<T>() != TypeId::of::<NoTls>();
610 let mut names = Vec::new();
611 for spec in &mut listeners {
612 check_spec(spec, self.trusted.as_ref(), has_tls, &names)?;
613 if let Some(n) = &spec.name {
614 names.push(n.clone());
615 }
616 }
617 let limits = if self.limits.max_connections().is_none() {
620 let cap = if driver == DriverKind::Reactor {
621 reactor_default_cap(workers)
622 } else {
623 u32::from(workers)
624 };
625 self.limits.to_builder().max_connections(cap).build()?
626 } else {
627 self.limits.clone()
628 };
629 limits.validate(workers, crate::sys::descriptor_limit())?;
630 for spec in &listeners {
631 limits.overlay(&spec.limits).validate(workers, None)?;
632 }
633 let tls: Option<Arc<dyn ErasedAcceptor>> = if has_tls {
634 Some(Arc::new(self.tls))
635 } else {
636 None
637 };
638 engine::start(engine::Config {
639 tls,
640 trusted: self.trusted,
641 listeners,
642 driver,
643 workers,
644 limits,
645 work: self.work,
646 gate: self.gate,
647 sink: self.sink,
648 control: self.control,
649 wipe: self.wipe,
650 clock: self.clock,
651 })
652 }
653}
654
655fn reactor_default_cap(workers: u16) -> u32 {
658 let wanted = 10_000u32;
659 match crate::sys::descriptor_limit() {
660 Some(have) => {
661 let spare = u64::from(workers).saturating_mul(2) + 64;
662 let room = have.saturating_sub(spare).clamp(16, u64::from(wanted));
663 u32::try_from(room).unwrap_or(wanted)
664 }
665 None => wanted,
666 }
667}
668
669fn invalid(field: &'static str, reason: ConfigReason) -> NetError {
670 NetError::InvalidConfig { field, reason }
671}
672
673#[must_use]
681#[derive(Clone, Debug, PartialEq, Eq)]
682pub struct AdoptSpec {
683 listener: String,
684 lane: Option<crate::info::Lane>,
685}
686
687impl AdoptSpec {
688 pub fn new(listener: &str) -> AdoptSpec {
690 AdoptSpec {
691 listener: listener.to_owned(),
692 lane: None,
693 }
694 }
695
696 pub fn lane(mut self, lane: crate::info::Lane) -> AdoptSpec {
698 self.lane = Some(lane);
699 self
700 }
701}
702
703fn check_spec(
706 spec: &mut ListenerSpec,
707 server_trusted: Option<&Arc<TrustedProxies>>,
708 has_tls: bool,
709 taken: &[String],
710) -> Result<(), NetError> {
711 if spec.name.is_none() {
712 spec.name = spec
713 .adopt
714 .as_ref()
715 .and_then(|h| h.name())
716 .map(str::to_owned);
717 }
718 let unix = spec.unix.is_some()
719 || spec
720 .adopt
721 .as_ref()
722 .is_some_and(|h| h.kind() == crate::info::Transport::Unix);
723 if unix && !cfg!(feature = "local") {
724 return Err(NetError::Unsupported {
725 feature: "Unix domain sockets (the `local` feature)",
726 platform: std::env::consts::OS,
727 });
728 }
729 if spec.tls {
730 if !cfg!(feature = "tls") {
731 return Err(NetError::Unsupported {
732 feature: "TLS (the `tls` feature)",
733 platform: std::env::consts::OS,
734 });
735 }
736 if !has_tls {
737 return Err(invalid("tls", ConfigReason::Missing));
738 }
739 }
740 if spec.proxy != ProxyMode::Off {
741 if !cfg!(feature = "proxy") {
742 return Err(NetError::Unsupported {
743 feature: "PROXY protocol (the `proxy` feature)",
744 platform: std::env::consts::OS,
745 });
746 }
747 if !unix {
749 let trusted = spec.trusted.clone().or_else(|| server_trusted.cloned());
750 match trusted {
751 Some(t) if !t.is_empty() => spec.trusted = Some(t),
752 _ => return Err(invalid("trusted_proxies", ConfigReason::Missing)),
754 }
755 }
756 }
757 if let Some(n) = &spec.name {
758 if n.len() > 64 {
759 return Err(invalid("name", ConfigReason::TooLarge { max: 64 }));
760 }
761 if taken.contains(n) {
762 return Err(invalid("name", ConfigReason::Inconsistent));
763 }
764 }
765 Ok(())
766}
767
768#[must_use = "dropping a Server stops it; call wait_for_stop() to run until a stop is requested"]
771pub struct Server {
772 pub(crate) shared: Arc<Shared>,
773 pub(crate) threads: Vec<JoinHandle<()>>,
774 pub(crate) listeners: Vec<ListenerInfo>,
775 pub(crate) stopped: bool,
776}
777
778impl Server {
779 pub fn open_door(&self) -> Result<(), NetError> {
785 self.shared.open_door()
786 }
787
788 pub fn close_door(&self) {
790 self.shared.close_door();
791 }
792
793 #[must_use]
795 pub fn door(&self) -> DoorState {
796 self.shared.door()
797 }
798
799 pub fn drain(&self, deadline: Instant) -> DrainReport {
802 self.shared.drain(deadline)
803 }
804
805 pub fn shutdown(mut self, deadline: Instant) -> DrainReport {
807 self.stop(deadline)
808 }
809
810 pub fn wait_for_stop(mut self) -> DrainReport {
813 let deadline = self.shared.wait_for_stop_request();
814 self.stop(deadline)
815 }
816
817 fn stop(&mut self, deadline: Instant) -> DrainReport {
818 if self.stopped {
819 return DrainReport {
820 graceful: 0,
821 killed: 0,
822 took: Duration::ZERO,
823 };
824 }
825 self.stopped = true;
826 let report = self.shared.drain(deadline);
827 self.shared.stop_threads();
828 for t in self.threads.drain(..) {
829 let _ = t.join();
830 }
831 self.shared.join_listeners();
832 report
833 }
834
835 pub fn adopt(&self, conn: TcpConnection, spec: AdoptSpec) -> Result<ConnectionId, NetError> {
862 let mut conn = conn;
863 let link = conn.take_link().ok_or(NetError::Closed)?;
864 let (Some(peer), Some(local)) =
865 (link.info.peer.socket_addr(), link.info.local.socket_addr())
866 else {
867 return Err(invalid("connection", ConfigReason::Inconsistent));
868 };
869 let stream = link
870 .into_stream(CloseReason::SessionClosed)
871 .and_then(crate::sys::Stream::into_tcp)
872 .ok_or(invalid("connection", ConfigReason::Inconsistent))?;
873 self.shared
874 .adopt(stream, peer, local, &spec.listener, spec.lane)
875 }
876
877 pub fn release_listeners(&self) -> Result<Vec<ListenerHandle>, NetError> {
887 self.shared.release_listeners()
888 }
889
890 pub fn add_listener(&mut self, spec: ListenerSpec) -> Result<ListenerId, NetError> {
914 let mut spec = spec;
915 if self.listeners.len() >= 64 {
916 return Err(invalid("listener", ConfigReason::TooLarge { max: 64 }));
917 }
918 let names: Vec<String> = self
919 .listeners
920 .iter()
921 .filter_map(|l| l.name.clone())
922 .collect();
923 check_spec(
924 &mut spec,
925 self.shared.trusted.as_ref(),
926 self.shared.tls.is_some(),
927 &names,
928 )?;
929 let workers = u16::try_from(self.shared.worker_count()).unwrap_or(u16::MAX);
930 self.shared
931 .base_limits
932 .overlay(&spec.limits)
933 .validate(workers, None)?;
934 let info = self.shared.add_listener(spec)?;
935 let id = info.id;
936 self.listeners.push(info);
937 Ok(id)
938 }
939
940 pub fn remove_listener(
950 &mut self,
951 id: ListenerId,
952 deadline: Instant,
953 ) -> Result<DrainReport, NetError> {
954 let report = self.shared.remove_listener(id, deadline)?;
955 self.listeners.retain(|l| l.id != id);
956 Ok(report)
957 }
958
959 #[must_use]
961 pub fn handle(&self) -> ServerHandle {
962 ServerHandle {
963 shared: self.shared.clone(),
964 }
965 }
966
967 #[must_use]
969 pub fn stats(&self) -> Stats {
970 self.shared.stats()
971 }
972
973 #[must_use]
975 pub fn listeners(&self) -> &[ListenerInfo] {
976 &self.listeners
977 }
978}
979
980impl Drop for Server {
981 fn drop(&mut self) {
982 let deadline = Instant::now() + self.shared.drain_timeout;
983 self.stop(deadline);
984 }
985}
986
987impl fmt::Debug for Server {
988 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
989 f.debug_struct("Server")
990 .field("listeners", &self.listeners)
991 .field("door", &self.door())
992 .finish()
993 }
994}
995
996#[derive(Clone)]
1010pub struct ServerHandle {
1011 pub(crate) shared: Arc<Shared>,
1012}
1013
1014impl ServerHandle {
1015 pub fn kill(&self, id: ConnectionId, reason: KillReason) -> bool {
1017 self.shared.kill(id, reason)
1018 }
1019
1020 pub fn close_door(&self) {
1022 self.shared.close_door();
1023 }
1024
1025 pub fn request_stop(&self) {
1027 self.shared.request_stop(None);
1028 }
1029
1030 pub fn wake_all(&self) {
1032 self.shared.wake_all();
1033 }
1034
1035 #[must_use]
1037 pub fn completer(&self, worker: WorkerId) -> Option<crate::completer::Completer> {
1038 self.shared.completer(worker)
1039 }
1040
1041 #[must_use]
1043 pub fn stats(&self) -> Stats {
1044 self.shared.stats()
1045 }
1046
1047 #[must_use]
1049 pub fn door(&self) -> DoorState {
1050 self.shared.door()
1051 }
1052}
1053
1054impl fmt::Debug for ServerHandle {
1055 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1056 f.debug_struct("ServerHandle")
1057 .field("door", &self.door())
1058 .finish()
1059 }
1060}
1061
1062impl Stats {
1063 pub(crate) fn from_parts(
1064 mut base: Stats,
1065 refused_by: [u64; RefusalCause::COUNT],
1066 closed_by: [u64; CloseReason::COUNT],
1067 ) -> Stats {
1068 base.refused_by = refused_by;
1069 base.closed_by = closed_by;
1070 base
1071 }
1072}