1use std::{
3 cell::RefCell,
4 collections::{HashMap, HashSet, VecDeque, hash_map::Entry},
5 hash::{DefaultHasher, Hash, Hasher},
6 io::Error as IoError,
7 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
8 os::unix::io::{AsRawFd, FromRawFd},
9 rc::Rc,
10 str::FromStr,
11 sync::LazyLock,
12 time::{Duration, Instant},
13};
14
15use mio::{
16 Events, Interest, Poll, Token,
17 net::{TcpListener as MioTcpListener, TcpStream, UdpSocket as MioUdpSocket},
18};
19use slab::Slab;
20use sozu_command::{
21 channel::Channel,
22 config::MetricDetailLevel,
23 logging,
24 proto::command::{
25 ActivateListener, AddBackend, CertificatesWithFingerprints, Cluster, ClusterHashes,
26 ClusterInformations, DeactivateListener, Event, EventKind, HttpListenerConfig,
27 HttpsListenerConfig, InitialState, ListenerType, LoadBalancingAlgorithms, LoadMetric,
28 MetricDetail, MetricsConfiguration, RemoveBackend, Request, ResponseContent,
29 ResponseStatus, ServerConfig, TcpListenerConfig as CommandTcpListener,
30 UdpListenerConfig as CommandUdpListener, UpdateHttpListenerConfig,
31 UpdateHttpsListenerConfig, UpdateTcpListenerConfig, UpdateUdpListenerConfig, WorkerRequest,
32 WorkerResponse, request::RequestType, response_content::ContentType,
33 },
34 ready::Ready,
35 scm_socket::{Listeners, ScmSocket, ScmSocketError},
36 state::ConfigState,
37};
38
39use crate::metrics::names;
40use crate::{
41 AcceptError, Protocol, ProxyConfiguration, ProxySession, SessionIsToBeClosed,
42 backends::{Backend, BackendMap},
43 features::FEATURES,
44 health_check::HealthChecker,
45 http, https,
46 metrics::METRICS,
47 pool::Pool,
48 tcp,
49 timer::Timer,
50 udp,
51};
52
53pub const CONN_RETRIES: u8 = 3;
55
56pub const PER_SOURCE_BUCKETS: usize = 256;
70
71static PER_SOURCE_BUCKET_KEYS: LazyLock<[&'static str; PER_SOURCE_BUCKETS]> = LazyLock::new(|| {
76 let mut keys: [&'static str; PER_SOURCE_BUCKETS] = [""; PER_SOURCE_BUCKETS];
77 for (i, slot) in keys.iter_mut().enumerate() {
78 let owned = format!("client.connect.per_source.bucket_{i:03}");
80 *slot = Box::leak(owned.into_boxed_str());
81 }
82 keys
83});
84
85fn per_source_bucket(peer: &SocketAddr) -> &'static str {
90 let mut hasher = DefaultHasher::new();
91 match peer.ip() {
92 IpAddr::V4(v4) => {
93 let octets = v4.octets();
94 let masked = Ipv4Addr::new(octets[0], octets[1], octets[2], 0);
96 masked.hash(&mut hasher);
97 }
98 IpAddr::V6(v6) => {
99 let octets = v6.octets();
100 let mut masked_octets = [0u8; 16];
102 masked_octets[..6].copy_from_slice(&octets[..6]);
103 Ipv6Addr::from(masked_octets).hash(&mut hasher);
104 }
105 }
106 let idx = (hasher.finish() as usize) % PER_SOURCE_BUCKETS;
107 PER_SOURCE_BUCKET_KEYS[idx]
108}
109
110const ACCEPT_SATURATION_TICK: Duration = Duration::from_secs(1);
115
116pub type ProxyChannel = Channel<WorkerResponse, WorkerRequest>;
117
118thread_local! {
119 pub static QUEUE: RefCell<VecDeque<WorkerResponse>> = const { RefCell::new(VecDeque::new()) };
120}
121
122thread_local! {
123 pub static TIMER: RefCell<Timer<Token>> = RefCell::new(Timer::default());
124}
125
126pub fn push_queue(message: WorkerResponse) {
127 QUEUE.with(|queue| {
128 (*queue.borrow_mut()).push_back(message);
129 });
130}
131
132pub fn push_event(event: Event) {
133 QUEUE.with(|queue| {
134 (*queue.borrow_mut()).push_back(WorkerResponse {
135 id: "EVENT".to_string(),
136 message: String::new(),
137 status: ResponseStatus::Processing.into(),
138 content: Some(ContentType::Event(event).into()),
139 });
140 });
141}
142
143fn worker_metric_detail_status_content(
149 configured: MetricDetailLevel,
150 effective: MetricDetailLevel,
151 previous_effective: MetricDetailLevel,
152 active_lease_count: u32,
153) -> ResponseContent {
154 use sozu_command::proto::command::WorkerMetricDetailStatus;
155 ContentType::WorkerMetricDetailStatus(WorkerMetricDetailStatus {
156 configured: MetricDetail::from(configured) as i32,
157 effective: MetricDetail::from(effective) as i32,
158 previous_effective: MetricDetail::from(previous_effective) as i32,
159 active_lease_count,
160 })
161 .into()
162}
163
164fn push_metric_detail_transition(
171 previous: MetricDetailLevel,
172 effective: MetricDetailLevel,
173 transition_kind: &'static str,
174 client_id: Option<String>,
175) {
176 use sozu_command::proto::command::MetricDetailTransition;
177 if previous == effective {
182 return;
183 }
184 push_event(Event {
185 kind: EventKind::MetricDetailChanged as i32,
186 cluster_id: None,
187 backend_id: None,
188 address: None,
189 metric_detail: Some(MetricDetailTransition {
190 previous_effective: MetricDetail::from(previous) as i32,
191 effective: MetricDetail::from(effective) as i32,
192 transition_kind: transition_kind.to_owned(),
193 client_id,
194 }),
195 });
196}
197
198#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
199pub struct ListenToken(pub usize);
200#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
201pub struct SessionToken(pub usize);
202
203impl From<usize> for ListenToken {
204 fn from(val: usize) -> ListenToken {
205 ListenToken(val)
206 }
207}
208
209impl From<ListenToken> for usize {
210 fn from(val: ListenToken) -> usize {
211 val.0
212 }
213}
214
215impl From<usize> for SessionToken {
216 fn from(val: usize) -> SessionToken {
217 SessionToken(val)
218 }
219}
220
221impl From<SessionToken> for usize {
222 fn from(val: SessionToken) -> usize {
223 val.0
224 }
225}
226
227pub struct SessionManager {
228 pub max_connections: usize,
229 pub nb_connections: usize,
230 pub can_accept: bool,
231 pub slab: Slab<Rc<RefCell<dyn ProxySession>>>,
232 pub max_connections_per_ip: u64,
236 pub retry_after: u32,
240 connections_per_cluster_ip: HashMap<String, HashMap<IpAddr, usize>>,
264 cluster_ip_tracks: HashMap<Token, HashMap<String, HashSet<IpAddr>>>,
271}
272
273impl SessionManager {
274 pub fn new(
275 slab: Slab<Rc<RefCell<dyn ProxySession>>>,
276 max_connections: usize,
277 max_connections_per_ip: u64,
278 retry_after: u32,
279 ) -> Rc<RefCell<Self>> {
280 Rc::new(RefCell::new(SessionManager {
281 max_connections,
282 nb_connections: 0,
283 can_accept: true,
284 slab,
285 max_connections_per_ip,
286 retry_after,
287 connections_per_cluster_ip: HashMap::new(),
288 cluster_ip_tracks: HashMap::new(),
289 }))
290 }
291
292 pub fn effective_max_connections_per_ip(&self, override_value: Option<u64>) -> u64 {
297 override_value.unwrap_or(self.max_connections_per_ip)
298 }
299
300 pub fn effective_retry_after(&self, override_value: Option<u32>) -> u32 {
304 override_value.unwrap_or(self.retry_after)
305 }
306
307 pub fn cluster_ip_at_limit(
319 &self,
320 token: Token,
321 cluster_id: &str,
322 ip: &IpAddr,
323 override_value: Option<u64>,
324 ) -> bool {
325 let limit = self.effective_max_connections_per_ip(override_value);
326 if limit == 0 {
327 return false;
328 }
329 debug_assert!(
332 limit > 0,
333 "limit==0 (unlimited) must have returned before reaching the bounded check"
334 );
335 let already_tracked = self
336 .cluster_ip_tracks
337 .get(&token)
338 .and_then(|by_cluster| by_cluster.get(cluster_id))
339 .is_some_and(|ips| ips.contains(ip));
340 if already_tracked {
341 debug_assert!(
345 self.connections_per_cluster_ip
346 .get(cluster_id)
347 .and_then(|by_ip| by_ip.get(ip))
348 .is_some_and(|c| *c > 0),
349 "a tracked (token, cluster, ip) slot must have a positive forward count"
350 );
351 return false;
352 }
353 self.connections_per_cluster_ip
354 .get(cluster_id)
355 .and_then(|by_ip| by_ip.get(ip))
356 .is_some_and(|c| (*c as u64) >= limit)
357 }
358
359 pub fn track_cluster_ip(&mut self, token: Token, cluster_id: String, ip: IpAddr) {
369 let count_before = self
373 .connections_per_cluster_ip
374 .get(&cluster_id)
375 .and_then(|by_ip| by_ip.get(&ip))
376 .copied()
377 .unwrap_or(0);
378 let inserted = self
379 .cluster_ip_tracks
380 .entry(token)
381 .or_default()
382 .entry(cluster_id.clone())
383 .or_default()
384 .insert(ip);
385 if inserted {
386 *self
387 .connections_per_cluster_ip
388 .entry(cluster_id.clone())
389 .or_default()
390 .entry(ip)
391 .or_insert(0) += 1;
392 }
393 debug_assert!(
397 self.cluster_ip_tracks
398 .get(&token)
399 .and_then(|by_cluster| by_cluster.get(&cluster_id))
400 .is_some_and(|ips| ips.contains(&ip)),
401 "track must leave the (token, cluster, ip) recorded in the reverse index"
402 );
403 debug_assert_eq!(
404 self.connections_per_cluster_ip
405 .get(&cluster_id)
406 .and_then(|by_ip| by_ip.get(&ip))
407 .copied()
408 .unwrap_or(0),
409 count_before + inserted as usize,
410 "forward count must advance by exactly 1 on first track, 0 on a repeat"
411 );
412 #[cfg(debug_assertions)]
413 self.check_invariants();
414 }
415
416 pub fn untrack_all_cluster_ip(&mut self, token: Token) {
423 let Some(by_cluster) = self.cluster_ip_tracks.remove(&token) else {
424 return;
425 };
426 debug_assert!(
429 !self.cluster_ip_tracks.contains_key(&token),
430 "untrack_all must evict the token from the reverse index"
431 );
432 for (cluster_id, ips) in by_cluster {
433 let Entry::Occupied(mut outer) = self.connections_per_cluster_ip.entry(cluster_id)
434 else {
435 continue;
436 };
437 for ip in ips {
438 if let Entry::Occupied(mut inner) = outer.get_mut().entry(ip) {
439 let count = inner.get_mut();
440 *count = count.saturating_sub(1);
441 if *count == 0 {
442 inner.remove();
443 }
444 }
445 }
446 if outer.get().is_empty() {
447 outer.remove();
448 }
449 }
450 debug_assert!(
453 self.connections_per_cluster_ip
454 .values()
455 .all(|by_ip| !by_ip.is_empty() && by_ip.values().all(|&c| c > 0)),
456 "untrack_all must not leave empty inner maps or zero-count ips behind"
457 );
458 #[cfg(debug_assertions)]
459 self.check_invariants();
460 }
461
462 pub fn clear_cluster_ip_tracking(&mut self) {
467 self.cluster_ip_tracks.clear();
468 self.connections_per_cluster_ip.clear();
469 debug_assert!(
472 self.cluster_ip_tracks.is_empty() && self.connections_per_cluster_ip.is_empty(),
473 "clear must wipe both the reverse index and the forward count map"
474 );
475 #[cfg(debug_assertions)]
476 self.check_invariants();
477 }
478
479 pub fn at_capacity(&self) -> bool {
481 self.slab.len() >= self.accept_slab_threshold()
482 }
483
484 pub fn accept_slab_threshold(&self) -> usize {
496 let threshold = 10 + 2 * self.max_connections;
497 debug_assert!(
501 threshold > self.max_connections,
502 "accept gate must sit strictly above max_connections to reserve system slots"
503 );
504 threshold
505 }
506
507 pub fn check_limits(&mut self) -> bool {
510 debug_assert!(
513 self.nb_connections <= self.max_connections,
514 "nb_connections must never exceed max_connections"
515 );
516 if self.nb_connections >= self.max_connections {
517 error!("max number of session connection reached, flushing the accept queue");
518 gauge!(names::accept_queue::BACKPRESSURE, 1);
519 self.can_accept = false;
520 debug_assert!(
522 !self.can_accept,
523 "refusing at the cap must clear can_accept"
524 );
525 return false;
526 }
527
528 if self.at_capacity() {
529 error!("not enough memory to accept another session, flushing the accept queue");
530 error!(
531 "nb_connections: {}, max_connections: {}",
532 self.nb_connections, self.max_connections
533 );
534 gauge!(names::accept_queue::BACKPRESSURE, 1);
535 self.can_accept = false;
536
537 debug_assert!(
538 !self.can_accept,
539 "refusing at slab capacity must clear can_accept"
540 );
541 return false;
542 }
543
544 debug_assert!(
546 self.nb_connections < self.max_connections && !self.at_capacity(),
547 "check_limits returned room while a gate was actually saturated"
548 );
549 true
550 }
551
552 pub fn to_session(token: Token) -> SessionToken {
553 SessionToken(token.0)
554 }
555
556 pub fn incr(&mut self) {
557 let before = self.nb_connections;
558 self.nb_connections += 1;
559 assert!(self.nb_connections <= self.max_connections);
560 debug_assert_eq!(
562 self.nb_connections,
563 before + 1,
564 "incr must raise nb_connections by exactly one"
565 );
566 gauge!(names::client::CONNECTIONS, self.nb_connections);
572 }
573
574 pub fn decr(&mut self) {
577 assert!(self.nb_connections != 0);
578 let before = self.nb_connections;
579 self.nb_connections -= 1;
580 debug_assert_eq!(
582 self.nb_connections,
583 before - 1,
584 "decr must lower nb_connections by exactly one"
585 );
586 gauge!(names::client::CONNECTIONS, self.nb_connections);
587
588 if !self.can_accept && self.nb_connections < self.max_connections * 90 / 100 {
590 debug!(
591 "nb_connections = {}, max_connections = {}, starting to accept again",
592 self.nb_connections, self.max_connections
593 );
594 gauge!(names::accept_queue::BACKPRESSURE, 0);
595 self.can_accept = true;
596 }
597 }
598
599 #[cfg(debug_assertions)]
604 fn check_invariants(&self) {
605 debug_assert!(
607 self.nb_connections <= self.max_connections,
608 "nb_connections {} exceeds max_connections {}",
609 self.nb_connections,
610 self.max_connections
611 );
612 debug_assert!(
615 self.connections_per_cluster_ip
616 .values()
617 .all(|by_ip| !by_ip.is_empty() && by_ip.values().all(|&c| c > 0)),
618 "connections_per_cluster_ip holds an empty inner map or a zero count"
619 );
620 debug_assert!(
625 self.cluster_ip_tracks.values().all(|by_cluster| {
626 by_cluster.iter().all(|(cluster_id, ips)| {
627 ips.iter().all(|ip| {
628 self.connections_per_cluster_ip
629 .get(cluster_id)
630 .and_then(|by_ip| by_ip.get(ip))
631 .is_some_and(|&c| c > 0)
632 })
633 })
634 }),
635 "a tracked (token, cluster, ip) slot has no positive forward count"
636 );
637 debug_assert!(
639 self.cluster_ip_tracks.values().all(|by_cluster| {
640 !by_cluster.is_empty() && by_cluster.values().all(|ips| !ips.is_empty())
641 }),
642 "cluster_ip_tracks retains an empty per-token or per-cluster entry"
643 );
644 }
645}
646
647#[derive(thiserror::Error, Debug)]
648pub enum ServerError {
649 #[error("could not create event loop with MIO poll: {0}")]
650 CreatePoll(IoError),
651 #[error("could not clone the MIO registry: {0}")]
652 CloneRegistry(IoError),
653 #[error("could not register the channel: {0}")]
654 RegisterChannel(IoError),
655 #[error("{msg}:{scm_err}")]
656 ScmSocket {
657 msg: String,
658 scm_err: ScmSocketError,
659 },
660}
661
662pub struct Server {
679 accept_queue_timeout: Duration,
680 accept_queue: VecDeque<(
687 TcpStream,
688 ListenToken,
689 Protocol,
690 Instant,
691 Option<SocketAddr>,
692 )>,
693 evict_on_queue_full: bool,
697 accept_ready: HashSet<ListenToken>,
698 backends: Rc<RefCell<BackendMap>>,
699 base_sessions_count: usize,
700 channel: ProxyChannel,
701 config_state: ConfigState,
702 current_poll_errors: i32,
703 health_checker: HealthChecker,
704 http: Rc<RefCell<http::HttpProxy>>,
705 https: Rc<RefCell<https::HttpsProxy>>,
706 last_sessions_len: usize,
707 last_shutting_down_message: Option<Instant>,
708 last_zombie_check: Instant,
709 loop_start: Instant,
710 started_at: Instant,
714 last_saturation_tick: Instant,
719 max_poll_errors: i32, pool: Rc<RefCell<Pool>>,
726 pub poll: Poll,
727 poll_timeout: Option<Duration>, scm_listeners: Option<Listeners>,
729 scm: ScmSocket,
730 sessions: Rc<RefCell<SessionManager>>,
731 should_poll_at: Option<Instant>,
732 shutting_down: Option<String>,
733 tcp: Rc<RefCell<tcp::TcpProxy>>,
734 udp: Rc<RefCell<udp::UdpProxy>>,
735 zombie_check_interval: Duration,
736}
737
738impl Server {
739 pub fn try_new_from_config(
740 worker_to_main_channel: ProxyChannel,
741 worker_to_main_scm: ScmSocket,
742 config: ServerConfig,
743 initial_state: InitialState,
744 expects_initial_status: bool,
745 ) -> Result<Self, ServerError> {
746 let event_loop = Poll::new().map_err(ServerError::CreatePoll)?;
747 if let Some(cap) = config.basic_auth_max_credential_bytes {
754 crate::protocol::mux::auth::set_max_decoded_credential_bytes(cap as usize);
755 }
756 #[cfg(all(target_os = "linux", feature = "splice"))]
763 if let Some(cap) = config.splice_pipe_capacity_bytes {
764 crate::splice::set_pipe_capacity(cap as usize);
765 }
766 let pool = Rc::new(RefCell::new(Pool::with_capacity(
767 config.min_buffers as usize,
768 config.max_buffers as usize,
769 config.buffer_size as usize,
770 )));
771 let backends = Rc::new(RefCell::new(BackendMap::new()));
772
773 let sessions: Rc<RefCell<SessionManager>> = SessionManager::new(
778 Slab::with_capacity(config.slab_capacity() as usize),
779 config.max_connections as usize,
780 config
781 .max_connections_per_ip
782 .unwrap_or(sozu_command::config::DEFAULT_MAX_CONNECTIONS_PER_IP),
783 config
784 .retry_after
785 .unwrap_or(sozu_command::config::DEFAULT_RETRY_AFTER),
786 );
787 {
788 let mut s = sessions.borrow_mut();
789 let entry = s.slab.vacant_entry();
790 trace!("taking token {:?} for channel", SessionToken(entry.key()));
791 entry.insert(Rc::new(RefCell::new(ListenSession {
792 protocol: Protocol::Channel,
793 })));
794 }
795 {
796 let mut s = sessions.borrow_mut();
797 let entry = s.slab.vacant_entry();
798 trace!("taking token {:?} for metrics", SessionToken(entry.key()));
799 entry.insert(Rc::new(RefCell::new(ListenSession {
800 protocol: Protocol::Timer,
801 })));
802 }
803 {
804 let mut s = sessions.borrow_mut();
805 let entry = s.slab.vacant_entry();
806 trace!("taking token {:?} for metrics", SessionToken(entry.key()));
807 entry.insert(Rc::new(RefCell::new(ListenSession {
808 protocol: Protocol::Metrics,
809 })));
810 }
811
812 Server::new(
813 event_loop,
814 worker_to_main_channel,
815 worker_to_main_scm,
816 sessions,
817 pool,
818 backends,
819 None,
820 None,
821 None,
822 config,
823 Some(initial_state),
824 expects_initial_status,
825 )
826 }
827
828 #[allow(clippy::too_many_arguments)]
829 pub fn new(
830 poll: Poll,
831 mut channel: ProxyChannel,
832 scm: ScmSocket,
833 sessions: Rc<RefCell<SessionManager>>,
834 pool: Rc<RefCell<Pool>>,
835 backends: Rc<RefCell<BackendMap>>,
836 http: Option<http::HttpProxy>,
837 https: Option<https::HttpsProxy>,
838 tcp: Option<tcp::TcpProxy>,
839 server_config: ServerConfig,
840 initial_state: Option<InitialState>,
841 expects_initial_status: bool,
842 ) -> Result<Self, ServerError> {
843 FEATURES.with(|_features| {
844 });
846
847 poll.registry()
848 .register(
849 &mut channel,
850 Token(0),
851 Interest::READABLE | Interest::WRITABLE,
852 )
853 .map_err(ServerError::RegisterChannel)?;
854
855 METRICS.with(|metrics| {
856 if let Some(sock) = (*metrics.borrow_mut()).socket_mut() {
857 poll.registry()
858 .register(sock, Token(2), Interest::WRITABLE)
859 .expect("should register the metrics socket");
860 }
861 });
862
863 let base_sessions_count = sessions.borrow().slab.len();
864
865 let http = Rc::new(RefCell::new(match http {
866 Some(http) => http,
867 None => {
868 let registry = poll
869 .registry()
870 .try_clone()
871 .map_err(ServerError::CloneRegistry)?;
872
873 http::HttpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
874 }
875 }));
876
877 let https = Rc::new(RefCell::new(match https {
878 Some(https) => https,
879 None => {
880 let registry = poll
881 .registry()
882 .try_clone()
883 .map_err(ServerError::CloneRegistry)?;
884
885 https::HttpsProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
886 }
887 }));
888
889 let tcp = Rc::new(RefCell::new(match tcp {
890 Some(tcp) => tcp,
891 None => {
892 let registry = poll
893 .registry()
894 .try_clone()
895 .map_err(ServerError::CloneRegistry)?;
896
897 tcp::TcpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
898 }
899 }));
900
901 let udp = Rc::new(RefCell::new({
905 let registry = poll
906 .registry()
907 .try_clone()
908 .map_err(ServerError::CloneRegistry)?;
909
910 udp::UdpProxy::new(
911 registry,
912 sessions.clone(),
913 pool.clone(),
914 backends.clone(),
915 server_config.max_connections as usize,
916 server_config.buffer_size as usize,
917 )
918 }));
919
920 let mut server = Server {
921 accept_queue_timeout: Duration::from_secs(u64::from(
922 server_config.accept_queue_timeout,
923 )),
924 accept_queue: VecDeque::new(),
925 evict_on_queue_full: server_config.evict_on_queue_full.unwrap_or(false),
926 accept_ready: HashSet::new(),
927 backends,
928 base_sessions_count,
929 channel,
930 config_state: ConfigState::new(),
931 current_poll_errors: 0,
932 health_checker: HealthChecker::new(),
933 http,
934 https,
935 last_sessions_len: 0, last_shutting_down_message: None,
937 last_zombie_check: Instant::now(), loop_start: Instant::now(), started_at: Instant::now(), last_saturation_tick: Instant::now(), max_poll_errors: 10000, pool,
943 poll_timeout: Some(Duration::from_millis(1000)), poll,
945 scm_listeners: None,
946 scm,
947 sessions,
948 should_poll_at: None,
949 shutting_down: None,
950 tcp,
951 udp,
952 zombie_check_interval: Duration::from_secs(u64::from(
953 server_config.zombie_check_interval,
954 )),
955 };
956
957 if let Some(state) = initial_state {
959 for request in state.requests {
960 trace!("generating initial config request: {:#?}", request);
961 server.notify_proxys(request);
962 }
963
964 QUEUE.with(|queue| {
966 (*queue.borrow_mut()).clear();
967 });
968 }
969
970 if expects_initial_status {
971 server.block_channel();
974 let msg = server.channel.read_message();
975 debug!("got message: {:?}", msg);
976
977 if let Ok(WorkerRequest {
978 id,
979 content:
980 Request {
981 request_type: Some(RequestType::Status(_)),
982 },
983 }) = msg
984 {
985 if let Err(e) = server.channel.write_message(&WorkerResponse::ok(id)) {
986 error!("Could not send an ok to the main process: {}", e);
987 }
988 } else {
989 panic!(
990 "plz give me a status request first when I start, you sent me this instead: {msg:?}"
991 );
992 }
993 server.unblock_channel();
994 }
995
996 info!("will try to receive listeners");
997 server
998 .scm
999 .set_blocking(true)
1000 .map_err(|scm_err| ServerError::ScmSocket {
1001 msg: "Could not set the scm socket to blocking".to_string(),
1002 scm_err,
1003 })?;
1004 let listeners =
1005 server
1006 .scm
1007 .receive_listeners()
1008 .map_err(|scm_err| ServerError::ScmSocket {
1009 msg: "could not receive listeners from the scm socket".to_string(),
1010 scm_err,
1011 })?;
1012 server
1013 .scm
1014 .set_blocking(false)
1015 .map_err(|scm_err| ServerError::ScmSocket {
1016 msg: "Could not set the scm socket to unblocking".to_string(),
1017 scm_err,
1018 })?;
1019 info!("received listeners: {:?}", listeners);
1020 server.scm_listeners = Some(listeners);
1021
1022 Ok(server)
1023 }
1024
1025 pub fn run(&mut self) {
1027 let mut events = Events::with_capacity(1024); self.last_sessions_len = self.sessions.borrow().slab.len();
1029
1030 self.last_zombie_check = Instant::now();
1031 self.loop_start = Instant::now();
1032
1033 loop {
1034 self.check_for_poll_errors();
1035
1036 let timeout = self.reset_loop_time_and_get_timeout();
1037
1038 match self.poll.poll(&mut events, timeout) {
1039 Ok(_) => self.current_poll_errors = 0,
1040 Err(error) => {
1041 error!("Error while polling events: {:?}", error);
1042 self.current_poll_errors += 1;
1043 continue;
1044 }
1045 }
1046
1047 let after_epoll = Instant::now();
1048 time!(
1049 names::event_loop::EPOLL_TIME,
1050 (after_epoll - self.loop_start).as_millis()
1051 );
1052 self.loop_start = after_epoll;
1053
1054 self.send_queue();
1055
1056 for event in events.iter() {
1057 match event.token() {
1058 Token(0) => {
1060 if event.is_error() {
1061 error!("error reading from command channel");
1062 continue;
1063 }
1064 if event.is_read_closed() || event.is_write_closed() {
1065 error!("command channel was closed");
1066 return;
1067 }
1068 let ready = Ready::from(event);
1069 self.channel.handle_events(ready);
1070
1071 loop {
1073 QUEUE.with(|queue| {
1074 if !(*queue.borrow()).is_empty() {
1075 self.channel.interest.insert(Ready::WRITABLE);
1076 }
1077 });
1078
1079 if self.channel.readiness() == Ready::EMPTY {
1082 break;
1083 }
1084
1085 if self.read_channel_messages_and_notify() {
1087 return;
1088 }
1089
1090 QUEUE.with(|queue| {
1091 if !(*queue.borrow()).is_empty() {
1092 self.channel.interest.insert(Ready::WRITABLE);
1093 }
1094 });
1095
1096 self.send_queue();
1097 }
1098 }
1099 Token(1) => {
1101 while let Some(t) = TIMER.with(|timer| timer.borrow_mut().poll()) {
1102 self.timeout(t);
1103 }
1104 }
1105 Token(2) => METRICS.with(|metrics| {
1107 (*metrics.borrow_mut()).writable();
1108 }),
1109 token if self.health_checker.owns_token(token) => {
1112 self.health_checker.ready(token);
1113 }
1114 token if self.udp.borrow().health_owns_token(token) => {
1115 self.udp.borrow_mut().health_ready(token);
1116 }
1117 token => self.ready(token, Ready::from(event)),
1118 }
1119 }
1120
1121 if let Some(t) = self.should_poll_at.as_ref()
1122 && *t <= Instant::now()
1123 {
1124 while let Some(t) = TIMER.with(|timer| timer.borrow_mut().poll()) {
1125 self.timeout(t);
1127 }
1128 }
1129 self.handle_remaining_readiness();
1130 self.create_sessions();
1131
1132 self.should_poll_at = TIMER.with(|timer| timer.borrow().next_poll_date());
1133
1134 self.zombie_check();
1135 self.health_checker
1136 .poll(&self.backends, self.poll.registry());
1137 self.udp.borrow_mut().health_poll();
1141
1142 {
1155 let sessions = self.sessions.borrow();
1156 let nb_connections = sessions.nb_connections;
1157 let max_connections = sessions.max_connections;
1158 let slab_len = sessions.slab.len();
1159 let slab_capacity = sessions.slab.capacity();
1160 let accept_threshold = sessions.accept_slab_threshold();
1161
1162 gauge!(names::client::CONNECTIONS, nb_connections);
1163 gauge!(names::client::CONNECTIONS_MAX, max_connections);
1164 if let Some(percent) = (nb_connections * 100).checked_div(max_connections) {
1165 gauge!("client.connections_percent", percent);
1166 }
1167
1168 gauge!(names::slab::ENTRIES, slab_len);
1169 gauge!(names::slab::CAPACITY, slab_capacity);
1170 if let Some(percent) = (slab_len * 100).checked_div(slab_capacity) {
1171 gauge!(names::slab::USAGE_PERCENT, percent);
1172 }
1173 if let Some(percent) = (slab_len * 100).checked_div(accept_threshold) {
1174 gauge!("slab.accept_threshold_percent", percent);
1175 }
1176 }
1177 {
1183 let pool = self.pool.borrow();
1184 let used = pool.inner.used();
1185 let capacity = pool.inner.capacity();
1186 gauge!(names::buffer::IN_USE, used);
1187 gauge!(names::buffer::CAPACITY, capacity);
1188 if let Some(percent) = (used * 100).checked_div(capacity) {
1189 gauge!(names::buffer::USAGE_PERCENT, percent);
1190 }
1191 }
1192 let now = Instant::now();
1200 if now.duration_since(self.last_saturation_tick) >= ACCEPT_SATURATION_TICK {
1201 if !self.sessions.borrow().can_accept {
1202 incr!(names::accept_queue::SATURATED_SECONDS);
1203 }
1204 self.last_saturation_tick = now;
1205 }
1206 gauge!(
1210 "process.uptime_seconds",
1211 self.started_at.elapsed().as_secs() as usize
1212 );
1213 gauge!(
1218 "server.live",
1219 if self.shutting_down.is_some() { 0 } else { 1 }
1220 );
1221 METRICS.with(|metrics| {
1222 (*metrics.borrow_mut()).send_data();
1223 });
1224
1225 if self.shutting_down.is_some() && self.shut_down_sessions() {
1226 return;
1227 }
1228 }
1229 }
1230
1231 fn check_for_poll_errors(&mut self) {
1232 if self.current_poll_errors >= self.max_poll_errors {
1233 error!(
1234 "Something is going very wrong. Last {} poll() calls failed, crashing..",
1235 self.current_poll_errors
1236 );
1237 panic!(
1238 "poll() calls failed {} times in a row",
1239 self.current_poll_errors
1240 );
1241 }
1242 }
1243
1244 fn reset_loop_time_and_get_timeout(&mut self) -> Option<Duration> {
1245 let now = Instant::now();
1246 time!(
1247 names::event_loop::EVENT_LOOP_TIME,
1248 (now - self.loop_start).as_millis()
1249 );
1250
1251 let mut timeout = match self.should_poll_at.as_ref() {
1252 None => self.poll_timeout,
1253 Some(i) => {
1254 if *i <= now {
1255 self.poll_timeout
1256 } else {
1257 let dur = *i - now;
1258 match self.poll_timeout {
1259 None => Some(dur),
1260 Some(t) => {
1261 if t < dur {
1262 Some(t)
1263 } else {
1264 Some(dur)
1265 }
1266 }
1267 }
1268 }
1269 }
1270 };
1271
1272 if self.shutting_down.is_some() {
1273 let shutdown_tick = Duration::from_millis(100);
1274 timeout = match timeout {
1275 None => Some(shutdown_tick),
1276 Some(current) => Some(current.min(shutdown_tick)),
1277 };
1278 }
1279
1280 self.loop_start = now;
1281 timeout
1282 }
1283
1284 fn read_channel_messages_and_notify(&mut self) -> bool {
1286 if !self.channel.readiness().is_readable() {
1287 return false;
1288 }
1289
1290 if let Err(e) = self.channel.readable() {
1291 error!("error reading from channel: {:?}", e);
1292 }
1293
1294 loop {
1295 let request = self.channel.read_message();
1296 debug!("Received request {:?}", request);
1297 match request {
1298 Ok(request) => match request.content.request_type {
1299 Some(RequestType::HardStop(_)) => {
1300 let req_id = request.id.clone();
1301 self.notify(request);
1302 if let Err(e) = self.channel.write_message(&WorkerResponse::ok(req_id)) {
1303 error!("Could not send ok response to the main process: {}", e);
1304 }
1305 if let Err(e) = self.channel.run() {
1306 error!("Error while running the server channel: {}", e);
1307 }
1308 return true;
1309 }
1310 Some(RequestType::SoftStop(_)) => {
1311 self.shutting_down = Some(request.id.clone());
1312 self.last_sessions_len = self.sessions.borrow().slab.len();
1313 self.notify(request);
1314 }
1315 Some(RequestType::ReturnListenSockets(_)) => {
1316 info!("received ReturnListenSockets order");
1317 match self.return_listen_sockets() {
1318 Ok(_) => push_queue(WorkerResponse::ok(request.id)),
1319 Err(error) => push_queue(worker_response_error(
1320 request.id,
1321 format!("Could not send listeners on scm socket: {error:?}"),
1322 )),
1323 }
1324 }
1325 _ => self.notify(request),
1326 },
1327 Err(_) => {
1329 if (self.channel.interest & self.channel.readiness).is_readable() {
1331 if let Err(e) = self.channel.readable() {
1332 error!("error reading from channel: {:?}", e);
1333 }
1334 continue;
1335 }
1336 break;
1337 }
1338 }
1339 }
1340 false
1341 }
1342
1343 fn zombie_check(&mut self) {
1345 let now = Instant::now();
1346 if now - self.last_zombie_check < self.zombie_check_interval {
1347 return;
1348 }
1349 info!("zombie check");
1350 debug_assert!(
1353 now >= self.last_zombie_check,
1354 "zombie-check timestamp must never move backwards"
1355 );
1356 self.last_zombie_check = now;
1357
1358 let mut zombie_tokens = HashSet::new();
1359
1360 for (_index, session) in self
1362 .sessions
1363 .borrow_mut()
1364 .slab
1365 .iter_mut()
1366 .filter(|(_, c)| now - c.borrow().last_event() > self.zombie_check_interval)
1367 {
1368 let session_token = session.borrow().frontend_token();
1369 if !zombie_tokens.contains(&session_token) {
1370 session.borrow().print_session();
1371 zombie_tokens.insert(session_token);
1372 }
1373 }
1374
1375 debug_assert!(
1380 !self.sessions.borrow().slab.iter().any(|(_, session)| {
1381 let s = session.borrow();
1382 zombie_tokens.contains(&s.frontend_token())
1383 && matches!(
1384 s.protocol(),
1385 Protocol::HTTPListen | Protocol::HTTPSListen | Protocol::TCPListen
1386 )
1387 }),
1388 "zombie reaping must never target a listener session"
1389 );
1390
1391 let zombie_count = zombie_tokens.len() as i64;
1392 count!(names::misc::ZOMBIES, zombie_count);
1393
1394 let remaining_count = self.shut_down_sessions_by_frontend_tokens(zombie_tokens);
1395 info!(
1396 "removing {} zombies ({} remaining entries after close)",
1397 zombie_count, remaining_count
1398 );
1399 }
1400
1401 fn shut_down_sessions_by_frontend_tokens(&self, tokens: HashSet<Token>) -> usize {
1404 if tokens.is_empty() {
1405 return 0;
1406 }
1407
1408 for token in &tokens {
1410 if self.sessions.borrow().slab.contains(token.0) {
1411 let slab_before = self.sessions.borrow().slab.len();
1412 let session = { self.sessions.borrow_mut().slab.remove(token.0) };
1413 session.borrow_mut().close();
1414 self.sessions.borrow_mut().decr();
1415 debug_assert!(
1420 !self.sessions.borrow().slab.contains(token.0),
1421 "removed token must be absent from the slab"
1422 );
1423 debug_assert!(
1424 self.sessions.borrow().slab.len() < slab_before,
1425 "removing a present session must free at least its own slab slot"
1426 );
1427 }
1428 }
1429
1430 let mut dangling_entries = HashSet::new();
1432 for (entry_key, session) in &self.sessions.borrow().slab {
1433 if tokens.contains(&session.borrow().frontend_token()) {
1434 dangling_entries.insert(entry_key);
1435 }
1436 }
1437
1438 let mut dangling_entries_count = 0;
1440 for entry_key in dangling_entries {
1441 let mut sessions = self.sessions.borrow_mut();
1442 if sessions.slab.contains(entry_key) {
1443 sessions.slab.remove(entry_key);
1444 dangling_entries_count += 1;
1445 }
1446 }
1447 debug_assert!(
1451 !self
1452 .sessions
1453 .borrow()
1454 .slab
1455 .iter()
1456 .any(|(_, session)| tokens.contains(&session.borrow().frontend_token())),
1457 "no slab entry may reference a closed frontend token after teardown"
1458 );
1459 dangling_entries_count
1460 }
1461
1462 fn shut_down_sessions(&mut self) -> bool {
1464 let sessions_count = self.sessions.borrow().slab.len();
1465 let mut sessions_to_shut_down = HashSet::new();
1466
1467 for (_key, session) in &self.sessions.borrow().slab {
1468 let mut session = session.borrow_mut();
1469 if session.shutting_down() {
1470 debug!(
1471 "Server killing session from shutting_down: token={:?}, protocol={:?}",
1472 session.frontend_token(),
1473 session.protocol()
1474 );
1475 sessions_to_shut_down.insert(Token(session.frontend_token().0));
1476 }
1477 }
1478 let _ = self.shut_down_sessions_by_frontend_tokens(sessions_to_shut_down);
1479
1480 let new_sessions_count = self.sessions.borrow().slab.len();
1481
1482 if new_sessions_count < sessions_count {
1483 let now = Instant::now();
1484 if let Some(last) = self.last_shutting_down_message
1485 && (now - last) > Duration::from_secs(5)
1486 {
1487 info!(
1488 "closed {} sessions, {} sessions left, base_sessions_count = {}",
1489 sessions_count - new_sessions_count,
1490 new_sessions_count,
1491 self.base_sessions_count
1492 );
1493 }
1494 self.last_shutting_down_message = Some(now);
1495 }
1496
1497 if new_sessions_count <= self.base_sessions_count {
1498 info!("last session stopped, shutting down!");
1499 if let Err(e) = self.channel.run() {
1500 error!("Error while running the server channel: {}", e);
1501 }
1502 let id = self
1504 .shutting_down
1505 .take()
1506 .expect("should have shut down correctly"); debug!("Responding OK to main process for request {}", id);
1509
1510 let proxy_response = WorkerResponse::ok(id);
1511 if let Err(e) = self.channel.write_message(&proxy_response) {
1512 error!("Could not write response to the main process: {}", e);
1513 }
1514 if let Err(e) = self.channel.run() {
1515 error!("Error while running the server channel: {}", e);
1516 }
1517 return true;
1518 }
1519
1520 if new_sessions_count < self.last_sessions_len {
1521 info!(
1522 "shutting down, {} slab elements remaining (base: {})",
1523 new_sessions_count - self.base_sessions_count,
1524 self.base_sessions_count
1525 );
1526 self.last_sessions_len = new_sessions_count;
1527 }
1528
1529 false
1530 }
1531
1532 fn kill_session(&self, session: Rc<RefCell<dyn ProxySession>>) {
1533 let token = session.borrow().frontend_token();
1534 let _ = self.shut_down_sessions_by_frontend_tokens(HashSet::from([token]));
1535 }
1536
1537 fn send_queue(&mut self) {
1538 if self.channel.readiness.is_writable() {
1539 QUEUE.with(|q| {
1540 let mut queue = q.borrow_mut();
1541 loop {
1542 if let Some(resp) = queue.pop_front() {
1543 debug!("Sending response {:?}", resp);
1544 if let Err(e) = self.channel.write_message(&resp) {
1545 error!("Could not write message {} on the channel: {}", resp, e);
1546 queue.push_front(resp);
1547 }
1548 }
1549
1550 if self.channel.back_buf.available_data() > 0
1551 && let Err(e) = self.channel.writable()
1552 {
1553 error!("error writing to channel: {:?}", e);
1554 }
1555
1556 if !self.channel.readiness.is_writable() {
1557 break;
1558 }
1559
1560 if self.channel.back_buf.available_data() == 0 && queue.is_empty() {
1561 break;
1562 }
1563 }
1564 });
1565 }
1566 }
1567
1568 fn notify(&mut self, message: WorkerRequest) {
1569 let now = std::time::Instant::now();
1576 let lease_tick_transition = METRICS.with(|metrics| {
1582 let mut m = metrics.borrow_mut();
1583 if !m.lease_tick_due(now) {
1584 return None;
1585 }
1586 let previous = m.lease_tick(now)?;
1587 let effective = m.detail_effective();
1588 Some((previous, effective))
1589 });
1590 if let Some((previous, effective)) = lease_tick_transition {
1591 push_metric_detail_transition(previous, effective, "lease_tick_expired", None);
1598 }
1599 match &message.content.request_type {
1600 Some(RequestType::ConfigureMetrics(configuration)) => {
1601 match MetricsConfiguration::try_from(*configuration) {
1602 Ok(metrics_config) => {
1603 METRICS.with(|metrics| {
1604 (*metrics.borrow_mut()).configure(&metrics_config);
1605 push_queue(WorkerResponse::ok(message.id));
1606 });
1607 }
1608 Err(e) => {
1609 error!("Error configuring metrics: {}", e);
1610 push_queue(WorkerResponse::error(message.id, e));
1611 }
1612 }
1613 return;
1614 }
1615 Some(RequestType::QueryMetrics(query_metrics_options)) => {
1616 METRICS.with(|metrics| {
1617 match (*metrics.borrow_mut()).query(query_metrics_options) {
1618 Ok(c) => push_queue(WorkerResponse::ok_with_content(message.id, c)),
1619 Err(e) => {
1620 error!("Error querying metrics: {}", e);
1621 push_queue(WorkerResponse::error(message.id, e))
1622 }
1623 }
1624 });
1625 return;
1626 }
1627 Some(RequestType::SetMetricDetail(req)) => {
1634 let presented_binding = crate::metrics::PeerBinding {
1641 pid: req.peer_pid,
1642 session_ulid: req.peer_session_ulid.as_deref().and_then(|s| {
1648 rusty_ulid::Ulid::from_str(s)
1649 .map(u128::from)
1650 .ok()
1651 .or_else(|| u128::from_str_radix(s.trim_start_matches("0x"), 16).ok())
1652 }),
1653 };
1654 if req.clear.unwrap_or(false) {
1655 if req.client_id.len() > crate::metrics::LEASE_CLIENT_ID_MAX_BYTES {
1666 let msg = format!(
1667 "SetMetricDetail: clear client_id length {} exceeds {} bytes",
1668 req.client_id.len(),
1669 crate::metrics::LEASE_CLIENT_ID_MAX_BYTES,
1670 );
1671 error!("{}", msg);
1672 push_queue(WorkerResponse::error(message.id.clone(), msg));
1673 return;
1674 }
1675 let (outcome, effective_after, configured_after, lease_count_after) = METRICS
1683 .with(|metrics| {
1684 let mut m = metrics.borrow_mut();
1685 let outcome = m.lease_clear(&req.client_id, presented_binding);
1686 (
1687 outcome,
1688 m.detail_effective(),
1689 m.detail_configured(),
1690 m.lease_count(),
1691 )
1692 });
1693 match outcome {
1694 crate::metrics::LeaseClearOutcome::Cleared { previous_effective } => {
1695 push_metric_detail_transition(
1696 previous_effective,
1697 effective_after,
1698 "lease_clear",
1699 Some(req.client_id.clone()),
1700 );
1701 push_queue(WorkerResponse::ok_with_content(
1702 message.id.clone(),
1703 worker_metric_detail_status_content(
1704 configured_after,
1705 effective_after,
1706 previous_effective,
1707 lease_count_after,
1708 ),
1709 ));
1710 }
1711 crate::metrics::LeaseClearOutcome::NotFound => {
1712 push_queue(WorkerResponse::ok_with_content(
1716 message.id.clone(),
1717 worker_metric_detail_status_content(
1718 configured_after,
1719 effective_after,
1720 effective_after,
1721 lease_count_after,
1722 ),
1723 ));
1724 }
1725 crate::metrics::LeaseClearOutcome::Unauthorized => {
1726 let msg = "SetMetricDetail: clear refused (peer \
1737 binding does not match the apply-time owner)"
1738 .to_owned();
1739 error!("{}", msg);
1740 push_queue(WorkerResponse::error(message.id.clone(), msg));
1741 }
1742 }
1743 return;
1744 }
1745 let detail_proto = match req.detail {
1746 Some(d) => d,
1747 None => {
1748 let msg = "SetMetricDetail without `detail` and without `clear`".to_owned();
1755 error!("{}", msg);
1756 push_queue(WorkerResponse::error(message.id.clone(), msg));
1757 return;
1758 }
1759 };
1760 let detail_enum = match MetricDetail::try_from(detail_proto) {
1761 Ok(d) => d,
1762 Err(e) => {
1763 let msg =
1764 format!("SetMetricDetail: invalid MetricDetail variant {detail_proto}");
1765 error!("{}: {}", msg, e);
1766 push_queue(WorkerResponse::error(message.id.clone(), msg));
1767 return;
1768 }
1769 };
1770 let level = MetricDetailLevel::from(detail_enum);
1771 if let Some(t) = req.ttl_seconds
1780 && u64::from(t) > crate::metrics::LEASE_TTL_MAX.as_secs()
1781 {
1782 let msg = format!(
1783 "SetMetricDetail: ttl_seconds={t} exceeds LEASE_TTL_MAX={}",
1784 crate::metrics::LEASE_TTL_MAX.as_secs()
1785 );
1786 error!("{}", msg);
1787 push_queue(WorkerResponse::error(message.id.clone(), msg));
1788 return;
1789 }
1790 let ttl_seconds = req.ttl_seconds.filter(|&t| t > 0).unwrap_or_else(|| {
1791 u32::try_from(crate::metrics::LEASE_TTL_DEFAULT.as_secs()).unwrap_or(60)
1798 });
1799 let ttl = std::time::Duration::from_secs(ttl_seconds.into());
1800 let (outcome, configured_after, lease_count_after) = METRICS.with(|metrics| {
1801 let mut m = metrics.borrow_mut();
1802 let outcome =
1803 m.lease_apply(req.client_id.clone(), level, ttl, presented_binding);
1804 (outcome, m.detail_configured(), m.lease_count())
1805 });
1806 match outcome {
1807 crate::metrics::LeaseApplyOutcome::Applied {
1808 previous_effective,
1809 new_effective,
1810 } => {
1811 push_metric_detail_transition(
1812 previous_effective,
1813 new_effective,
1814 "lease_apply",
1815 Some(req.client_id.clone()),
1816 );
1817 push_queue(WorkerResponse::ok_with_content(
1818 message.id.clone(),
1819 worker_metric_detail_status_content(
1820 configured_after,
1821 new_effective,
1822 previous_effective,
1823 lease_count_after,
1824 ),
1825 ));
1826 }
1827 crate::metrics::LeaseApplyOutcome::ClientIdTooLong => {
1828 let msg = format!(
1829 "SetMetricDetail: client_id length {} exceeds {} bytes",
1830 req.client_id.len(),
1831 crate::metrics::LEASE_CLIENT_ID_MAX_BYTES,
1832 );
1833 error!("{}", msg);
1834 push_queue(WorkerResponse::error(message.id.clone(), msg));
1835 }
1836 crate::metrics::LeaseApplyOutcome::TableFull => {
1837 let msg = format!(
1844 "SetMetricDetail: lease table at capacity ({} entries); reject new \
1845 apply — operators must retry after an active lease expires or is \
1846 cleared",
1847 crate::metrics::LEASE_TABLE_CAP,
1848 );
1849 error!("{}", msg);
1850 push_queue(WorkerResponse::error(message.id.clone(), msg));
1851 }
1852 crate::metrics::LeaseApplyOutcome::TtlOutOfRange => {
1853 let msg = format!(
1859 "SetMetricDetail: ttl exceeds LEASE_TTL_MAX={} (internal contract \
1860 violation: dispatch gate should have rejected)",
1861 crate::metrics::LEASE_TTL_MAX.as_secs(),
1862 );
1863 error!("{}", msg);
1864 push_queue(WorkerResponse::error(message.id.clone(), msg));
1865 }
1866 crate::metrics::LeaseApplyOutcome::Unauthorized => {
1867 let msg = "SetMetricDetail: renewal refused (peer binding does not \
1876 match the apply-time owner)"
1877 .to_owned();
1878 error!("{}", msg);
1879 push_queue(WorkerResponse::error(message.id.clone(), msg));
1880 }
1881 }
1882 return;
1883 }
1884 Some(RequestType::Logging(logging_filter)) => {
1885 info!(
1886 "{} changing logging filter to {}",
1887 message.id, logging_filter
1888 );
1889 let (directives, _errors) = logging::parse_logging_spec(logging_filter);
1891 logging::LOGGER.with(|logger| {
1892 logger.borrow_mut().set_directives(directives);
1893 });
1894 push_queue(WorkerResponse::ok(message.id));
1895 return;
1896 }
1897 Some(RequestType::QueryClustersHashes(_)) => {
1898 push_queue(WorkerResponse::ok_with_content(
1899 message.id.clone(),
1900 ContentType::ClusterHashes(ClusterHashes {
1901 map: self.config_state.hash_state(),
1902 })
1903 .into(),
1904 ));
1905 return;
1906 }
1907 Some(RequestType::QueryClusterById(cluster_id)) => {
1908 push_queue(WorkerResponse::ok_with_content(
1909 message.id.clone(),
1910 ContentType::Clusters(ClusterInformations {
1911 vec: self
1912 .config_state
1913 .cluster_state(cluster_id)
1914 .map_or(vec![], |ci| vec![ci]),
1915 })
1916 .into(),
1917 ));
1918 }
1919 Some(RequestType::SetMaxConnectionsPerIp(limit)) => {
1920 let mut sessions = self.sessions.borrow_mut();
1921 let previous = sessions.max_connections_per_ip;
1922 sessions.max_connections_per_ip = *limit;
1923 if *limit == 0 {
1928 sessions.clear_cluster_ip_tracking();
1929 }
1930 info!(
1931 "{} updated global max_connections_per_ip from {} to {}",
1932 message.id, previous, limit
1933 );
1934 push_queue(WorkerResponse::ok(message.id));
1935 return;
1936 }
1937 Some(RequestType::QueryMaxConnectionsPerIp(_)) => {
1938 let limit = self.sessions.borrow().max_connections_per_ip;
1939 push_queue(WorkerResponse::ok_with_content(
1940 message.id,
1941 ContentType::MaxConnectionsPerIpLimit(
1942 sozu_command::proto::command::MaxConnectionsPerIpLimit { limit },
1943 )
1944 .into(),
1945 ));
1946 return;
1947 }
1948 Some(RequestType::QueryClustersByDomain(domain)) => {
1949 let cluster_ids = self
1950 .config_state
1951 .get_cluster_ids_by_domain(domain.hostname.clone(), domain.path.clone());
1952 let vec = cluster_ids
1953 .iter()
1954 .filter_map(|cluster_id| self.config_state.cluster_state(cluster_id))
1955 .collect();
1956
1957 push_queue(WorkerResponse::ok_with_content(
1958 message.id.clone(),
1959 ContentType::Clusters(ClusterInformations { vec }).into(),
1960 ));
1961 return;
1962 }
1963 Some(RequestType::QueryCertificatesFromWorkers(filters))
1964 if filters.fingerprint.is_some() =>
1965 {
1966 let certs = self.config_state.get_certificates(filters.clone());
1967 let response = if !certs.is_empty() {
1968 WorkerResponse::ok_with_content(
1969 message.id.clone(),
1970 ContentType::CertificatesWithFingerprints(CertificatesWithFingerprints {
1971 certs,
1972 })
1973 .into(),
1974 )
1975 } else {
1976 worker_response_error(
1977 message.id.clone(),
1978 "Could not find certificate for this fingerprint",
1979 )
1980 };
1981 push_queue(response);
1982 return;
1983 }
1984 _other_request => {}
1987 }
1988 self.notify_proxys(message);
1989 }
1990
1991 pub fn notify_proxys(&mut self, request: WorkerRequest) {
1992 if let Err(e) = self.config_state.dispatch(&request.content) {
1993 error!("Could not execute order on config state: {}", e);
1994 }
1995
1996 let req_id = request.id.clone();
1997
1998 match request.content.request_type {
1999 Some(RequestType::AddCluster(ref cluster)) => {
2000 if let Some(hc) = cluster.health_check.as_ref()
2008 && let Err(reason) = sozu_command::config::validate_health_check_config(hc)
2009 {
2010 push_queue(worker_response_error(req_id, reason));
2011 return;
2012 }
2013 self.add_cluster(cluster);
2014 METRICS.with(|metrics| {
2019 (*metrics.borrow_mut()).add_cluster(&cluster.cluster_id);
2020 });
2021 }
2023 Some(RequestType::RemoveCluster(ref cluster_id)) => {
2024 self.remove_health_check_state(cluster_id);
2025 METRICS.with(|metrics| {
2026 (*metrics.borrow_mut()).remove_cluster(cluster_id);
2027 });
2028 }
2030 Some(RequestType::SetHealthCheck(ref set)) => {
2031 if let Err(reason) = sozu_command::config::validate_health_check_config(&set.config)
2032 {
2033 push_queue(worker_response_error(req_id, reason));
2034 return;
2035 }
2036 self.backends
2037 .borrow_mut()
2038 .set_health_check_config(&set.cluster_id, Some(set.config.to_owned()));
2039 push_queue(WorkerResponse::ok(req_id));
2040 return;
2041 }
2042 Some(RequestType::RemoveHealthCheck(ref cluster_id)) => {
2043 self.remove_health_check_state(cluster_id);
2044 push_queue(WorkerResponse::ok(req_id));
2045 return;
2046 }
2047 Some(RequestType::AddBackend(ref backend)) => {
2048 push_queue(self.add_backend(&req_id, backend));
2049 return;
2050 }
2051 Some(RequestType::RemoveBackend(ref remove_backend)) => {
2052 push_queue(self.remove_backend(&req_id, remove_backend));
2053 return;
2054 }
2055 _ => {}
2056 };
2057
2058 let proxy_destinations = request.content.get_destinations();
2059 let mut notify_response = None;
2060 if proxy_destinations.to_http_proxy {
2061 notify_response = Some(self.http.borrow_mut().notify(request.clone()));
2062 }
2063 if proxy_destinations.to_https_proxy {
2064 let http_proxy_response = self.https.borrow_mut().notify(request.clone());
2065 if http_proxy_response.is_failure() || notify_response.is_none() {
2066 notify_response = Some(http_proxy_response);
2067 }
2068 }
2069 if proxy_destinations.to_tcp_proxy {
2070 let tcp_proxy_response = self.tcp.borrow_mut().notify(request.clone());
2071 if tcp_proxy_response.is_failure() || notify_response.is_none() {
2072 notify_response = Some(tcp_proxy_response);
2073 }
2074 }
2075 if proxy_destinations.to_udp_proxy {
2076 let udp_proxy_response = self.udp.borrow_mut().notify(request.clone());
2077 if udp_proxy_response.is_failure() || notify_response.is_none() {
2078 notify_response = Some(udp_proxy_response);
2079 }
2080 }
2081 if let Some(response) = notify_response {
2082 push_queue(response);
2083 }
2084
2085 match request.content.request_type {
2086 Some(RequestType::AddHttpListener(listener)) => {
2088 push_queue(self.notify_add_http_listener(&req_id, listener));
2089 }
2090 Some(RequestType::AddHttpsListener(listener)) => {
2091 push_queue(self.notify_add_https_listener(&req_id, listener));
2092 }
2093 Some(RequestType::AddTcpListener(listener)) => {
2094 push_queue(self.notify_add_tcp_listener(&req_id, listener));
2095 }
2096 Some(RequestType::AddUdpListener(listener)) => {
2097 push_queue(self.notify_add_udp_listener(&req_id, listener));
2098 }
2099 Some(RequestType::UpdateHttpListener(patch)) => {
2100 push_queue(self.notify_update_http_listener(&req_id, patch));
2101 }
2102 Some(RequestType::UpdateHttpsListener(patch)) => {
2103 push_queue(self.notify_update_https_listener(&req_id, patch));
2104 }
2105 Some(RequestType::UpdateTcpListener(patch)) => {
2106 push_queue(self.notify_update_tcp_listener(&req_id, patch));
2107 }
2108 Some(RequestType::UpdateUdpListener(patch)) => {
2109 push_queue(self.notify_update_udp_listener(&req_id, patch));
2110 }
2111 Some(RequestType::RemoveListener(ref remove)) => {
2112 debug!("{} remove {:?} listener {:?}", req_id, remove.proxy, remove);
2113 debug_assert!(
2116 self.base_sessions_count > 0,
2117 "removing a listener with base_sessions_count == 0 would underflow"
2118 );
2119 self.base_sessions_count -= 1;
2120 let response = match ListenerType::try_from(remove.proxy) {
2121 Ok(ListenerType::Http) => self.http.borrow_mut().notify(request),
2122 Ok(ListenerType::Https) => self.https.borrow_mut().notify(request),
2123 Ok(ListenerType::Tcp) => self.tcp.borrow_mut().notify(request),
2124 Ok(ListenerType::Udp) => self.udp.borrow_mut().notify(request),
2125 Err(_) => WorkerResponse::error(req_id, "Wrong variant ListenerType"),
2126 };
2127 push_queue(response);
2128 }
2129 Some(RequestType::ActivateListener(ref activate)) => {
2130 push_queue(self.notify_activate_listener(&req_id, activate));
2131 }
2132 Some(RequestType::DeactivateListener(ref deactivate)) => {
2133 push_queue(self.notify_deactivate_listener(&req_id, deactivate));
2134 }
2135 _other_request => {}
2136 };
2137 }
2138
2139 fn add_cluster(&mut self, cluster: &Cluster) {
2140 let mut backends = self.backends.borrow_mut();
2141 backends.set_load_balancing_policy_for_cluster(
2142 &cluster.cluster_id,
2143 LoadBalancingAlgorithms::try_from(cluster.load_balancing).unwrap_or_default(),
2144 cluster
2145 .load_metric
2146 .and_then(|n| LoadMetric::try_from(n).ok()),
2147 );
2148 backends.set_health_check_config(&cluster.cluster_id, cluster.health_check.to_owned());
2149 backends.set_cluster_http2(&cluster.cluster_id, cluster.http2.unwrap_or(false));
2150 }
2151
2152 fn add_backend(&mut self, req_id: &str, add_backend: &AddBackend) -> WorkerResponse {
2153 let new_backend = Backend::new(
2154 &add_backend.backend_id,
2155 add_backend.address.into(),
2156 add_backend.sticky_id.clone(),
2157 add_backend.load_balancing_parameters,
2158 add_backend.backup,
2159 );
2160 self.backends
2161 .borrow_mut()
2162 .add_backend(&add_backend.cluster_id, new_backend);
2163
2164 WorkerResponse::ok(req_id)
2165 }
2166
2167 fn remove_health_check_state(&mut self, cluster_id: &str) {
2168 self.health_checker.remove_cluster(cluster_id);
2169 self.backends
2170 .borrow_mut()
2171 .health_check_configs
2172 .remove(cluster_id);
2173 }
2174
2175 fn remove_backend(&mut self, req_id: &str, backend: &RemoveBackend) -> WorkerResponse {
2176 let address = backend.address.into();
2177 let removed_ids = self
2185 .backends
2186 .borrow_mut()
2187 .remove_backend(&backend.cluster_id, &address);
2188 if removed_ids.is_empty() {
2189 METRICS.with(|metrics| {
2194 (*metrics.borrow_mut()).remove_backend(&backend.cluster_id, &backend.backend_id);
2195 });
2196 } else {
2197 METRICS.with(|metrics| {
2198 let mut metrics = metrics.borrow_mut();
2199 for id in &removed_ids {
2200 metrics.remove_backend(&backend.cluster_id, id);
2201 }
2202 });
2203 }
2204
2205 WorkerResponse::ok(req_id)
2206 }
2207
2208 fn notify_add_http_listener(
2209 &mut self,
2210 req_id: &str,
2211 listener: HttpListenerConfig,
2212 ) -> WorkerResponse {
2213 debug!("{} add http listener {:?}", req_id, listener);
2214
2215 if self.sessions.borrow().at_capacity() {
2216 return worker_response_error(req_id, "session list is full, cannot add a listener");
2217 }
2218
2219 let mut session_manager = self.sessions.borrow_mut();
2220 let slab_before = session_manager.slab.len();
2222 debug_assert!(
2223 !session_manager
2224 .slab
2225 .contains(session_manager.slab.vacant_key()),
2226 "the next vacant slab key must be free before insertion"
2227 );
2228 let entry = session_manager.slab.vacant_entry();
2229 let token = Token(entry.key());
2230
2231 match self.http.borrow_mut().add_listener(listener, token) {
2232 Ok(_token) => {
2233 entry.insert(Rc::new(RefCell::new(ListenSession {
2234 protocol: Protocol::HTTPListen,
2235 })));
2236 debug_assert!(
2239 session_manager.slab.contains(token.0),
2240 "listener insert must occupy the token's slab key"
2241 );
2242 debug_assert_eq!(
2243 session_manager.slab.len(),
2244 slab_before + 1,
2245 "adding a listener must occupy exactly one slab slot"
2246 );
2247 self.base_sessions_count += 1;
2248 WorkerResponse::ok(req_id)
2249 }
2250 Err(e) => worker_response_error(req_id, format!("Could not add HTTP listener: {e}")),
2251 }
2252 }
2253
2254 fn notify_add_https_listener(
2255 &mut self,
2256 req_id: &str,
2257 listener: HttpsListenerConfig,
2258 ) -> WorkerResponse {
2259 debug!("{} add https listener {:?}", req_id, listener);
2260
2261 if self.sessions.borrow().at_capacity() {
2262 return worker_response_error(req_id, "session list is full, cannot add a listener");
2263 }
2264
2265 let mut session_manager = self.sessions.borrow_mut();
2266 let slab_before = session_manager.slab.len();
2267 debug_assert!(
2268 !session_manager
2269 .slab
2270 .contains(session_manager.slab.vacant_key()),
2271 "the next vacant slab key must be free before insertion"
2272 );
2273 let entry = session_manager.slab.vacant_entry();
2274 let token = Token(entry.key());
2275
2276 match self
2277 .https
2278 .borrow_mut()
2279 .add_listener(listener.clone(), token)
2280 {
2281 Ok(_token) => {
2282 entry.insert(Rc::new(RefCell::new(ListenSession {
2283 protocol: Protocol::HTTPSListen,
2284 })));
2285 debug_assert!(
2286 session_manager.slab.contains(token.0),
2287 "listener insert must occupy the token's slab key"
2288 );
2289 debug_assert_eq!(
2290 session_manager.slab.len(),
2291 slab_before + 1,
2292 "adding a listener must occupy exactly one slab slot"
2293 );
2294 self.base_sessions_count += 1;
2295 WorkerResponse::ok(req_id)
2296 }
2297 Err(e) => worker_response_error(req_id, format!("Could not add HTTPS listener: {e}")),
2298 }
2299 }
2300
2301 fn notify_add_tcp_listener(
2302 &mut self,
2303 req_id: &str,
2304 listener: CommandTcpListener,
2305 ) -> WorkerResponse {
2306 debug!("{} add tcp listener {:?}", req_id, listener);
2307
2308 if self.sessions.borrow().at_capacity() {
2309 return worker_response_error(req_id, "session list is full, cannot add a listener");
2310 }
2311
2312 let mut session_manager = self.sessions.borrow_mut();
2313 let slab_before = session_manager.slab.len();
2314 debug_assert!(
2315 !session_manager
2316 .slab
2317 .contains(session_manager.slab.vacant_key()),
2318 "the next vacant slab key must be free before insertion"
2319 );
2320 let entry = session_manager.slab.vacant_entry();
2321 let token = Token(entry.key());
2322
2323 match self.tcp.borrow_mut().add_listener(listener, token) {
2324 Ok(_token) => {
2325 entry.insert(Rc::new(RefCell::new(ListenSession {
2326 protocol: Protocol::TCPListen,
2327 })));
2328 debug_assert!(
2329 session_manager.slab.contains(token.0),
2330 "listener insert must occupy the token's slab key"
2331 );
2332 debug_assert_eq!(
2333 session_manager.slab.len(),
2334 slab_before + 1,
2335 "adding a listener must occupy exactly one slab slot"
2336 );
2337 self.base_sessions_count += 1;
2338 WorkerResponse::ok(req_id)
2339 }
2340 Err(e) => worker_response_error(req_id, format!("Could not add TCP listener: {e}")),
2341 }
2342 }
2343
2344 fn notify_add_udp_listener(
2345 &mut self,
2346 req_id: &str,
2347 listener: CommandUdpListener,
2348 ) -> WorkerResponse {
2349 debug!("{} add udp listener {:?}", req_id, listener);
2350
2351 if self.sessions.borrow().at_capacity() {
2352 return worker_response_error(req_id, "session list is full, cannot add a listener");
2353 }
2354
2355 let mut session_manager = self.sessions.borrow_mut();
2356 let entry = session_manager.slab.vacant_entry();
2357 let token = Token(entry.key());
2358
2359 match self.udp.borrow_mut().add_listener(listener, token) {
2360 Ok(_token) => {
2361 entry.insert(Rc::new(RefCell::new(ListenSession {
2362 protocol: Protocol::UDPListen,
2363 })));
2364 self.base_sessions_count += 1;
2365 WorkerResponse::ok(req_id)
2366 }
2367 Err(e) => worker_response_error(req_id, format!("Could not add UDP listener: {e}")),
2368 }
2369 }
2370
2371 fn notify_update_udp_listener(
2372 &mut self,
2373 req_id: &str,
2374 patch: UpdateUdpListenerConfig,
2375 ) -> WorkerResponse {
2376 debug!("{} update udp listener {:?}", req_id, patch.address);
2377 match self.udp.borrow_mut().update_listener(patch) {
2378 Ok(()) => WorkerResponse::ok(req_id),
2379 Err(e) => worker_response_error(req_id, format!("Could not update UDP listener: {e}")),
2380 }
2381 }
2382
2383 fn notify_update_http_listener(
2384 &mut self,
2385 req_id: &str,
2386 patch: UpdateHttpListenerConfig,
2387 ) -> WorkerResponse {
2388 debug!("{} update http listener {:?}", req_id, patch.address);
2389 match self.http.borrow_mut().update_listener(patch) {
2390 Ok(()) => WorkerResponse::ok(req_id),
2391 Err(e) => worker_response_error(req_id, format!("Could not update HTTP listener: {e}")),
2392 }
2393 }
2394
2395 fn notify_update_https_listener(
2396 &mut self,
2397 req_id: &str,
2398 patch: UpdateHttpsListenerConfig,
2399 ) -> WorkerResponse {
2400 debug!("{} update https listener {:?}", req_id, patch.address);
2401 match self.https.borrow_mut().update_listener(patch) {
2402 Ok(()) => WorkerResponse::ok(req_id),
2403 Err(e) => {
2404 worker_response_error(req_id, format!("Could not update HTTPS listener: {e}"))
2405 }
2406 }
2407 }
2408
2409 fn notify_update_tcp_listener(
2410 &mut self,
2411 req_id: &str,
2412 patch: UpdateTcpListenerConfig,
2413 ) -> WorkerResponse {
2414 debug!("{} update tcp listener {:?}", req_id, patch.address);
2415 match self.tcp.borrow_mut().update_listener(patch) {
2416 Ok(()) => WorkerResponse::ok(req_id),
2417 Err(e) => worker_response_error(req_id, format!("Could not update TCP listener: {e}")),
2418 }
2419 }
2420
2421 fn notify_activate_listener(
2422 &mut self,
2423 req_id: &str,
2424 activate: &ActivateListener,
2425 ) -> WorkerResponse {
2426 debug!(
2427 "{} activate {:?} listener {:?}",
2428 req_id, activate.proxy, activate
2429 );
2430
2431 let address: std::net::SocketAddr = activate.address.into();
2432
2433 match ListenerType::try_from(activate.proxy) {
2434 Ok(ListenerType::Http) => {
2435 let listener = self
2436 .scm_listeners
2437 .as_mut()
2438 .and_then(|s| s.get_http(&address))
2439 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) });
2444
2445 let activated_token = self.http.borrow_mut().activate_listener(&address, listener);
2446 match activated_token {
2447 Ok(token) => {
2448 self.accept(ListenToken(token.0), Protocol::HTTPListen);
2449 WorkerResponse::ok(req_id)
2450 }
2451 Err(activate_error) => worker_response_error(
2452 req_id,
2453 format!("Could not activate HTTP listener: {activate_error}"),
2454 ),
2455 }
2456 }
2457 Ok(ListenerType::Https) => {
2458 let listener = self
2459 .scm_listeners
2460 .as_mut()
2461 .and_then(|s| s.get_https(&address))
2462 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) });
2467
2468 let activated_token = self
2469 .https
2470 .borrow_mut()
2471 .activate_listener(&address, listener);
2472 match activated_token {
2473 Ok(token) => {
2474 self.accept(ListenToken(token.0), Protocol::HTTPSListen);
2475 WorkerResponse::ok(req_id)
2476 }
2477 Err(activate_error) => worker_response_error(
2478 req_id,
2479 format!("Could not activate HTTPS listener: {activate_error}"),
2480 ),
2481 }
2482 }
2483 Ok(ListenerType::Tcp) => {
2484 let listener = self
2485 .scm_listeners
2486 .as_mut()
2487 .and_then(|s| s.get_tcp(&address))
2488 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) });
2493
2494 let listener_token = self.tcp.borrow_mut().activate_listener(&address, listener);
2495 match listener_token {
2496 Ok(token) => {
2497 self.accept(ListenToken(token.0), Protocol::TCPListen);
2498 WorkerResponse::ok(req_id)
2499 }
2500 Err(activate_error) => worker_response_error(
2501 req_id,
2502 format!("Could not activate TCP listener: {activate_error}"),
2503 ),
2504 }
2505 }
2506 Ok(ListenerType::Udp) => {
2507 let socket = self
2508 .scm_listeners
2509 .as_mut()
2510 .and_then(|s| s.get_udp(&address))
2511 .map(|fd| unsafe { MioUdpSocket::from_raw_fd(fd) });
2519
2520 let activated_token = self.udp.borrow_mut().activate_listener(&address, socket);
2521 match activated_token {
2522 Ok(token) => {
2523 if let Some(session) = self.udp.borrow_mut().build_session(token) {
2529 let mut sessions = self.sessions.borrow_mut();
2530 if sessions.slab.contains(token.0) {
2531 sessions.slab[token.0] = session;
2532 }
2533 }
2534 WorkerResponse::ok(req_id)
2535 }
2536 Err(activate_error) => worker_response_error(
2537 req_id,
2538 format!("Could not activate UDP listener: {activate_error}"),
2539 ),
2540 }
2541 }
2542 Err(_) => worker_response_error(req_id, "Wrong variant for ListenerType on request"),
2543 }
2544 }
2545
2546 fn notify_deactivate_listener(
2547 &mut self,
2548 req_id: &str,
2549 deactivate: &DeactivateListener,
2550 ) -> WorkerResponse {
2551 debug!(
2552 "{} deactivate {:?} listener {:?}",
2553 req_id, deactivate.proxy, deactivate
2554 );
2555
2556 let address: std::net::SocketAddr = deactivate.address.into();
2557
2558 match ListenerType::try_from(deactivate.proxy) {
2559 Ok(ListenerType::Http) => {
2560 let (token, mut listener) = match self.http.borrow_mut().give_back_listener(address)
2561 {
2562 Ok((token, listener)) => (token, listener),
2563 Err(e) => {
2564 return worker_response_error(
2565 req_id,
2566 format!(
2567 "Couldn't deactivate HTTP listener at address {address:?}: {e}"
2568 ),
2569 );
2570 }
2571 };
2572
2573 if let Err(e) = self.poll.registry().deregister(&mut listener) {
2574 error!(
2575 "error deregistering HTTP listen socket({:?}): {:?}",
2576 deactivate, e
2577 );
2578 }
2579
2580 {
2581 let mut sessions = self.sessions.borrow_mut();
2582 if sessions.slab.contains(token.0) {
2583 sessions.slab.remove(token.0);
2584 info!("removed listen token {:?}", token);
2585 }
2586 }
2587
2588 if deactivate.to_scm {
2589 self.unblock_scm_socket();
2590 let listeners = Listeners {
2591 http: vec![(address, listener.as_raw_fd())],
2592 tls: vec![],
2593 tcp: vec![],
2594 udp: vec![],
2595 };
2596 info!("sending HTTP listener: {:?}", listeners);
2597 let res = self.scm.send_listeners(&listeners);
2598
2599 self.block_scm_socket();
2600
2601 info!("sent HTTP listener: {:?}", res);
2602 }
2603 WorkerResponse::ok(req_id)
2604 }
2605 Ok(ListenerType::Https) => {
2606 let (token, mut listener) = match self
2607 .https
2608 .borrow_mut()
2609 .give_back_listener(address)
2610 {
2611 Ok((token, listener)) => (token, listener),
2612 Err(e) => {
2613 return worker_response_error(
2614 req_id,
2615 format!(
2616 "Couldn't deactivate HTTPS listener at address {address:?}: {e}",
2617 ),
2618 );
2619 }
2620 };
2621 if let Err(e) = self.poll.registry().deregister(&mut listener) {
2622 error!(
2623 "error deregistering HTTPS listen socket({:?}): {:?}",
2624 deactivate, e
2625 );
2626 }
2627 if self.sessions.borrow().slab.contains(token.0) {
2628 self.sessions.borrow_mut().slab.remove(token.0);
2629 info!("removed listen token {:?}", token);
2630 }
2631
2632 if deactivate.to_scm {
2633 self.unblock_scm_socket();
2634 let listeners = Listeners {
2635 http: vec![],
2636 tls: vec![(address, listener.as_raw_fd())],
2637 tcp: vec![],
2638 udp: vec![],
2639 };
2640 info!("sending HTTPS listener: {:?}", listeners);
2641 let res = self.scm.send_listeners(&listeners);
2642
2643 self.block_scm_socket();
2644
2645 info!("sent HTTPS listener: {:?}", res);
2646 }
2647 WorkerResponse::ok(req_id)
2648 }
2649 Ok(ListenerType::Tcp) => {
2650 let (token, mut listener) = match self.tcp.borrow_mut().give_back_listener(address)
2651 {
2652 Ok((token, listener)) => (token, listener),
2653 Err(e) => {
2654 return worker_response_error(
2655 req_id,
2656 format!(
2657 "Could not deactivate TCP listener at address {address:?}: {e}"
2658 ),
2659 );
2660 }
2661 };
2662
2663 if let Err(e) = self.poll.registry().deregister(&mut listener) {
2664 error!(
2665 "error deregistering TCP listen socket({:?}): {:?}",
2666 deactivate, e
2667 );
2668 }
2669 if self.sessions.borrow().slab.contains(token.0) {
2670 self.sessions.borrow_mut().slab.remove(token.0);
2671 info!("removed listen token {:?}", token);
2672 }
2673
2674 if deactivate.to_scm {
2675 self.unblock_scm_socket();
2676 let listeners = Listeners {
2677 http: vec![],
2678 tls: vec![],
2679 tcp: vec![(address, listener.as_raw_fd())],
2680 udp: vec![],
2681 };
2682 info!("sending TCP listener: {:?}", listeners);
2683 let res = self.scm.send_listeners(&listeners);
2684
2685 self.block_scm_socket();
2686
2687 info!("sent TCP listener: {:?}", res);
2688 }
2689 WorkerResponse::ok(req_id)
2690 }
2691 Ok(ListenerType::Udp) => {
2692 let (token, mut listener) = match self.udp.borrow_mut().give_back_listener(address)
2693 {
2694 Ok((token, listener)) => (token, listener),
2695 Err(e) => {
2696 return worker_response_error(
2697 req_id,
2698 format!(
2699 "Could not deactivate UDP listener at address {address:?}: {e}"
2700 ),
2701 );
2702 }
2703 };
2704
2705 if let Err(e) = self.poll.registry().deregister(&mut listener) {
2706 error!(
2707 "error deregistering UDP listen socket({:?}): {:?}",
2708 deactivate, e
2709 );
2710 }
2711 if self.sessions.borrow().slab.contains(token.0) {
2712 self.sessions.borrow_mut().slab.remove(token.0);
2713 info!("removed listen token {:?}", token);
2714 }
2715
2716 if deactivate.to_scm {
2717 self.unblock_scm_socket();
2718 let listeners = Listeners {
2719 http: vec![],
2720 tls: vec![],
2721 tcp: vec![],
2722 udp: vec![(address, listener.as_raw_fd())],
2723 };
2724 info!("sending UDP listener: {:?}", listeners);
2725 let res = self.scm.send_listeners(&listeners);
2726
2727 self.block_scm_socket();
2728
2729 info!("sent UDP listener: {:?}", res);
2730 }
2731 WorkerResponse::ok(req_id)
2732 }
2733 Err(_) => worker_response_error(req_id, "Wrong variant for ListenerType on request"),
2734 }
2735 }
2736
2737 pub fn return_listen_sockets(&mut self) -> Result<(), ScmSocketError> {
2739 self.unblock_scm_socket();
2740
2741 let mut http_listeners = self.http.borrow_mut().give_back_listeners();
2742 for &mut (_, ref mut sock) in http_listeners.iter_mut() {
2743 if let Err(e) = self.poll.registry().deregister(sock) {
2744 error!(
2745 "error deregistering HTTP listen socket({:?}): {:?}",
2746 sock, e
2747 );
2748 }
2749 }
2750
2751 let mut https_listeners = self.https.borrow_mut().give_back_listeners();
2752 for &mut (_, ref mut sock) in https_listeners.iter_mut() {
2753 if let Err(e) = self.poll.registry().deregister(sock) {
2754 error!(
2755 "error deregistering HTTPS listen socket({:?}): {:?}",
2756 sock, e
2757 );
2758 }
2759 }
2760
2761 let mut tcp_listeners = self.tcp.borrow_mut().give_back_listeners();
2762 for &mut (_, ref mut sock) in tcp_listeners.iter_mut() {
2763 if let Err(e) = self.poll.registry().deregister(sock) {
2764 error!("error deregistering TCP listen socket({:?}): {:?}", sock, e);
2765 }
2766 }
2767
2768 let mut udp_listeners = self.udp.borrow_mut().give_back_listeners();
2769 for &mut (_, ref mut sock) in udp_listeners.iter_mut() {
2770 if let Err(e) = self.poll.registry().deregister(sock) {
2771 error!("error deregistering UDP listen socket({:?}): {:?}", sock, e);
2772 }
2773 }
2774
2775 let listeners = Listeners {
2777 http: http_listeners
2778 .iter()
2779 .map(|(addr, listener)| (*addr, listener.as_raw_fd()))
2780 .collect(),
2781 tls: https_listeners
2782 .iter()
2783 .map(|(addr, listener)| (*addr, listener.as_raw_fd()))
2784 .collect(),
2785 tcp: tcp_listeners
2786 .iter()
2787 .map(|(addr, listener)| (*addr, listener.as_raw_fd()))
2788 .collect(),
2789 udp: udp_listeners
2790 .iter()
2791 .map(|(addr, listener)| (*addr, listener.as_raw_fd()))
2792 .collect(),
2793 };
2794 debug_assert_eq!(
2798 listeners.http.len(),
2799 http_listeners.len(),
2800 "every HTTP listener must be collected exactly once"
2801 );
2802 debug_assert_eq!(
2803 listeners.tls.len(),
2804 https_listeners.len(),
2805 "every HTTPS listener must be collected exactly once"
2806 );
2807 debug_assert_eq!(
2808 listeners.tcp.len(),
2809 tcp_listeners.len(),
2810 "every TCP listener must be collected exactly once"
2811 );
2812 info!("sending default listeners: {:?}", listeners);
2813 let res = self.scm.send_listeners(&listeners);
2814
2815 self.block_scm_socket();
2816
2817 info!("sent default listeners: {:?}", res);
2818 res
2819 }
2820
2821 fn block_scm_socket(&mut self) {
2822 if let Err(e) = self.scm.set_blocking(true) {
2823 error!("Could not block scm socket: {}", e);
2824 }
2825 }
2826
2827 fn unblock_scm_socket(&mut self) {
2828 if let Err(e) = self.scm.set_blocking(false) {
2829 error!("Could not unblock scm socket: {}", e);
2830 }
2831 }
2832
2833 pub fn to_session(&self, token: Token) -> SessionToken {
2834 SessionToken(token.0)
2835 }
2836
2837 pub fn from_session(&self, token: SessionToken) -> Token {
2838 Token(token.0)
2839 }
2840
2841 pub fn accept(&mut self, token: ListenToken, protocol: Protocol) {
2842 let (proto_key, accepted_protocol) = match protocol {
2855 Protocol::TCPListen => ("listener.accepted.tcp", Protocol::TCPListen),
2856 Protocol::HTTPListen => ("listener.accepted.http", Protocol::HTTPListen),
2857 Protocol::HTTPSListen => ("listener.accepted.https", Protocol::HTTPSListen),
2858 other => {
2859 warn!(
2860 "accept() called with non-listen protocol {:?} on token {:?}; skipping",
2861 other, token
2862 );
2863 return;
2864 }
2865 };
2866
2867 debug_assert!(
2870 matches!(
2871 accepted_protocol,
2872 Protocol::TCPListen | Protocol::HTTPListen | Protocol::HTTPSListen
2873 ),
2874 "accept dispatch must run with a listen protocol only"
2875 );
2876
2877 loop {
2878 let result = match accepted_protocol {
2879 Protocol::TCPListen => self.tcp.borrow_mut().accept(token),
2880 Protocol::HTTPListen => self.http.borrow_mut().accept(token),
2881 Protocol::HTTPSListen => self.https.borrow_mut().accept(token),
2882 other => unreachable!(
2886 "accept dispatch reached non-listen protocol {:?} after outer guard",
2887 other
2888 ),
2889 };
2890 match result {
2891 Ok(sock) => {
2892 let peer = sock.peer_addr().ok();
2897 incr!(names::listener::ACCEPTED_TOTAL);
2898 incr!(proto_key);
2899 if let Some(peer_addr) = peer.as_ref() {
2900 incr!(per_source_bucket(peer_addr));
2901 }
2902 let queue_before = self.accept_queue.len();
2903 self.accept_queue.push_back((
2904 sock,
2905 token,
2906 accepted_protocol,
2907 Instant::now(),
2908 peer,
2909 ));
2910 debug_assert_eq!(
2912 self.accept_queue.len(),
2913 queue_before + 1,
2914 "each accepted socket must enqueue exactly one entry"
2915 );
2916 }
2917 Err(AcceptError::WouldBlock) => {
2918 self.accept_ready.remove(&token);
2919 break;
2920 }
2921 Err(other) => {
2922 error!(
2923 "error accepting {:?} sockets: {:?}",
2924 accepted_protocol, other
2925 );
2926 self.accept_ready.remove(&token);
2927 break;
2928 }
2929 }
2930 }
2931
2932 gauge!(names::accept_queue::CONNECTIONS, self.accept_queue.len());
2933 }
2934
2935 pub fn create_sessions(&mut self) {
2936 while let Some((sock, token, protocol, timestamp, _peer)) = self.accept_queue.pop_back() {
2937 let wait_time = Instant::now() - timestamp;
2938 time!(names::accept_queue::WAIT_TIME, wait_time.as_millis());
2939 if wait_time > self.accept_queue_timeout {
2940 incr!(names::accept_queue::TIMEOUT);
2941 continue;
2942 }
2943
2944 if !self.sessions.borrow_mut().check_limits() {
2945 incr!(names::listener::CONNECTION_CAPPED);
2951
2952 if !self.evict_on_queue_full {
2953 break;
2954 }
2955
2956 if self.shutting_down.is_some() {
2960 break;
2961 }
2962
2963 let to_evict = (self.sessions.borrow().max_connections / 100).max(1);
2972 let evicted = self.evict_least_active_sessions(to_evict);
2973 if evicted == 0 {
2974 warn!("evict_on_queue_full enabled but no candidate sessions to evict");
2980 break;
2981 }
2982
2983 count!(names::sessions::EVICTED, evicted as i64);
2984 warn!(
2985 "evicted {} least recently active sessions to make room",
2986 evicted
2987 );
2988
2989 if !self.sessions.borrow_mut().check_limits() {
2990 break;
2991 }
2992 }
2993
2994 debug_assert!(
3001 matches!(
3002 protocol,
3003 Protocol::TCPListen | Protocol::HTTPListen | Protocol::HTTPSListen
3004 ),
3005 "accept queue must only hold listen protocols, got {protocol:?}"
3006 );
3007 match protocol {
3008 Protocol::TCPListen => {
3009 let proxy = self.tcp.clone();
3010 if self
3011 .tcp
3012 .borrow_mut()
3013 .create_session(sock, token, wait_time, proxy)
3014 .is_err()
3015 {
3016 break;
3017 }
3018 }
3019 Protocol::HTTPListen => {
3020 let proxy = self.http.clone();
3021 if self
3022 .http
3023 .borrow_mut()
3024 .create_session(sock, token, wait_time, proxy)
3025 .is_err()
3026 {
3027 break;
3028 }
3029 }
3030 Protocol::HTTPSListen => {
3031 if self
3032 .https
3033 .borrow_mut()
3034 .create_session(sock, token, wait_time, self.https.clone())
3035 .is_err()
3036 {
3037 break;
3038 }
3039 }
3040 _ => panic!("should not call accept() on a HTTP, HTTPS or TCP session"),
3041 };
3042 let nb_before = self.sessions.borrow().nb_connections;
3043 self.sessions.borrow_mut().incr();
3044 debug_assert_eq!(
3046 self.sessions.borrow().nb_connections,
3047 nb_before + 1,
3048 "create_sessions must account exactly one new connection per created session"
3049 );
3050 }
3051
3052 gauge!(names::accept_queue::CONNECTIONS, self.accept_queue.len());
3053 }
3054
3055 pub fn ready(&mut self, token: Token, events: Ready) {
3056 trace!("PROXY\t{:?} got events: {:?}", token, events);
3057
3058 let session_token = token.0;
3059 if self.sessions.borrow().slab.contains(session_token) {
3060 let protocol = self.sessions.borrow().slab[session_token]
3062 .borrow()
3063 .protocol();
3064 match protocol {
3073 Protocol::HTTPListen | Protocol::HTTPSListen | Protocol::TCPListen => {
3074 if events.is_readable() {
3076 self.accept_ready.insert(ListenToken(token.0));
3077 if self.sessions.borrow().can_accept {
3078 self.accept(ListenToken(token.0), protocol);
3079 }
3080 return;
3081 }
3082
3083 if events.is_writable() {
3084 error!(
3085 "received writable for listener {:?}, this should not happen",
3086 token
3087 );
3088 return;
3089 }
3090
3091 if events.is_hup() {
3092 error!("should not happen: server {:?} closed", token);
3093 return;
3094 }
3095
3096 unreachable!();
3097 }
3098 _ => {}
3099 }
3100
3101 let session = self.sessions.borrow_mut().slab[session_token].clone();
3102 session.borrow_mut().update_readiness(token, events);
3103 if session.borrow_mut().ready(session.clone()) {
3104 debug!(
3105 "Server killing session from ready: token={:?}, protocol={:?}, events={:?}",
3106 token, protocol, events
3107 );
3108 self.kill_session(session);
3109 }
3110 }
3111 }
3112
3113 pub fn timeout(&mut self, token: Token) {
3114 trace!("PROXY\t{:?} got timeout", token);
3115
3116 let session_token = token.0;
3117 if self.sessions.borrow().slab.contains(session_token) {
3118 let session = self.sessions.borrow_mut().slab[session_token].clone();
3119 if session.borrow_mut().timeout(token) {
3120 debug!(
3121 "Server killing session from timeout: token={:?}, protocol={:?}",
3122 token,
3123 session.borrow().protocol()
3124 );
3125 self.kill_session(session);
3126 }
3127 }
3128 }
3129
3130 pub fn handle_remaining_readiness(&mut self) {
3131 if self.sessions.borrow().can_accept && !self.accept_ready.is_empty() {
3134 while let Some(token) = self
3135 .accept_ready
3136 .iter()
3137 .next()
3138 .map(|token| ListenToken(token.0))
3139 {
3140 let protocol = self.sessions.borrow().slab[token.0].borrow().protocol();
3141 self.accept(token, protocol);
3142 if !self.sessions.borrow().can_accept || self.accept_ready.is_empty() {
3143 break;
3144 }
3145 }
3146 }
3147 }
3148 fn block_channel(&mut self) {
3149 if let Err(e) = self.channel.blocking() {
3150 error!("Could not block channel: {}", e);
3151 }
3152 }
3153 fn unblock_channel(&mut self) {
3154 if let Err(e) = self.channel.nonblocking() {
3155 error!("Could not block channel: {}", e);
3156 }
3157 }
3158
3159 fn evict_least_active_sessions(&self, count: usize) -> usize {
3171 if count == 0 {
3172 return 0;
3173 }
3174
3175 let tokens = {
3176 let sessions = self.sessions.borrow();
3177 let mut candidates: Vec<(Token, Instant)> = sessions
3178 .slab
3179 .iter()
3180 .filter(|(_, session)| {
3181 !matches!(
3182 session.borrow().protocol(),
3183 Protocol::HTTPListen
3184 | Protocol::HTTPSListen
3185 | Protocol::TCPListen
3186 | Protocol::UDPListen
3187 | Protocol::Channel
3188 | Protocol::Metrics
3189 | Protocol::Timer
3190 )
3191 })
3192 .map(|(_, session)| {
3193 let s = session.borrow();
3194 (s.frontend_token(), s.last_event())
3195 })
3196 .collect();
3197
3198 if candidates.is_empty() {
3201 return 0;
3202 }
3203
3204 let pivot = count.min(candidates.len()) - 1;
3205 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
3206
3207 candidates[..=pivot]
3208 .iter()
3209 .map(|&(token, _)| token)
3210 .collect::<HashSet<Token>>()
3211 };
3212
3213 let evicted = tokens.len();
3214 self.shut_down_sessions_by_frontend_tokens(tokens);
3215 evicted
3216 }
3217}
3218
3219fn worker_response_error<S: ToString, T: ToString>(request_id: S, error: T) -> WorkerResponse {
3222 error!(
3223 "error on request {}, {}",
3224 request_id.to_string(),
3225 error.to_string()
3226 );
3227 WorkerResponse::error(request_id, error)
3228}
3229
3230pub struct ListenSession {
3231 pub protocol: Protocol,
3232}
3233
3234impl ProxySession for ListenSession {
3235 fn last_event(&self) -> Instant {
3236 Instant::now()
3237 }
3238
3239 fn print_session(&self) {}
3240
3241 fn frontend_token(&self) -> Token {
3242 Token(0)
3243 }
3244
3245 fn protocol(&self) -> Protocol {
3246 self.protocol
3247 }
3248
3249 fn ready(&mut self, _session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
3250 false
3251 }
3252
3253 fn shutting_down(&mut self) -> SessionIsToBeClosed {
3254 false
3255 }
3256
3257 fn update_readiness(&mut self, _token: Token, _events: Ready) {}
3258
3259 fn close(&mut self) {}
3260
3261 fn timeout(&mut self, _token: Token) -> SessionIsToBeClosed {
3262 error!(
3263 "called ProxySession::timeout(token={:?}, time) on ListenSession {{ protocol: {:?} }}",
3264 _token, self.protocol
3265 );
3266 false
3267 }
3268}
3269
3270#[cfg(test)]
3271mod accept_telemetry_tests {
3272 use super::*;
3273
3274 #[test]
3277 fn per_source_bucket_collapses_ipv4_slash24() {
3278 let a: SocketAddr = "203.0.113.5:1234".parse().unwrap();
3279 let b: SocketAddr = "203.0.113.250:9999".parse().unwrap();
3280 assert_eq!(
3281 per_source_bucket(&a),
3282 per_source_bucket(&b),
3283 "addresses in the same /24 must land in the same bucket"
3284 );
3285 }
3286
3287 #[test]
3289 fn per_source_bucket_collapses_ipv6_slash48() {
3290 let a: SocketAddr = "[2001:db8:1234::1]:443".parse().unwrap();
3291 let b: SocketAddr = "[2001:db8:1234:abcd::ffff]:8443".parse().unwrap();
3292 assert_eq!(
3293 per_source_bucket(&a),
3294 per_source_bucket(&b),
3295 "addresses in the same /48 must land in the same bucket"
3296 );
3297 }
3298
3299 #[test]
3302 fn per_source_bucket_keys_are_bounded() {
3303 assert_eq!(PER_SOURCE_BUCKET_KEYS.len(), PER_SOURCE_BUCKETS);
3304 for (i, key) in PER_SOURCE_BUCKET_KEYS.iter().enumerate() {
3305 let expected = format!("client.connect.per_source.bucket_{i:03}");
3306 assert_eq!(*key, expected.as_str());
3307 }
3308 }
3309
3310 #[test]
3313 fn per_source_bucket_distributes_distinct_subnets() {
3314 let mut hits = std::collections::HashSet::new();
3315 for i in 0..200u8 {
3316 let addr: SocketAddr = format!("10.0.{i}.42:80").parse().unwrap();
3317 hits.insert(per_source_bucket(&addr));
3318 }
3319 assert!(
3323 hits.len() >= 100,
3324 "expected at least 100 distinct buckets across 200 /24s, got {}",
3325 hits.len()
3326 );
3327 }
3328}
3329
3330#[cfg(test)]
3331mod state_error_log_tests {
3332 use sozu_command::state::StateError;
3333
3334 #[test]
3335 fn worker_state_dispatch_error_sink_bounds_the_reason() {
3336 const REASON_SECRET: &str = "WORKER_STATE_ERROR_REASON_SECRET_SENTINEL";
3337
3338 let reason = format!("{REASON_SECRET}{}", "x".repeat(4096));
3339 let reason_len = reason.len();
3340 let output = crate::capture_test_logs(move || {
3341 let error = StateError::InvalidTcpFrontend {
3342 address: "127.0.0.1:443"
3343 .parse()
3344 .expect("test TCP frontend address must parse"),
3345 reason,
3346 };
3347 error!("Could not execute order on config state: {}", error);
3348 });
3349
3350 assert!(
3351 !output.contains(REASON_SECRET),
3352 "worker state-error sink leaked the reason: {output}"
3353 );
3354 assert!(
3355 output.contains(&format!("reason_bytes={reason_len}")),
3356 "worker state-error sink omitted bounded reason metadata: {output}"
3357 );
3358 assert!(
3359 output.len() <= 512,
3360 "worker state-error sink is not bounded: {} bytes",
3361 output.len()
3362 );
3363 }
3364}
3365
3366#[cfg(test)]
3367mod eviction_tests {
3368 use std::collections::HashSet;
3369 use std::time::{Duration, Instant};
3370
3371 use mio::Token;
3372
3373 #[test]
3377 fn select_nth_finds_oldest_sessions() {
3378 let now = Instant::now();
3379 let mut candidates = [
3380 (Token(1), now - Duration::from_secs(10)), (Token(2), now - Duration::from_secs(50)), (Token(3), now - Duration::from_secs(5)), (Token(4), now - Duration::from_secs(30)), (Token(5), now - Duration::from_secs(20)), ];
3386
3387 let count = 2;
3388 let pivot = count.min(candidates.len()) - 1;
3389 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
3390
3391 let selected: HashSet<Token> = candidates[..=pivot]
3392 .iter()
3393 .map(|&(token, _)| token)
3394 .collect();
3395
3396 assert_eq!(selected.len(), 2);
3397 assert!(
3398 selected.contains(&Token(2)),
3399 "should contain 50s-old session"
3400 );
3401 assert!(
3402 selected.contains(&Token(4)),
3403 "should contain 30s-old session"
3404 );
3405 }
3406
3407 #[test]
3411 fn select_nth_with_count_exceeding_candidates() {
3412 let now = Instant::now();
3413 let mut candidates = [(Token(1), now - Duration::from_secs(10))];
3414
3415 let count = 5;
3416 let pivot = count.min(candidates.len()) - 1;
3417 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
3418
3419 let selected: HashSet<Token> = candidates[..=pivot]
3420 .iter()
3421 .map(|&(token, _)| token)
3422 .collect();
3423
3424 assert_eq!(selected.len(), 1);
3425 assert!(selected.contains(&Token(1)));
3426 }
3427}