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, RawFd},
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 listener_key::ListenerKey,
24 logging,
25 proto::command::{
26 ActivateListener, AddBackend, CertificatesWithFingerprints, Cluster, ClusterHashes,
27 ClusterInformations, DeactivateListener, Event, EventKind, HttpListenerConfig,
28 HttpsListenerConfig, InitialState, ListenerType, LoadBalancingAlgorithms, LoadMetric,
29 MetricDetail, MetricsConfiguration, RemoveBackend, Request, ResponseContent,
30 ResponseStatus, ServerConfig, TcpListenerConfig as CommandTcpListener,
31 UdpListenerConfig as CommandUdpListener, UpdateHttpListenerConfig,
32 UpdateHttpsListenerConfig, UpdateTcpListenerConfig, UpdateUdpListenerConfig, WorkerRequest,
33 WorkerResponse, request::RequestType, response_content::ContentType,
34 },
35 ready::Ready,
36 scm_socket::{Listeners, ScmSocket, ScmSocketError},
37 state::{ClusterId, ConfigState, StateError},
38};
39
40use crate::metrics::names;
41use crate::{
42 AcceptError, Protocol, ProxyConfiguration, ProxySession, SessionIsToBeClosed,
43 backends::{Backend, BackendMap},
44 features::FEATURES,
45 health_check::HealthChecker,
46 http, https,
47 load_balancing::ShuffleSharding,
48 metrics::METRICS,
49 pool::Pool,
50 tcp,
51 timer::Timer,
52 udp,
53};
54
55pub const PER_SOURCE_BUCKETS: usize = 256;
69
70static PER_SOURCE_BUCKET_KEYS: LazyLock<[&'static str; PER_SOURCE_BUCKETS]> = LazyLock::new(|| {
75 let mut keys: [&'static str; PER_SOURCE_BUCKETS] = [""; PER_SOURCE_BUCKETS];
76 for (i, slot) in keys.iter_mut().enumerate() {
77 let owned = format!("client.connect.per_source.bucket_{i:03}");
79 *slot = Box::leak(owned.into_boxed_str());
80 }
81 keys
82});
83
84fn per_source_bucket(peer: &SocketAddr) -> &'static str {
89 let mut hasher = DefaultHasher::new();
90 match peer.ip() {
91 IpAddr::V4(v4) => {
92 let octets = v4.octets();
93 let masked = Ipv4Addr::new(octets[0], octets[1], octets[2], 0);
95 masked.hash(&mut hasher);
96 }
97 IpAddr::V6(v6) => {
98 let octets = v6.octets();
99 let mut masked_octets = [0u8; 16];
101 masked_octets[..6].copy_from_slice(&octets[..6]);
102 Ipv6Addr::from(masked_octets).hash(&mut hasher);
103 }
104 }
105 let idx = (hasher.finish() as usize) % PER_SOURCE_BUCKETS;
106 PER_SOURCE_BUCKET_KEYS[idx]
107}
108
109const ACCEPT_SATURATION_TICK: Duration = Duration::from_secs(1);
114
115pub type ProxyChannel = Channel<WorkerResponse, WorkerRequest>;
116
117thread_local! {
118 pub static QUEUE: RefCell<VecDeque<WorkerResponse>> = const { RefCell::new(VecDeque::new()) };
119}
120
121thread_local! {
122 pub static TIMER: RefCell<Timer<Token>> = RefCell::new(Timer::default());
123}
124
125pub fn push_queue(message: WorkerResponse) {
126 QUEUE.with(|queue| {
127 (*queue.borrow_mut()).push_back(message);
128 });
129}
130
131pub fn push_event(event: Event) {
132 QUEUE.with(|queue| {
133 (*queue.borrow_mut()).push_back(WorkerResponse {
134 id: "EVENT".to_string(),
135 message: String::new(),
136 status: ResponseStatus::Processing.into(),
137 content: Some(ContentType::Event(event).into()),
138 });
139 });
140}
141
142fn is_frontend_removal(request: &Request) -> bool {
144 matches!(
145 request.request_type,
146 Some(
147 RequestType::RemoveHttpFrontend(_)
148 | RequestType::RemoveHttpsFrontend(_)
149 | RequestType::RemoveTcpFrontend(_)
150 | RequestType::RemoveUdpFrontend(_)
151 )
152 )
153}
154
155fn worker_metric_detail_status_content(
161 configured: MetricDetailLevel,
162 effective: MetricDetailLevel,
163 previous_effective: MetricDetailLevel,
164 active_lease_count: u32,
165) -> ResponseContent {
166 use sozu_command::proto::command::WorkerMetricDetailStatus;
167 ContentType::WorkerMetricDetailStatus(WorkerMetricDetailStatus {
168 configured: MetricDetail::from(configured) as i32,
169 effective: MetricDetail::from(effective) as i32,
170 previous_effective: MetricDetail::from(previous_effective) as i32,
171 active_lease_count,
172 })
173 .into()
174}
175
176fn push_metric_detail_transition(
183 previous: MetricDetailLevel,
184 effective: MetricDetailLevel,
185 transition_kind: &'static str,
186 client_id: Option<String>,
187) {
188 use sozu_command::proto::command::MetricDetailTransition;
189 if previous == effective {
194 return;
195 }
196 push_event(Event {
197 kind: EventKind::MetricDetailChanged as i32,
198 cluster_id: None,
199 backend_id: None,
200 address: None,
201 metric_detail: Some(MetricDetailTransition {
202 previous_effective: MetricDetail::from(previous) as i32,
203 effective: MetricDetail::from(effective) as i32,
204 transition_kind: transition_kind.to_owned(),
205 client_id,
206 }),
207 });
208}
209
210fn tick_metric_detail_leases(now: Instant) {
218 let lease_tick_transition = METRICS.with(|metrics| {
225 let mut m = metrics.borrow_mut();
226 if !m.lease_tick_due(now) {
227 return None;
228 }
229 let previous = m.lease_tick(now)?;
230 let effective = m.detail_effective();
231 Some((previous, effective))
232 });
233 if let Some((previous, effective)) = lease_tick_transition {
234 push_metric_detail_transition(previous, effective, "lease_tick_expired", None);
239 }
240}
241
242#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
243pub struct ListenToken(pub usize);
244#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
245pub struct SessionToken(pub usize);
246
247impl From<usize> for ListenToken {
248 fn from(val: usize) -> ListenToken {
249 ListenToken(val)
250 }
251}
252
253impl From<ListenToken> for usize {
254 fn from(val: ListenToken) -> usize {
255 val.0
256 }
257}
258
259impl From<usize> for SessionToken {
260 fn from(val: usize) -> SessionToken {
261 SessionToken(val)
262 }
263}
264
265impl From<SessionToken> for usize {
266 fn from(val: SessionToken) -> usize {
267 val.0
268 }
269}
270
271fn mask_ipv4(address: Ipv4Addr, prefix: u32) -> Ipv4Addr {
285 if prefix >= u32::BITS {
286 return address;
287 }
288 if prefix == 0 {
289 return Ipv4Addr::UNSPECIFIED;
290 }
291 debug_assert!(
294 prefix > 0 && prefix < u32::BITS,
295 "both shift-overflowing ends must have returned before the shift"
296 );
297 let mask = u32::MAX << (u32::BITS - prefix);
298 let masked = Ipv4Addr::from(u32::from(address) & mask);
299 debug_assert_eq!(
303 u32::from(masked),
304 u32::from(address) & mask,
305 "masking must keep exactly the network bits of the source address"
306 );
307 debug_assert_eq!(
308 u32::from(masked) & !mask,
309 0,
310 "masking must clear every host bit below the prefix"
311 );
312 masked
313}
314
315fn mask_ipv6(address: Ipv6Addr, prefix: u32) -> Ipv6Addr {
319 if prefix >= u128::BITS {
320 return address;
321 }
322 if prefix == 0 {
323 return Ipv6Addr::UNSPECIFIED;
324 }
325 debug_assert!(
326 prefix > 0 && prefix < u128::BITS,
327 "both shift-overflowing ends must have returned before the shift"
328 );
329 let mask = u128::MAX << (u128::BITS - prefix);
330 let masked = Ipv6Addr::from(u128::from(address) & mask);
331 debug_assert_eq!(
332 u128::from(masked),
333 u128::from(address) & mask,
334 "masking must keep exactly the network bits of the source address"
335 );
336 debug_assert_eq!(
337 u128::from(masked) & !mask,
338 0,
339 "masking must clear every host bit below the prefix"
340 );
341 masked
342}
343
344pub fn subnet_key(address: &IpAddr, ipv4_prefix: u32, ipv6_prefix: u32) -> IpAddr {
355 let canonical_v4 = match address {
356 IpAddr::V4(v4) => Some(*v4),
357 IpAddr::V6(v6) => v6.to_ipv4_mapped(),
358 };
359 let key = match (canonical_v4, address) {
360 (Some(v4), _) => IpAddr::V4(mask_ipv4(v4, ipv4_prefix)),
361 (None, IpAddr::V6(v6)) => IpAddr::V6(mask_ipv6(*v6, ipv6_prefix)),
362 (None, IpAddr::V4(v4)) => IpAddr::V4(mask_ipv4(*v4, ipv4_prefix)),
364 };
365 debug_assert_eq!(
369 key.is_ipv4(),
370 canonical_v4.is_some(),
371 "subnet key family must follow the canonicalised source family"
372 );
373 debug_assert_eq!(
374 key.is_ipv6(),
375 canonical_v4.is_none(),
376 "a genuine IPv6 source must never produce an IPv4 subnet key"
377 );
378 key
379}
380
381pub struct SessionManager {
382 pub max_connections: usize,
383 pub nb_connections: usize,
384 pub can_accept: bool,
385 pub slab: Slab<Rc<RefCell<dyn ProxySession>>>,
386 pub max_connections_per_ip: u64,
390 pub retry_after: u32,
394 connections_per_cluster_ip: HashMap<ClusterId, HashMap<IpAddr, usize>>,
418 cluster_ip_tracks: HashMap<Token, HashMap<ClusterId, HashSet<IpAddr>>>,
425 pub max_connections_per_subnet: u64,
439 pub subnet_ipv4_prefix: u32,
443 pub subnet_ipv6_prefix: u32,
446 connections_per_cluster_subnet: HashMap<ClusterId, HashMap<IpAddr, usize>>,
459 cluster_subnet_tracks: HashMap<Token, HashMap<ClusterId, HashSet<IpAddr>>>,
462 pub max_connection_attempts: u32,
469}
470
471impl SessionManager {
472 pub fn new(
473 slab: Slab<Rc<RefCell<dyn ProxySession>>>,
474 max_connections: usize,
475 max_connections_per_ip: u64,
476 retry_after: u32,
477 max_connections_per_subnet: u64,
478 subnet_ipv4_prefix: u32,
479 subnet_ipv6_prefix: u32,
480 ) -> Rc<RefCell<Self>> {
481 Rc::new(RefCell::new(SessionManager {
482 max_connections,
483 nb_connections: 0,
484 can_accept: true,
485 slab,
486 max_connections_per_ip,
487 retry_after,
488 connections_per_cluster_ip: HashMap::new(),
489 cluster_ip_tracks: HashMap::new(),
490 max_connections_per_subnet,
491 subnet_ipv4_prefix,
492 subnet_ipv6_prefix,
493 connections_per_cluster_subnet: HashMap::new(),
494 cluster_subnet_tracks: HashMap::new(),
495 max_connection_attempts: sozu_command::config::DEFAULT_MAX_CONNECTION_ATTEMPTS,
496 }))
497 }
498
499 pub fn effective_max_connection_attempts(&self, override_value: Option<u32>) -> u32 {
503 override_value.unwrap_or(self.max_connection_attempts)
504 }
505
506 pub fn effective_max_connections_per_ip(&self, override_value: Option<u64>) -> u64 {
511 override_value.unwrap_or(self.max_connections_per_ip)
512 }
513
514 pub fn effective_retry_after(&self, override_value: Option<u32>) -> u32 {
518 override_value.unwrap_or(self.retry_after)
519 }
520
521 pub fn effective_max_connections_per_subnet(&self, override_value: Option<u64>) -> u64 {
526 override_value.unwrap_or(self.max_connections_per_subnet)
527 }
528
529 pub fn subnet_key(&self, ip: &IpAddr) -> IpAddr {
532 subnet_key(ip, self.subnet_ipv4_prefix, self.subnet_ipv6_prefix)
533 }
534
535 pub fn cluster_subnet_at_limit(
545 &self,
546 token: Token,
547 cluster_id: &str,
548 ip: &IpAddr,
549 override_value: Option<u64>,
550 ) -> bool {
551 let limit = self.effective_max_connections_per_subnet(override_value);
552 if limit == 0 {
553 return false;
554 }
555 debug_assert!(
556 limit > 0,
557 "limit==0 (unlimited) must have returned before reaching the bounded check"
558 );
559 let subnet = self.subnet_key(ip);
560 let already_tracked = self
561 .cluster_subnet_tracks
562 .get(&token)
563 .and_then(|by_cluster| by_cluster.get(cluster_id))
564 .is_some_and(|subnets| subnets.contains(&subnet));
565 if already_tracked {
566 debug_assert!(
567 self.connections_per_cluster_subnet
568 .get(cluster_id)
569 .and_then(|by_subnet| by_subnet.get(&subnet))
570 .is_some_and(|c| *c > 0),
571 "a tracked (token, cluster, subnet) slot must have a positive forward count"
572 );
573 return false;
574 }
575 self.connections_per_cluster_subnet
576 .get(cluster_id)
577 .and_then(|by_subnet| by_subnet.get(&subnet))
578 .is_some_and(|c| (*c as u64) >= limit)
579 }
580
581 pub fn cluster_connection_at_limit(
592 &self,
593 token: Token,
594 cluster_id: &str,
595 ip: &IpAddr,
596 ip_override: Option<u64>,
597 subnet_override: Option<u64>,
598 ) -> bool {
599 self.cluster_ip_at_limit(token, cluster_id, ip, ip_override)
600 || self.cluster_subnet_at_limit(token, cluster_id, ip, subnet_override)
601 }
602
603 pub fn cluster_ip_at_limit(
615 &self,
616 token: Token,
617 cluster_id: &str,
618 ip: &IpAddr,
619 override_value: Option<u64>,
620 ) -> bool {
621 let limit = self.effective_max_connections_per_ip(override_value);
622 if limit == 0 {
623 return false;
624 }
625 debug_assert!(
628 limit > 0,
629 "limit==0 (unlimited) must have returned before reaching the bounded check"
630 );
631 let already_tracked = self
632 .cluster_ip_tracks
633 .get(&token)
634 .and_then(|by_cluster| by_cluster.get(cluster_id))
635 .is_some_and(|ips| ips.contains(ip));
636 if already_tracked {
637 debug_assert!(
641 self.connections_per_cluster_ip
642 .get(cluster_id)
643 .and_then(|by_ip| by_ip.get(ip))
644 .is_some_and(|c| *c > 0),
645 "a tracked (token, cluster, ip) slot must have a positive forward count"
646 );
647 return false;
648 }
649 self.connections_per_cluster_ip
650 .get(cluster_id)
651 .and_then(|by_ip| by_ip.get(ip))
652 .is_some_and(|c| (*c as u64) >= limit)
653 }
654
655 pub fn track_cluster_ip(&mut self, token: Token, cluster_id: ClusterId, ip: IpAddr) {
735 let count_before = self
739 .connections_per_cluster_ip
740 .get(&cluster_id)
741 .and_then(|by_ip| by_ip.get(&ip))
742 .copied()
743 .unwrap_or(0);
744 let inserted = self
745 .cluster_ip_tracks
746 .entry(token)
747 .or_default()
748 .entry(cluster_id.clone())
749 .or_default()
750 .insert(ip);
751 if inserted {
752 *self
753 .connections_per_cluster_ip
754 .entry(cluster_id.clone())
755 .or_default()
756 .entry(ip)
757 .or_insert(0) += 1;
758 }
759 debug_assert!(
763 self.cluster_ip_tracks
764 .get(&token)
765 .and_then(|by_cluster| by_cluster.get(&cluster_id))
766 .is_some_and(|ips| ips.contains(&ip)),
767 "track must leave the (token, cluster, ip) recorded in the reverse index"
768 );
769 debug_assert_eq!(
770 self.connections_per_cluster_ip
771 .get(&cluster_id)
772 .and_then(|by_ip| by_ip.get(&ip))
773 .copied()
774 .unwrap_or(0),
775 count_before + inserted as usize,
776 "forward count must advance by exactly 1 on first track, 0 on a repeat"
777 );
778 #[cfg(debug_assertions)]
779 self.check_invariants();
780 }
781
782 pub fn track_cluster_subnet(
796 &mut self,
797 token: Token,
798 cluster_id: ClusterId,
799 ip: IpAddr,
800 override_value: Option<u64>,
801 ) {
802 if self.effective_max_connections_per_subnet(override_value) == 0 {
803 return;
811 }
812 let subnet = self.subnet_key(&ip);
813 let count_before = self
817 .connections_per_cluster_subnet
818 .get(&cluster_id)
819 .and_then(|by_subnet| by_subnet.get(&subnet))
820 .copied()
821 .unwrap_or(0);
822 let inserted = self
823 .cluster_subnet_tracks
824 .entry(token)
825 .or_default()
826 .entry(cluster_id.clone())
827 .or_default()
828 .insert(subnet);
829 if inserted {
830 *self
831 .connections_per_cluster_subnet
832 .entry(cluster_id.clone())
833 .or_default()
834 .entry(subnet)
835 .or_insert(0) += 1;
836 }
837 debug_assert!(
838 self.cluster_subnet_tracks
839 .get(&token)
840 .and_then(|by_cluster| by_cluster.get(&cluster_id))
841 .is_some_and(|subnets| subnets.contains(&subnet)),
842 "track must leave the (token, cluster, subnet) recorded in the reverse index"
843 );
844 debug_assert_eq!(
845 self.connections_per_cluster_subnet
846 .get(&cluster_id)
847 .and_then(|by_subnet| by_subnet.get(&subnet))
848 .copied()
849 .unwrap_or(0),
850 count_before + inserted as usize,
851 "forward count must advance by exactly 1 on first track, 0 on a repeat"
852 );
853 #[cfg(debug_assertions)]
854 self.check_invariants();
855 }
856
857 pub fn track_cluster_connection(
863 &mut self,
864 token: Token,
865 cluster_id: ClusterId,
866 ip: IpAddr,
867 subnet_override: Option<u64>,
868 ) {
869 self.track_cluster_ip(token, cluster_id.clone(), ip);
870 self.track_cluster_subnet(token, cluster_id, ip, subnet_override);
871 }
872
873 pub fn untrack_all_cluster_ip(&mut self, token: Token) {
887 self.untrack_all_cluster_subnet(token);
888 let Some(by_cluster) = self.cluster_ip_tracks.remove(&token) else {
889 return;
890 };
891 debug_assert!(
894 !self.cluster_ip_tracks.contains_key(&token),
895 "untrack_all must evict the token from the reverse index"
896 );
897 for (cluster_id, ips) in by_cluster {
898 let Entry::Occupied(mut outer) = self.connections_per_cluster_ip.entry(cluster_id)
899 else {
900 continue;
901 };
902 for ip in ips {
903 if let Entry::Occupied(mut inner) = outer.get_mut().entry(ip) {
904 let count = inner.get_mut();
905 *count = count.saturating_sub(1);
906 if *count == 0 {
907 inner.remove();
908 }
909 }
910 }
911 if outer.get().is_empty() {
912 outer.remove();
913 }
914 }
915 debug_assert!(
918 self.connections_per_cluster_ip
919 .values()
920 .all(|by_ip| !by_ip.is_empty() && by_ip.values().all(|&c| c > 0)),
921 "untrack_all must not leave empty inner maps or zero-count ips behind"
922 );
923 #[cfg(debug_assertions)]
924 self.check_invariants();
925 }
926
927 fn untrack_all_cluster_subnet(&mut self, token: Token) {
932 let Some(by_cluster) = self.cluster_subnet_tracks.remove(&token) else {
933 return;
934 };
935 debug_assert!(
936 !self.cluster_subnet_tracks.contains_key(&token),
937 "untrack_all must evict the token from the subnet reverse index"
938 );
939 for (cluster_id, subnets) in by_cluster {
940 let Entry::Occupied(mut outer) = self.connections_per_cluster_subnet.entry(cluster_id)
941 else {
942 continue;
943 };
944 for subnet in subnets {
945 if let Entry::Occupied(mut inner) = outer.get_mut().entry(subnet) {
946 let count = inner.get_mut();
947 *count = count.saturating_sub(1);
948 if *count == 0 {
949 inner.remove();
950 }
951 }
952 }
953 if outer.get().is_empty() {
954 outer.remove();
955 }
956 }
957 debug_assert!(
958 self.connections_per_cluster_subnet
959 .values()
960 .all(|by_subnet| !by_subnet.is_empty() && by_subnet.values().all(|&c| c > 0)),
961 "untrack_all must not leave empty inner maps or zero-count subnets behind"
962 );
963 }
964
965 pub fn subnet_tracking_is_empty(&self) -> bool {
971 self.cluster_subnet_tracks.is_empty() && self.connections_per_cluster_subnet.is_empty()
972 }
973
974 pub fn clear_cluster_subnet_tracking(&mut self) {
980 self.cluster_subnet_tracks.clear();
981 self.connections_per_cluster_subnet.clear();
982 debug_assert!(
983 self.cluster_subnet_tracks.is_empty() && self.connections_per_cluster_subnet.is_empty(),
984 "clear must wipe both the subnet reverse index and the subnet forward count map"
985 );
986 #[cfg(debug_assertions)]
987 self.check_invariants();
988 }
989
990 pub fn clear_cluster_ip_tracking(&mut self) {
995 self.cluster_ip_tracks.clear();
996 self.connections_per_cluster_ip.clear();
997 debug_assert!(
1000 self.cluster_ip_tracks.is_empty() && self.connections_per_cluster_ip.is_empty(),
1001 "clear must wipe both the reverse index and the forward count map"
1002 );
1003 #[cfg(debug_assertions)]
1004 self.check_invariants();
1005 }
1006
1007 pub fn at_capacity(&self) -> bool {
1009 self.slab.len() >= self.accept_slab_threshold()
1010 }
1011
1012 pub fn accept_slab_threshold(&self) -> usize {
1024 let threshold = 10 + 2 * self.max_connections;
1025 debug_assert!(
1029 threshold > self.max_connections,
1030 "accept gate must sit strictly above max_connections to reserve system slots"
1031 );
1032 threshold
1033 }
1034
1035 pub fn check_limits(&mut self) -> bool {
1038 debug_assert!(
1041 self.nb_connections <= self.max_connections,
1042 "nb_connections must never exceed max_connections"
1043 );
1044 if self.nb_connections >= self.max_connections {
1045 error!("max number of session connection reached, flushing the accept queue");
1046 gauge!(names::accept_queue::BACKPRESSURE, 1);
1047 self.can_accept = false;
1048 debug_assert!(
1050 !self.can_accept,
1051 "refusing at the cap must clear can_accept"
1052 );
1053 return false;
1054 }
1055
1056 if self.at_capacity() {
1057 error!("not enough memory to accept another session, flushing the accept queue");
1058 error!(
1059 "nb_connections: {}, max_connections: {}",
1060 self.nb_connections, self.max_connections
1061 );
1062 gauge!(names::accept_queue::BACKPRESSURE, 1);
1063 self.can_accept = false;
1064
1065 debug_assert!(
1066 !self.can_accept,
1067 "refusing at slab capacity must clear can_accept"
1068 );
1069 return false;
1070 }
1071
1072 debug_assert!(
1074 self.nb_connections < self.max_connections && !self.at_capacity(),
1075 "check_limits returned room while a gate was actually saturated"
1076 );
1077 true
1078 }
1079
1080 pub fn to_session(token: Token) -> SessionToken {
1081 SessionToken(token.0)
1082 }
1083
1084 pub fn incr(&mut self) {
1085 let before = self.nb_connections;
1086 self.nb_connections += 1;
1087 assert!(self.nb_connections <= self.max_connections);
1088 debug_assert_eq!(
1090 self.nb_connections,
1091 before + 1,
1092 "incr must raise nb_connections by exactly one"
1093 );
1094 gauge!(names::client::CONNECTIONS, self.nb_connections);
1100 }
1101
1102 pub fn decr(&mut self) {
1105 assert!(self.nb_connections != 0);
1106 let before = self.nb_connections;
1107 self.nb_connections -= 1;
1108 debug_assert_eq!(
1110 self.nb_connections,
1111 before - 1,
1112 "decr must lower nb_connections by exactly one"
1113 );
1114 gauge!(names::client::CONNECTIONS, self.nb_connections);
1115
1116 if !self.can_accept && self.nb_connections < self.max_connections * 90 / 100 {
1118 debug!(
1119 "nb_connections = {}, max_connections = {}, starting to accept again",
1120 self.nb_connections, self.max_connections
1121 );
1122 gauge!(names::accept_queue::BACKPRESSURE, 0);
1123 self.can_accept = true;
1124 }
1125 }
1126
1127 #[cfg(debug_assertions)]
1132 fn check_invariants(&self) {
1133 debug_assert!(
1135 self.nb_connections <= self.max_connections,
1136 "nb_connections {} exceeds max_connections {}",
1137 self.nb_connections,
1138 self.max_connections
1139 );
1140 debug_assert!(
1143 self.connections_per_cluster_ip
1144 .values()
1145 .all(|by_ip| !by_ip.is_empty() && by_ip.values().all(|&c| c > 0)),
1146 "connections_per_cluster_ip holds an empty inner map or a zero count"
1147 );
1148 debug_assert!(
1153 self.cluster_ip_tracks.values().all(|by_cluster| {
1154 by_cluster.iter().all(|(cluster_id, ips)| {
1155 ips.iter().all(|ip| {
1156 self.connections_per_cluster_ip
1157 .get(cluster_id)
1158 .and_then(|by_ip| by_ip.get(ip))
1159 .is_some_and(|&c| c > 0)
1160 })
1161 })
1162 }),
1163 "a tracked (token, cluster, ip) slot has no positive forward count"
1164 );
1165 debug_assert!(
1167 self.cluster_ip_tracks.values().all(|by_cluster| {
1168 !by_cluster.is_empty() && by_cluster.values().all(|ips| !ips.is_empty())
1169 }),
1170 "cluster_ip_tracks retains an empty per-token or per-cluster entry"
1171 );
1172 debug_assert!(
1174 self.connections_per_cluster_subnet
1175 .values()
1176 .all(|by_subnet| !by_subnet.is_empty() && by_subnet.values().all(|&c| c > 0)),
1177 "connections_per_cluster_subnet holds an empty inner map or a zero count"
1178 );
1179 debug_assert!(
1180 self.cluster_subnet_tracks.values().all(|by_cluster| {
1181 by_cluster.iter().all(|(cluster_id, subnets)| {
1182 subnets.iter().all(|subnet| {
1183 self.connections_per_cluster_subnet
1184 .get(cluster_id)
1185 .and_then(|by_subnet| by_subnet.get(subnet))
1186 .is_some_and(|&c| c > 0)
1187 })
1188 })
1189 }),
1190 "a tracked (token, cluster, subnet) slot has no positive forward count"
1191 );
1192 debug_assert!(
1193 self.cluster_subnet_tracks.values().all(|by_cluster| {
1194 !by_cluster.is_empty() && by_cluster.values().all(|subnets| !subnets.is_empty())
1195 }),
1196 "cluster_subnet_tracks retains an empty per-token or per-cluster entry"
1197 );
1198 }
1199}
1200
1201#[derive(thiserror::Error, Debug)]
1202pub enum ServerError {
1203 #[error("could not create event loop with MIO poll: {0}")]
1204 CreatePoll(IoError),
1205 #[error("could not clone the MIO registry: {0}")]
1206 CloneRegistry(IoError),
1207 #[error("could not register the channel: {0}")]
1208 RegisterChannel(IoError),
1209 #[error("{msg}:{scm_err}")]
1210 ScmSocket {
1211 msg: String,
1212 scm_err: ScmSocketError,
1213 },
1214}
1215
1216pub struct Server {
1233 accept_queue_timeout: Duration,
1234 accept_queue: VecDeque<(TcpStream, ListenToken, Protocol, Instant, SocketAddr)>,
1241 evict_on_queue_full: bool,
1245 accept_ready: HashSet<ListenToken>,
1246 backends: Rc<RefCell<BackendMap>>,
1247 base_sessions_count: usize,
1248 channel: ProxyChannel,
1249 config_state: ConfigState,
1250 current_poll_errors: i32,
1251 health_checker: HealthChecker,
1252 http: Rc<RefCell<http::HttpProxy>>,
1253 https: Rc<RefCell<https::HttpsProxy>>,
1254 last_sessions_len: usize,
1255 last_shutting_down_message: Option<Instant>,
1256 last_zombie_check: Instant,
1257 loop_start: Instant,
1258 started_at: Instant,
1262 last_saturation_tick: Instant,
1267 max_poll_errors: i32, pool: Rc<RefCell<Pool>>,
1274 pub poll: Poll,
1275 poll_timeout: Option<Duration>, scm_listeners: Option<Listeners>,
1277 scm: ScmSocket,
1278 sessions: Rc<RefCell<SessionManager>>,
1279 should_poll_at: Option<Instant>,
1280 shutting_down: Option<String>,
1281 tcp: Rc<RefCell<tcp::TcpProxy>>,
1282 udp: Rc<RefCell<udp::UdpProxy>>,
1283 zombie_check_interval: Duration,
1284}
1285
1286impl Server {
1287 pub fn try_new_from_config(
1288 worker_to_main_channel: ProxyChannel,
1289 worker_to_main_scm: ScmSocket,
1290 config: ServerConfig,
1291 initial_state: InitialState,
1292 expects_initial_status: bool,
1293 ) -> Result<Self, ServerError> {
1294 let event_loop = Poll::new().map_err(ServerError::CreatePoll)?;
1295 if let Some(cap) = config.basic_auth_max_credential_bytes {
1302 crate::protocol::mux::auth::set_max_decoded_credential_bytes(cap as usize);
1303 }
1304 #[cfg(all(target_os = "linux", feature = "splice"))]
1311 if let Some(cap) = config.splice_pipe_capacity_bytes {
1312 crate::splice::set_pipe_capacity(cap as usize);
1313 }
1314 let pool = Rc::new(RefCell::new(Pool::with_capacity(
1315 config.min_buffers as usize,
1316 config.max_buffers as usize,
1317 config.buffer_size as usize,
1318 )));
1319 let backends = Rc::new(RefCell::new(BackendMap::new()));
1320
1321 let sessions: Rc<RefCell<SessionManager>> = SessionManager::new(
1326 Slab::with_capacity(config.slab_capacity() as usize),
1327 config.max_connections as usize,
1328 config
1329 .max_connections_per_ip
1330 .unwrap_or(sozu_command::config::DEFAULT_MAX_CONNECTIONS_PER_IP),
1331 config
1332 .retry_after
1333 .unwrap_or(sozu_command::config::DEFAULT_RETRY_AFTER),
1334 config
1335 .max_connections_per_subnet
1336 .unwrap_or(sozu_command::config::DEFAULT_MAX_CONNECTIONS_PER_SUBNET),
1337 config
1338 .subnet_ipv4_prefix
1339 .unwrap_or(sozu_command::config::DEFAULT_SUBNET_IPV4_PREFIX),
1340 config
1341 .subnet_ipv6_prefix
1342 .unwrap_or(sozu_command::config::DEFAULT_SUBNET_IPV6_PREFIX),
1343 );
1344 sessions.borrow_mut().max_connection_attempts = match config.max_connection_attempts {
1348 Some(attempts)
1349 if sozu_command::config::validate_max_connection_attempts(attempts).is_ok() =>
1350 {
1351 attempts
1352 }
1353 Some(attempts) => {
1354 error!(
1355 "max_connection_attempts = {} is out of 1..=255, keeping {}",
1356 attempts,
1357 sozu_command::config::DEFAULT_MAX_CONNECTION_ATTEMPTS
1358 );
1359 sozu_command::config::DEFAULT_MAX_CONNECTION_ATTEMPTS
1360 }
1361 None => sozu_command::config::DEFAULT_MAX_CONNECTION_ATTEMPTS,
1362 };
1363 {
1364 let mut s = sessions.borrow_mut();
1365 let entry = s.slab.vacant_entry();
1366 trace!("taking token {:?} for channel", SessionToken(entry.key()));
1367 entry.insert(Rc::new(RefCell::new(ListenSession {
1368 protocol: Protocol::Channel,
1369 })));
1370 }
1371 {
1372 let mut s = sessions.borrow_mut();
1373 let entry = s.slab.vacant_entry();
1374 trace!("taking token {:?} for metrics", SessionToken(entry.key()));
1375 entry.insert(Rc::new(RefCell::new(ListenSession {
1376 protocol: Protocol::Timer,
1377 })));
1378 }
1379 {
1380 let mut s = sessions.borrow_mut();
1381 let entry = s.slab.vacant_entry();
1382 trace!("taking token {:?} for metrics", SessionToken(entry.key()));
1383 entry.insert(Rc::new(RefCell::new(ListenSession {
1384 protocol: Protocol::Metrics,
1385 })));
1386 }
1387
1388 Server::new(
1389 event_loop,
1390 worker_to_main_channel,
1391 worker_to_main_scm,
1392 sessions,
1393 pool,
1394 backends,
1395 None,
1396 None,
1397 None,
1398 config,
1399 Some(initial_state),
1400 expects_initial_status,
1401 )
1402 }
1403
1404 #[allow(clippy::too_many_arguments)]
1405 pub fn new(
1406 poll: Poll,
1407 mut channel: ProxyChannel,
1408 scm: ScmSocket,
1409 sessions: Rc<RefCell<SessionManager>>,
1410 pool: Rc<RefCell<Pool>>,
1411 backends: Rc<RefCell<BackendMap>>,
1412 http: Option<http::HttpProxy>,
1413 https: Option<https::HttpsProxy>,
1414 tcp: Option<tcp::TcpProxy>,
1415 server_config: ServerConfig,
1416 initial_state: Option<InitialState>,
1417 expects_initial_status: bool,
1418 ) -> Result<Self, ServerError> {
1419 FEATURES.with(|_features| {
1420 });
1422
1423 poll.registry()
1424 .register(
1425 &mut channel,
1426 Token(0),
1427 Interest::READABLE | Interest::WRITABLE,
1428 )
1429 .map_err(ServerError::RegisterChannel)?;
1430
1431 METRICS.with(|metrics| {
1432 if let Some(sock) = (*metrics.borrow_mut()).socket_mut() {
1433 poll.registry()
1434 .register(sock, Token(2), Interest::WRITABLE)
1435 .expect("should register the metrics socket");
1436 }
1437 });
1438
1439 let base_sessions_count = sessions.borrow().slab.len();
1440
1441 let http = Rc::new(RefCell::new(match http {
1442 Some(http) => http,
1443 None => {
1444 let registry = poll
1445 .registry()
1446 .try_clone()
1447 .map_err(ServerError::CloneRegistry)?;
1448
1449 http::HttpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
1450 }
1451 }));
1452
1453 let https = Rc::new(RefCell::new(match https {
1454 Some(https) => https,
1455 None => {
1456 let registry = poll
1457 .registry()
1458 .try_clone()
1459 .map_err(ServerError::CloneRegistry)?;
1460
1461 https::HttpsProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
1462 }
1463 }));
1464
1465 let tcp = Rc::new(RefCell::new(match tcp {
1466 Some(tcp) => tcp,
1467 None => {
1468 let registry = poll
1469 .registry()
1470 .try_clone()
1471 .map_err(ServerError::CloneRegistry)?;
1472
1473 tcp::TcpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone())
1474 }
1475 }));
1476
1477 let udp = Rc::new(RefCell::new({
1481 let registry = poll
1482 .registry()
1483 .try_clone()
1484 .map_err(ServerError::CloneRegistry)?;
1485
1486 udp::UdpProxy::new(
1487 registry,
1488 sessions.clone(),
1489 pool.clone(),
1490 backends.clone(),
1491 server_config.max_connections as usize,
1492 server_config.buffer_size as usize,
1493 )
1494 }));
1495
1496 let mut server = Server {
1497 accept_queue_timeout: Duration::from_secs(u64::from(
1498 server_config.accept_queue_timeout,
1499 )),
1500 accept_queue: VecDeque::new(),
1501 evict_on_queue_full: server_config.evict_on_queue_full.unwrap_or(false),
1502 accept_ready: HashSet::new(),
1503 backends,
1504 base_sessions_count,
1505 channel,
1506 config_state: ConfigState::new(),
1507 current_poll_errors: 0,
1508 health_checker: HealthChecker::new(),
1509 http,
1510 https,
1511 last_sessions_len: 0, last_shutting_down_message: None,
1513 last_zombie_check: Instant::now(), loop_start: Instant::now(), started_at: Instant::now(), last_saturation_tick: Instant::now(), max_poll_errors: 10000, pool,
1519 poll_timeout: Some(Duration::from_millis(1000)), poll,
1521 scm_listeners: None,
1522 scm,
1523 sessions,
1524 should_poll_at: None,
1525 shutting_down: None,
1526 tcp,
1527 udp,
1528 zombie_check_interval: Duration::from_secs(u64::from(
1529 server_config.zombie_check_interval,
1530 )),
1531 };
1532
1533 info!("will try to receive listeners");
1554 server
1555 .scm
1556 .set_blocking(true)
1557 .map_err(|scm_err| ServerError::ScmSocket {
1558 msg: "Could not set the scm socket to blocking".to_string(),
1559 scm_err,
1560 })?;
1561 let listeners =
1562 server
1563 .scm
1564 .receive_listeners()
1565 .map_err(|scm_err| ServerError::ScmSocket {
1566 msg: "could not receive listeners from the scm socket".to_string(),
1567 scm_err,
1568 })?;
1569 server
1570 .scm
1571 .set_blocking(false)
1572 .map_err(|scm_err| ServerError::ScmSocket {
1573 msg: "Could not set the scm socket to unblocking".to_string(),
1574 scm_err,
1575 })?;
1576 info!("received listeners: {:?}", listeners);
1577 server.scm_listeners = Some(listeners);
1578
1579 if let Some(state) = initial_state {
1581 for request in state.requests {
1582 trace!("generating initial config request: {:#?}", request);
1583 server.notify_proxys(request);
1584 }
1585
1586 QUEUE.with(|queue| {
1588 (*queue.borrow_mut()).clear();
1589 });
1590 }
1591
1592 server.report_unclaimed_inherited_sockets();
1593
1594 if expects_initial_status {
1595 server.block_channel();
1598 let msg = server.channel.read_message();
1599 debug!("got message: {:?}", msg);
1600
1601 if let Ok(WorkerRequest {
1602 id,
1603 content:
1604 Request {
1605 request_type: Some(RequestType::Status(_)),
1606 },
1607 }) = msg
1608 {
1609 if let Err(e) = server.channel.write_message(&WorkerResponse::ok(id)) {
1610 error!("Could not send an ok to the main process: {}", e);
1611 }
1612 } else {
1613 panic!(
1614 "plz give me a status request first when I start, you sent me this instead: {msg:?}"
1615 );
1616 }
1617 server.unblock_channel();
1618 }
1619
1620 Ok(server)
1621 }
1622
1623 pub fn run(&mut self) {
1625 let mut events = Events::with_capacity(1024); let mut event_owners: Vec<Option<Rc<RefCell<dyn ProxySession>>>> =
1630 Vec::with_capacity(events.capacity());
1631 self.last_sessions_len = self.sessions.borrow().slab.len();
1632
1633 self.last_zombie_check = Instant::now();
1634 self.loop_start = Instant::now();
1635
1636 loop {
1637 self.check_for_poll_errors();
1638
1639 let timeout = self.reset_loop_time_and_get_timeout();
1640
1641 match self.poll.poll(&mut events, timeout) {
1642 Ok(_) => self.current_poll_errors = 0,
1643 Err(error) => {
1644 error!("Error while polling events: {:?}", error);
1645 self.current_poll_errors += 1;
1646 continue;
1647 }
1648 }
1649
1650 let after_epoll = Instant::now();
1651 time!(
1652 names::event_loop::EPOLL_TIME,
1653 (after_epoll - self.loop_start).as_millis()
1654 );
1655 self.loop_start = after_epoll;
1656
1657 tick_metric_detail_leases(after_epoll);
1659
1660 self.send_queue();
1661
1662 self.snapshot_event_owners(events.iter().map(|event| event.token()), &mut event_owners);
1663 for (event, owner) in events.iter().zip(event_owners.drain(..)) {
1664 match event.token() {
1665 Token(0) => {
1667 if event.is_error() {
1668 error!("error reading from command channel");
1669 continue;
1670 }
1671 if event.is_read_closed() || event.is_write_closed() {
1672 error!("command channel was closed");
1673 return;
1674 }
1675 let ready = Ready::from(event);
1676 self.channel.handle_events(ready);
1677
1678 loop {
1680 QUEUE.with(|queue| {
1681 if !(*queue.borrow()).is_empty() {
1682 self.channel.interest.insert(Ready::WRITABLE);
1683 }
1684 });
1685
1686 if self.channel.readiness() == Ready::EMPTY {
1689 break;
1690 }
1691
1692 if self.read_channel_messages_and_notify() {
1694 return;
1695 }
1696
1697 QUEUE.with(|queue| {
1698 if !(*queue.borrow()).is_empty() {
1699 self.channel.interest.insert(Ready::WRITABLE);
1700 }
1701 });
1702
1703 self.send_queue();
1704 }
1705 }
1706 Token(1) => {
1708 while let Some(t) = TIMER.with(|timer| timer.borrow_mut().poll()) {
1709 self.timeout(t);
1710 }
1711 }
1712 Token(2) => METRICS.with(|metrics| {
1714 (*metrics.borrow_mut()).writable();
1715 }),
1716 token if self.health_checker.owns_token(token) => {
1719 self.health_checker.ready(token);
1720 }
1721 token if self.udp.borrow().health_owns_token(token) => {
1722 self.udp.borrow_mut().health_ready(token);
1723 }
1724 token => self.ready_if_still_owned(token, Ready::from(event), owner),
1725 }
1726 }
1727
1728 if let Some(t) = self.should_poll_at.as_ref()
1729 && *t <= Instant::now()
1730 {
1731 while let Some(t) = TIMER.with(|timer| timer.borrow_mut().poll()) {
1732 self.timeout(t);
1734 }
1735 }
1736 self.handle_remaining_readiness();
1737 self.create_sessions();
1738
1739 self.should_poll_at = TIMER.with(|timer| timer.borrow().next_poll_date());
1740
1741 self.zombie_check();
1742 self.health_checker
1743 .poll(&self.backends, self.poll.registry());
1744 self.udp.borrow_mut().health_poll();
1748
1749 {
1762 let sessions = self.sessions.borrow();
1763 let nb_connections = sessions.nb_connections;
1764 let max_connections = sessions.max_connections;
1765 let slab_len = sessions.slab.len();
1766 let slab_capacity = sessions.slab.capacity();
1767 let accept_threshold = sessions.accept_slab_threshold();
1768
1769 gauge!(names::client::CONNECTIONS, nb_connections);
1770 gauge!(names::client::CONNECTIONS_MAX, max_connections);
1771 if let Some(percent) = (nb_connections * 100).checked_div(max_connections) {
1772 gauge!(names::client::CONNECTIONS_PERCENT, percent);
1773 }
1774
1775 gauge!(names::slab::ENTRIES, slab_len);
1776 gauge!(names::slab::CAPACITY, slab_capacity);
1777 if let Some(percent) = (slab_len * 100).checked_div(slab_capacity) {
1778 gauge!(names::slab::USAGE_PERCENT, percent);
1779 }
1780 if let Some(percent) = (slab_len * 100).checked_div(accept_threshold) {
1781 gauge!(names::slab::ACCEPT_THRESHOLD_PERCENT, percent);
1782 }
1783 }
1784 {
1790 let pool = self.pool.borrow();
1791 let used = pool.inner.used();
1792 let capacity = pool.inner.capacity();
1793 gauge!(names::buffer::IN_USE, used);
1794 gauge!(names::buffer::CAPACITY, capacity);
1795 if let Some(percent) = (used * 100).checked_div(capacity) {
1796 gauge!(names::buffer::USAGE_PERCENT, percent);
1797 }
1798 }
1799 let now = Instant::now();
1807 if now.duration_since(self.last_saturation_tick) >= ACCEPT_SATURATION_TICK {
1808 if !self.sessions.borrow().can_accept {
1809 incr!(names::accept_queue::SATURATED_SECONDS);
1810 }
1811 self.last_saturation_tick = now;
1812 }
1813 gauge!(
1817 names::process::UPTIME_SECONDS,
1818 self.started_at.elapsed().as_secs() as usize
1819 );
1820 gauge!(
1825 names::server::LIVE,
1826 if self.shutting_down.is_some() { 0 } else { 1 }
1827 );
1828 METRICS.with(|metrics| {
1829 (*metrics.borrow_mut()).send_data();
1830 });
1831
1832 if self.shutting_down.is_some() && self.shut_down_sessions() {
1833 return;
1834 }
1835 }
1836 }
1837
1838 fn check_for_poll_errors(&mut self) {
1839 if self.current_poll_errors >= self.max_poll_errors {
1840 error!(
1841 "Something is going very wrong. Last {} poll() calls failed, crashing..",
1842 self.current_poll_errors
1843 );
1844 panic!(
1845 "poll() calls failed {} times in a row",
1846 self.current_poll_errors
1847 );
1848 }
1849 }
1850
1851 fn reset_loop_time_and_get_timeout(&mut self) -> Option<Duration> {
1852 let now = Instant::now();
1853 time!(
1854 names::event_loop::EVENT_LOOP_TIME,
1855 (now - self.loop_start).as_millis()
1856 );
1857
1858 let mut timeout = match self.should_poll_at.as_ref() {
1859 None => self.poll_timeout,
1860 Some(i) => {
1861 if *i <= now {
1862 self.poll_timeout
1863 } else {
1864 let dur = *i - now;
1865 match self.poll_timeout {
1866 None => Some(dur),
1867 Some(t) => {
1868 if t < dur {
1869 Some(t)
1870 } else {
1871 Some(dur)
1872 }
1873 }
1874 }
1875 }
1876 }
1877 };
1878
1879 if self.shutting_down.is_some() {
1880 let shutdown_tick = Duration::from_millis(100);
1881 timeout = match timeout {
1882 None => Some(shutdown_tick),
1883 Some(current) => Some(current.min(shutdown_tick)),
1884 };
1885 }
1886
1887 self.loop_start = now;
1888 timeout
1889 }
1890
1891 fn read_channel_messages_and_notify(&mut self) -> bool {
1893 if !self.channel.readiness().is_readable() {
1894 return false;
1895 }
1896
1897 if let Err(e) = self.channel.readable() {
1898 error!("error reading from channel: {:?}", e);
1899 }
1900
1901 loop {
1902 let request = self.channel.read_message();
1903 debug!("Received request {:?}", request);
1904 match request {
1905 Ok(request) => match request.content.request_type {
1906 Some(RequestType::HardStop(_)) => {
1907 let req_id = request.id.clone();
1908 self.notify(request);
1909 if let Err(e) = self.channel.write_message(&WorkerResponse::ok(req_id)) {
1910 error!("Could not send ok response to the main process: {}", e);
1911 }
1912 if let Err(e) = self.channel.run() {
1913 error!("Error while running the server channel: {}", e);
1914 }
1915 return true;
1916 }
1917 Some(RequestType::SoftStop(_)) => {
1918 self.shutting_down = Some(request.id.clone());
1919 self.last_sessions_len = self.sessions.borrow().slab.len();
1920 self.notify(request);
1921 }
1922 Some(RequestType::ReturnListenSockets(_)) => {
1923 info!("received ReturnListenSockets order");
1924 match self.return_listen_sockets() {
1925 Ok(_) => push_queue(WorkerResponse::ok(request.id)),
1926 Err(error) => push_queue(worker_response_error(
1927 request.id,
1928 format!("Could not send listeners on scm socket: {error:?}"),
1929 )),
1930 }
1931 }
1932 _ => self.notify(request),
1933 },
1934 Err(_) => {
1936 if (self.channel.interest & self.channel.readiness).is_readable() {
1938 if let Err(e) = self.channel.readable() {
1939 error!("error reading from channel: {:?}", e);
1940 }
1941 continue;
1942 }
1943 break;
1944 }
1945 }
1946 }
1947 false
1948 }
1949
1950 fn zombie_check(&mut self) {
1952 let now = Instant::now();
1953 if now - self.last_zombie_check < self.zombie_check_interval {
1954 return;
1955 }
1956 info!("zombie check");
1957 debug_assert!(
1960 now >= self.last_zombie_check,
1961 "zombie-check timestamp must never move backwards"
1962 );
1963 self.last_zombie_check = now;
1964
1965 let mut zombie_tokens = HashSet::new();
1966
1967 for (_index, session) in self
1969 .sessions
1970 .borrow_mut()
1971 .slab
1972 .iter_mut()
1973 .filter(|(_, c)| now - c.borrow().last_event() > self.zombie_check_interval)
1974 {
1975 let session_token = session.borrow().frontend_token();
1976 if !zombie_tokens.contains(&session_token) {
1977 session.borrow().print_session();
1978 zombie_tokens.insert(session_token);
1979 }
1980 }
1981
1982 debug_assert!(
1987 !self.sessions.borrow().slab.iter().any(|(_, session)| {
1988 let s = session.borrow();
1989 zombie_tokens.contains(&s.frontend_token())
1990 && matches!(
1991 s.protocol(),
1992 Protocol::HTTPListen | Protocol::HTTPSListen | Protocol::TCPListen
1993 )
1994 }),
1995 "zombie reaping must never target a listener session"
1996 );
1997
1998 let zombie_count = zombie_tokens.len() as i64;
1999 count!(names::misc::ZOMBIES, zombie_count);
2000
2001 let remaining_count = self.shut_down_sessions_by_frontend_tokens(zombie_tokens);
2002 info!(
2003 "removing {} zombies ({} remaining entries after close)",
2004 zombie_count, remaining_count
2005 );
2006 }
2007
2008 fn shut_down_sessions_by_frontend_tokens(&self, tokens: HashSet<Token>) -> usize {
2011 if tokens.is_empty() {
2012 return 0;
2013 }
2014
2015 for token in &tokens {
2017 if self.sessions.borrow().slab.contains(token.0) {
2018 let slab_before = self.sessions.borrow().slab.len();
2019 let session = { self.sessions.borrow_mut().slab.remove(token.0) };
2020 session.borrow_mut().close();
2021 self.sessions.borrow_mut().decr();
2022 debug_assert!(
2027 !self.sessions.borrow().slab.contains(token.0),
2028 "removed token must be absent from the slab"
2029 );
2030 debug_assert!(
2031 self.sessions.borrow().slab.len() < slab_before,
2032 "removing a present session must free at least its own slab slot"
2033 );
2034 }
2035 }
2036
2037 let mut dangling_entries = HashSet::new();
2039 for (entry_key, session) in &self.sessions.borrow().slab {
2040 if tokens.contains(&session.borrow().frontend_token()) {
2041 dangling_entries.insert(entry_key);
2042 }
2043 }
2044
2045 let mut dangling_entries_count = 0;
2047 for entry_key in dangling_entries {
2048 let mut sessions = self.sessions.borrow_mut();
2049 if sessions.slab.contains(entry_key) {
2050 sessions.slab.remove(entry_key);
2051 dangling_entries_count += 1;
2052 }
2053 }
2054 debug_assert!(
2058 !self
2059 .sessions
2060 .borrow()
2061 .slab
2062 .iter()
2063 .any(|(_, session)| tokens.contains(&session.borrow().frontend_token())),
2064 "no slab entry may reference a closed frontend token after teardown"
2065 );
2066 dangling_entries_count
2067 }
2068
2069 fn shut_down_sessions(&mut self) -> bool {
2071 let sessions_count = self.sessions.borrow().slab.len();
2072 let mut sessions_to_shut_down = HashSet::new();
2073
2074 for (_key, session) in &self.sessions.borrow().slab {
2075 let mut session = session.borrow_mut();
2076 if session.shutting_down() {
2077 debug!(
2078 "Server killing session from shutting_down: token={:?}, protocol={:?}",
2079 session.frontend_token(),
2080 session.protocol()
2081 );
2082 sessions_to_shut_down.insert(Token(session.frontend_token().0));
2083 }
2084 }
2085 let _ = self.shut_down_sessions_by_frontend_tokens(sessions_to_shut_down);
2086
2087 let new_sessions_count = self.sessions.borrow().slab.len();
2088
2089 if new_sessions_count < sessions_count {
2090 let now = Instant::now();
2091 if let Some(last) = self.last_shutting_down_message
2092 && (now - last) > Duration::from_secs(5)
2093 {
2094 info!(
2095 "closed {} sessions, {} sessions left, base_sessions_count = {}",
2096 sessions_count - new_sessions_count,
2097 new_sessions_count,
2098 self.base_sessions_count
2099 );
2100 }
2101 self.last_shutting_down_message = Some(now);
2102 }
2103
2104 if new_sessions_count <= self.base_sessions_count {
2105 info!("last session stopped, shutting down!");
2106 if let Err(e) = self.channel.run() {
2107 error!("Error while running the server channel: {}", e);
2108 }
2109 let id = self
2111 .shutting_down
2112 .take()
2113 .expect("should have shut down correctly"); debug!("Responding OK to main process for request {}", id);
2116
2117 let proxy_response = WorkerResponse::ok(id);
2118 if let Err(e) = self.channel.write_message(&proxy_response) {
2119 error!("Could not write response to the main process: {}", e);
2120 }
2121 if let Err(e) = self.channel.run() {
2122 error!("Error while running the server channel: {}", e);
2123 }
2124 return true;
2125 }
2126
2127 if new_sessions_count < self.last_sessions_len {
2128 info!(
2129 "shutting down, {} slab elements remaining (base: {})",
2130 new_sessions_count - self.base_sessions_count,
2131 self.base_sessions_count
2132 );
2133 self.last_sessions_len = new_sessions_count;
2134 }
2135
2136 false
2137 }
2138
2139 fn kill_session(&self, session: Rc<RefCell<dyn ProxySession>>) {
2140 let token = session.borrow().frontend_token();
2141 let _ = self.shut_down_sessions_by_frontend_tokens(HashSet::from([token]));
2142 }
2143
2144 fn send_queue(&mut self) {
2145 if self.channel.readiness.is_writable() {
2146 QUEUE.with(|q| {
2147 let mut queue = q.borrow_mut();
2148 loop {
2149 if let Some(resp) = queue.pop_front() {
2150 debug!("Sending response {:?}", resp);
2151 if let Err(e) = self.channel.write_message(&resp) {
2152 error!("Could not write message {} on the channel: {}", resp, e);
2153 queue.push_front(resp);
2154 }
2155 }
2156
2157 if self.channel.back_buf.available_data() > 0
2158 && let Err(e) = self.channel.writable()
2159 {
2160 error!("error writing to channel: {:?}", e);
2161 }
2162
2163 if !self.channel.readiness.is_writable() {
2164 break;
2165 }
2166
2167 if self.channel.back_buf.available_data() == 0 && queue.is_empty() {
2168 break;
2169 }
2170 }
2171 });
2172 }
2173 }
2174
2175 fn notify(&mut self, message: WorkerRequest) {
2176 let now = std::time::Instant::now();
2182 tick_metric_detail_leases(now);
2183 match &message.content.request_type {
2184 Some(RequestType::ConfigureMetrics(configuration)) => {
2185 match MetricsConfiguration::try_from(*configuration) {
2186 Ok(metrics_config) => {
2187 METRICS.with(|metrics| {
2188 (*metrics.borrow_mut()).configure(&metrics_config);
2189 push_queue(WorkerResponse::ok(message.id));
2190 });
2191 }
2192 Err(e) => {
2193 error!("Error configuring metrics: {}", e);
2194 push_queue(WorkerResponse::error(message.id, e));
2195 }
2196 }
2197 return;
2198 }
2199 Some(RequestType::QueryMetrics(query_metrics_options)) => {
2200 METRICS.with(|metrics| {
2201 match (*metrics.borrow_mut()).query(query_metrics_options) {
2202 Ok(c) => push_queue(WorkerResponse::ok_with_content(message.id, c)),
2203 Err(e) => {
2204 error!("Error querying metrics: {}", e);
2205 push_queue(WorkerResponse::error(message.id, e))
2206 }
2207 }
2208 });
2209 return;
2210 }
2211 Some(RequestType::SetMetricDetail(req)) => {
2219 let presented_binding = crate::metrics::PeerBinding {
2226 pid: req.peer_pid,
2227 session_ulid: req.peer_session_ulid.as_deref().and_then(|s| {
2233 rusty_ulid::Ulid::from_str(s)
2234 .map(u128::from)
2235 .ok()
2236 .or_else(|| u128::from_str_radix(s.trim_start_matches("0x"), 16).ok())
2237 }),
2238 };
2239 if req.clear.unwrap_or(false) {
2240 if req.client_id.len() > crate::metrics::LEASE_CLIENT_ID_MAX_BYTES {
2251 let msg = format!(
2252 "SetMetricDetail: clear client_id length {} exceeds {} bytes",
2253 req.client_id.len(),
2254 crate::metrics::LEASE_CLIENT_ID_MAX_BYTES,
2255 );
2256 error!("{}", msg);
2257 push_queue(WorkerResponse::error(message.id.clone(), msg));
2258 return;
2259 }
2260 let (outcome, effective_after, configured_after, lease_count_after) = METRICS
2268 .with(|metrics| {
2269 let mut m = metrics.borrow_mut();
2270 let outcome = m.lease_clear(&req.client_id, presented_binding);
2271 (
2272 outcome,
2273 m.detail_effective(),
2274 m.detail_configured(),
2275 m.lease_count(),
2276 )
2277 });
2278 match outcome {
2279 crate::metrics::LeaseClearOutcome::Cleared { previous_effective } => {
2280 push_metric_detail_transition(
2281 previous_effective,
2282 effective_after,
2283 "lease_clear",
2284 Some(req.client_id.clone()),
2285 );
2286 push_queue(WorkerResponse::ok_with_content(
2287 message.id.clone(),
2288 worker_metric_detail_status_content(
2289 configured_after,
2290 effective_after,
2291 previous_effective,
2292 lease_count_after,
2293 ),
2294 ));
2295 }
2296 crate::metrics::LeaseClearOutcome::NotFound => {
2297 push_queue(WorkerResponse::ok_with_content(
2301 message.id.clone(),
2302 worker_metric_detail_status_content(
2303 configured_after,
2304 effective_after,
2305 effective_after,
2306 lease_count_after,
2307 ),
2308 ));
2309 }
2310 crate::metrics::LeaseClearOutcome::Unauthorized => {
2311 let msg = "SetMetricDetail: clear refused (peer \
2322 binding does not match the apply-time owner)"
2323 .to_owned();
2324 error!("{}", msg);
2325 push_queue(WorkerResponse::error(message.id.clone(), msg));
2326 }
2327 }
2328 return;
2329 }
2330 let detail_proto = match req.detail {
2331 Some(d) => d,
2332 None => {
2333 let msg = "SetMetricDetail without `detail` and without `clear`".to_owned();
2340 error!("{}", msg);
2341 push_queue(WorkerResponse::error(message.id.clone(), msg));
2342 return;
2343 }
2344 };
2345 let detail_enum = match MetricDetail::try_from(detail_proto) {
2346 Ok(d) => d,
2347 Err(e) => {
2348 let msg =
2349 format!("SetMetricDetail: invalid MetricDetail variant {detail_proto}");
2350 error!("{}: {}", msg, e);
2351 push_queue(WorkerResponse::error(message.id.clone(), msg));
2352 return;
2353 }
2354 };
2355 let level = MetricDetailLevel::from(detail_enum);
2356 if let Some(t) = req.ttl_seconds
2365 && u64::from(t) > crate::metrics::LEASE_TTL_MAX.as_secs()
2366 {
2367 let msg = format!(
2368 "SetMetricDetail: ttl_seconds={t} exceeds LEASE_TTL_MAX={}",
2369 crate::metrics::LEASE_TTL_MAX.as_secs()
2370 );
2371 error!("{}", msg);
2372 push_queue(WorkerResponse::error(message.id.clone(), msg));
2373 return;
2374 }
2375 let ttl_seconds = req.ttl_seconds.filter(|&t| t > 0).unwrap_or_else(|| {
2376 u32::try_from(crate::metrics::LEASE_TTL_DEFAULT.as_secs()).unwrap_or(60)
2383 });
2384 let ttl = std::time::Duration::from_secs(ttl_seconds.into());
2385 let (outcome, configured_after, lease_count_after) = METRICS.with(|metrics| {
2386 let mut m = metrics.borrow_mut();
2387 let outcome =
2388 m.lease_apply(req.client_id.clone(), level, ttl, presented_binding, now);
2389 (outcome, m.detail_configured(), m.lease_count())
2390 });
2391 match outcome {
2392 crate::metrics::LeaseApplyOutcome::Applied {
2393 previous_effective,
2394 new_effective,
2395 } => {
2396 push_metric_detail_transition(
2397 previous_effective,
2398 new_effective,
2399 "lease_apply",
2400 Some(req.client_id.clone()),
2401 );
2402 push_queue(WorkerResponse::ok_with_content(
2403 message.id.clone(),
2404 worker_metric_detail_status_content(
2405 configured_after,
2406 new_effective,
2407 previous_effective,
2408 lease_count_after,
2409 ),
2410 ));
2411 }
2412 crate::metrics::LeaseApplyOutcome::ClientIdTooLong => {
2413 let msg = format!(
2414 "SetMetricDetail: client_id length {} exceeds {} bytes",
2415 req.client_id.len(),
2416 crate::metrics::LEASE_CLIENT_ID_MAX_BYTES,
2417 );
2418 error!("{}", msg);
2419 push_queue(WorkerResponse::error(message.id.clone(), msg));
2420 }
2421 crate::metrics::LeaseApplyOutcome::TableFull => {
2422 let msg = format!(
2429 "SetMetricDetail: lease table at capacity ({} entries); reject new \
2430 apply — operators must retry after an active lease expires or is \
2431 cleared",
2432 crate::metrics::LEASE_TABLE_CAP,
2433 );
2434 error!("{}", msg);
2435 push_queue(WorkerResponse::error(message.id.clone(), msg));
2436 }
2437 crate::metrics::LeaseApplyOutcome::TtlOutOfRange => {
2438 let msg = format!(
2444 "SetMetricDetail: ttl exceeds LEASE_TTL_MAX={} (internal contract \
2445 violation: dispatch gate should have rejected)",
2446 crate::metrics::LEASE_TTL_MAX.as_secs(),
2447 );
2448 error!("{}", msg);
2449 push_queue(WorkerResponse::error(message.id.clone(), msg));
2450 }
2451 crate::metrics::LeaseApplyOutcome::Unauthorized => {
2452 let msg = "SetMetricDetail: renewal refused (peer binding does not \
2461 match the apply-time owner)"
2462 .to_owned();
2463 error!("{}", msg);
2464 push_queue(WorkerResponse::error(message.id.clone(), msg));
2465 }
2466 }
2467 return;
2468 }
2469 Some(RequestType::Logging(logging_filter)) => {
2470 info!(
2471 "{} changing logging filter to {}",
2472 message.id, logging_filter
2473 );
2474 let (directives, _errors) = logging::parse_logging_spec(logging_filter);
2476 logging::LOGGER.with(|logger| {
2477 logger.borrow_mut().set_directives(directives);
2478 });
2479 push_queue(WorkerResponse::ok(message.id));
2480 return;
2481 }
2482 Some(RequestType::QueryClustersHashes(_)) => {
2483 push_queue(WorkerResponse::ok_with_content(
2484 message.id.clone(),
2485 ContentType::ClusterHashes(ClusterHashes {
2486 map: self
2487 .config_state
2488 .hash_state()
2489 .into_iter()
2490 .map(|(cluster_id, hash)| (cluster_id.to_string(), hash))
2491 .collect(),
2492 })
2493 .into(),
2494 ));
2495 return;
2496 }
2497 Some(RequestType::QueryClusterById(cluster_id)) => {
2498 push_queue(WorkerResponse::ok_with_content(
2499 message.id.clone(),
2500 ContentType::Clusters(ClusterInformations {
2501 vec: self
2502 .config_state
2503 .cluster_state(cluster_id)
2504 .map_or(vec![], |ci| vec![ci]),
2505 })
2506 .into(),
2507 ));
2508 }
2509 Some(RequestType::SetMaxConnectionsPerIp(limit)) => {
2510 let mut sessions = self.sessions.borrow_mut();
2511 let previous = sessions.max_connections_per_ip;
2512 sessions.max_connections_per_ip = *limit;
2513 if *limit == 0 {
2518 sessions.clear_cluster_ip_tracking();
2519 }
2520 info!(
2521 "{} updated global max_connections_per_ip from {} to {}",
2522 message.id, previous, limit
2523 );
2524 push_queue(WorkerResponse::ok(message.id));
2525 return;
2526 }
2527 Some(RequestType::QueryMaxConnectionsPerIp(_)) => {
2528 let limit = self.sessions.borrow().max_connections_per_ip;
2529 push_queue(WorkerResponse::ok_with_content(
2530 message.id,
2531 ContentType::MaxConnectionsPerIpLimit(
2532 sozu_command::proto::command::MaxConnectionsPerIpLimit { limit },
2533 )
2534 .into(),
2535 ));
2536 return;
2537 }
2538 Some(RequestType::SetMaxConnectionsPerSubnet(limit)) => {
2539 let mut sessions = self.sessions.borrow_mut();
2540 let previous = sessions.max_connections_per_subnet;
2541 sessions.max_connections_per_subnet = *limit;
2542 if *limit == 0 {
2548 sessions.clear_cluster_subnet_tracking();
2549 }
2550 info!(
2551 "{} updated global max_connections_per_subnet from {} to {}",
2552 message.id, previous, limit
2553 );
2554 push_queue(WorkerResponse::ok(message.id));
2555 return;
2556 }
2557 Some(RequestType::SetMaxConnectionAttempts(attempts)) => {
2558 if let Err(reason) =
2559 sozu_command::config::validate_max_connection_attempts(*attempts)
2560 {
2561 push_queue(WorkerResponse::error(message.id, reason));
2562 return;
2563 }
2564 let mut sessions = self.sessions.borrow_mut();
2565 let previous = sessions.max_connection_attempts;
2566 sessions.max_connection_attempts = *attempts;
2567 info!(
2568 "{} updated global max_connection_attempts from {} to {}",
2569 message.id, previous, attempts
2570 );
2571 push_queue(WorkerResponse::ok(message.id));
2572 return;
2573 }
2574 Some(RequestType::QueryMaxConnectionsPerSubnet(_)) => {
2575 let sessions = self.sessions.borrow();
2576 let limit = sessions.max_connections_per_subnet;
2577 let ipv4_prefix = sessions.subnet_ipv4_prefix;
2581 let ipv6_prefix = sessions.subnet_ipv6_prefix;
2582 drop(sessions);
2583 push_queue(WorkerResponse::ok_with_content(
2584 message.id,
2585 ContentType::MaxConnectionsPerSubnetLimit(
2586 sozu_command::proto::command::MaxConnectionsPerSubnetLimit {
2587 limit,
2588 ipv4_prefix,
2589 ipv6_prefix,
2590 },
2591 )
2592 .into(),
2593 ));
2594 return;
2595 }
2596 Some(RequestType::QueryClustersByDomain(domain)) => {
2597 let cluster_ids = self
2598 .config_state
2599 .get_cluster_ids_by_domain(domain.hostname.clone(), domain.path.clone());
2600 let vec = cluster_ids
2601 .iter()
2602 .filter_map(|cluster_id| self.config_state.cluster_state(cluster_id))
2603 .collect();
2604
2605 push_queue(WorkerResponse::ok_with_content(
2606 message.id.clone(),
2607 ContentType::Clusters(ClusterInformations { vec }).into(),
2608 ));
2609 return;
2610 }
2611 Some(RequestType::QueryCertificatesFromWorkers(filters))
2622 if filters.fingerprint.is_some() =>
2623 {
2624 let certs = self.config_state.get_certificates(filters.clone());
2625 let response = if !certs.is_empty() {
2626 WorkerResponse::ok_with_content(
2627 message.id.clone(),
2628 ContentType::CertificatesWithFingerprints(CertificatesWithFingerprints {
2629 certs,
2630 })
2631 .into(),
2632 )
2633 } else {
2634 worker_response_error(
2635 message.id.clone(),
2636 "Could not find certificate for this fingerprint",
2637 )
2638 };
2639 push_queue(response);
2640 return;
2641 }
2642 _other_request => {}
2645 }
2646 self.notify_proxys(message);
2647 }
2648
2649 pub fn notify_proxys(&mut self, request: WorkerRequest) {
2650 let cluster_objects = match &request.content.request_type {
2654 Some(RequestType::RemoveCluster(cluster_id)) => {
2655 self.config_state.cluster_removal_requests(cluster_id)
2656 }
2657 _ => Vec::new(),
2658 };
2659
2660 if let Err(e) = self.config_state.dispatch(&request.content) {
2661 if self
2662 .config_state
2663 .removed_with_its_cluster(&request.content, &e)
2664 {
2665 debug!("{} already removed with its cluster: {}", request.id, e);
2671 push_queue(WorkerResponse::ok(request.id));
2672 return;
2673 }
2674 if is_frontend_removal(&request.content)
2675 && matches!(e, StateError::NotFound { .. } | StateError::NoChange)
2676 {
2677 push_queue(WorkerResponse::error(
2687 request.id,
2688 format!("Could not execute order on config state: {e}"),
2689 ));
2690 return;
2691 }
2692 error!("Could not execute order on config state: {}", e);
2693 }
2694
2695 let req_id = request.id.clone();
2696
2697 match request.content.request_type {
2698 Some(RequestType::AddCluster(ref cluster)) => {
2699 if let Some(hc) = cluster.health_check.as_ref()
2707 && let Err(reason) = sozu_command::config::validate_health_check_config(hc)
2708 {
2709 push_queue(worker_response_error(req_id, reason));
2710 return;
2711 }
2712 if let Err(reason) = sozu_command::config::validate_shuffle_sharding(
2715 cluster.shard_percent,
2716 cluster.shard_min_backends,
2717 cluster.shard_mode,
2718 ) {
2719 push_queue(worker_response_error(req_id, reason));
2720 return;
2721 }
2722 if let Some(Err(reason)) = cluster
2723 .max_connection_attempts
2724 .map(sozu_command::config::validate_max_connection_attempts)
2725 {
2726 push_queue(worker_response_error(req_id, reason));
2727 return;
2728 }
2729 self.add_cluster(cluster);
2730 if cluster.health_check.is_none() {
2734 self.health_checker.remove_cluster(&cluster.cluster_id);
2735 }
2736 METRICS.with(|metrics| {
2741 (*metrics.borrow_mut()).add_cluster(&cluster.cluster_id);
2742 });
2743 }
2745 Some(RequestType::RemoveCluster(ref cluster_id)) => {
2746 self.remove_cluster_objects(&req_id, cluster_id, cluster_objects);
2747 self.remove_health_check_state(cluster_id);
2748 METRICS.with(|metrics| {
2749 (*metrics.borrow_mut()).remove_cluster(cluster_id);
2750 });
2751 }
2753 Some(RequestType::SetHealthCheck(ref set)) => {
2754 if let Err(reason) = sozu_command::config::validate_health_check_config(&set.config)
2755 {
2756 push_queue(worker_response_error(req_id, reason));
2757 return;
2758 }
2759 self.backends
2760 .borrow_mut()
2761 .set_health_check_config(&set.cluster_id, Some(set.config.to_owned()));
2762 push_queue(WorkerResponse::ok(req_id));
2763 return;
2764 }
2765 Some(RequestType::RemoveHealthCheck(ref cluster_id)) => {
2766 self.remove_health_check_state(cluster_id);
2767 push_queue(WorkerResponse::ok(req_id));
2768 return;
2769 }
2770 Some(RequestType::AddBackend(ref backend)) => {
2771 push_queue(self.add_backend(&req_id, backend));
2772 return;
2773 }
2774 Some(RequestType::RemoveBackend(ref remove_backend)) => {
2775 push_queue(self.remove_backend(&req_id, remove_backend));
2776 return;
2777 }
2778 _ => {}
2779 };
2780
2781 let proxy_destinations = request.content.get_destinations();
2782 let mut notify_response = None;
2783 if proxy_destinations.to_http_proxy {
2784 notify_response = Some(self.http.borrow_mut().notify(request.clone()));
2785 }
2786 if proxy_destinations.to_https_proxy {
2787 let http_proxy_response = self.https.borrow_mut().notify(request.clone());
2788 if http_proxy_response.is_failure() || notify_response.is_none() {
2789 notify_response = Some(http_proxy_response);
2790 }
2791 }
2792 if proxy_destinations.to_tcp_proxy {
2793 let tcp_proxy_response = self.tcp.borrow_mut().notify(request.clone());
2794 if tcp_proxy_response.is_failure() || notify_response.is_none() {
2795 notify_response = Some(tcp_proxy_response);
2796 }
2797 }
2798 if proxy_destinations.to_udp_proxy {
2799 let udp_proxy_response = self.udp.borrow_mut().notify(request.clone());
2800 if udp_proxy_response.is_failure() || notify_response.is_none() {
2801 notify_response = Some(udp_proxy_response);
2802 }
2803 }
2804 if let Some(response) = notify_response {
2805 push_queue(response);
2806 }
2807
2808 match request.content.request_type {
2809 Some(RequestType::AddHttpListener(listener)) => {
2811 push_queue(self.notify_add_http_listener(&req_id, listener));
2812 }
2813 Some(
2814 RequestType::AddHttpsListener(listener)
2815 | RequestType::AddHttpsListenerWithClientAuth(listener),
2816 ) => {
2817 push_queue(self.notify_add_https_listener(&req_id, listener));
2818 }
2819 Some(RequestType::AddTcpListener(listener)) => {
2820 push_queue(self.notify_add_tcp_listener(&req_id, listener));
2821 }
2822 Some(RequestType::AddUdpListener(listener)) => {
2823 push_queue(self.notify_add_udp_listener(&req_id, listener));
2824 }
2825 Some(RequestType::UpdateHttpListener(patch)) => {
2826 push_queue(self.notify_update_http_listener(&req_id, patch));
2827 }
2828 Some(
2829 RequestType::UpdateHttpsListener(patch)
2830 | RequestType::UpdateHttpsListenerWithClientAuth(patch),
2831 ) => {
2832 push_queue(self.notify_update_https_listener(&req_id, patch));
2833 }
2834 Some(RequestType::UpdateTcpListener(patch)) => {
2835 push_queue(self.notify_update_tcp_listener(&req_id, patch));
2836 }
2837 Some(RequestType::UpdateUdpListener(patch)) => {
2838 push_queue(self.notify_update_udp_listener(&req_id, patch));
2839 }
2840 Some(RequestType::RemoveListener(ref remove)) => {
2841 debug!("{} remove {:?} listener {:?}", req_id, remove.proxy, remove);
2842 debug_assert!(
2845 self.base_sessions_count > 0,
2846 "removing a listener with base_sessions_count == 0 would underflow"
2847 );
2848 self.base_sessions_count -= 1;
2849 let listener_type = ListenerType::try_from(remove.proxy);
2850 let address = remove.listener_key();
2858 let listen_token = match listener_type {
2859 Ok(ListenerType::Http) => self.http.borrow().listener_token(&address),
2860 Ok(ListenerType::Https) => self.https.borrow().listener_token(&address),
2861 Ok(ListenerType::Tcp) => self.tcp.borrow().listener_token(&address),
2862 Ok(ListenerType::Udp) => self.udp.borrow().listener_token(&address),
2863 Err(_) => None,
2864 };
2865 let response = match listener_type {
2866 Ok(ListenerType::Http) => self.http.borrow_mut().notify(request),
2867 Ok(ListenerType::Https) => self.https.borrow_mut().notify(request),
2868 Ok(ListenerType::Tcp) => self.tcp.borrow_mut().notify(request),
2869 Ok(ListenerType::Udp) => self.udp.borrow_mut().notify(request),
2870 Err(_) => WorkerResponse::error(req_id, "Wrong variant ListenerType"),
2871 };
2872 if let Some(token) = listen_token {
2873 self.sessions.borrow_mut().slab.try_remove(token.0);
2874 self.accept_ready.remove(&ListenToken(token.0));
2877 info!("released listen token {:?}", token);
2878 }
2879 push_queue(response);
2880 }
2881 Some(RequestType::ActivateListener(ref activate)) => {
2882 push_queue(self.notify_activate_listener(&req_id, activate));
2883 }
2884 Some(RequestType::DeactivateListener(ref deactivate)) => {
2885 push_queue(self.notify_deactivate_listener(&req_id, deactivate));
2886 }
2887 _other_request => {}
2888 };
2889 }
2890
2891 fn add_cluster(&mut self, cluster: &Cluster) {
2892 let mut backends = self.backends.borrow_mut();
2893 backends.set_load_balancing_policy_for_cluster(
2894 &cluster.cluster_id,
2895 LoadBalancingAlgorithms::try_from(cluster.load_balancing).unwrap_or_default(),
2896 cluster
2897 .load_metric
2898 .and_then(|n| LoadMetric::try_from(n).ok()),
2899 );
2900 backends.set_shuffle_sharding_for_cluster(
2901 &cluster.cluster_id,
2902 ShuffleSharding::from_cluster(
2903 cluster.shard_percent,
2904 cluster.shard_min_backends,
2905 cluster.shard_mode,
2906 ),
2907 );
2908 backends.set_health_check_config(&cluster.cluster_id, cluster.health_check.to_owned());
2909 backends.set_cluster_http2(&cluster.cluster_id, cluster.http2.unwrap_or(false));
2910 }
2911
2912 fn add_backend(&mut self, req_id: &str, add_backend: &AddBackend) -> WorkerResponse {
2913 let new_backend = Backend::new(
2914 &add_backend.backend_id,
2915 add_backend.address.into(),
2916 add_backend.sticky_id.clone(),
2917 add_backend.load_balancing_parameters,
2918 add_backend.backup,
2919 );
2920 self.backends
2921 .borrow_mut()
2922 .add_backend(&add_backend.cluster_id, new_backend);
2923
2924 WorkerResponse::ok(req_id)
2925 }
2926
2927 fn remove_cluster_objects(&mut self, req_id: &str, cluster_id: &str, requests: Vec<Request>) {
2939 for request in requests {
2940 let result = match request.request_type {
2941 Some(RequestType::RemoveHttpFrontend(front)) => {
2942 self.http.borrow_mut().remove_http_frontend(front)
2943 }
2944 Some(RequestType::RemoveHttpsFrontend(front)) => self
2945 .https
2946 .borrow_mut()
2947 .remove_https_frontend(front)
2948 .map(|_| ()),
2949 Some(RequestType::RemoveTcpFrontend(front)) => {
2950 self.tcp.borrow_mut().remove_tcp_front(front)
2951 }
2952 Some(RequestType::RemoveUdpFrontend(front)) => {
2953 self.udp.borrow_mut().remove_udp_front(front)
2954 }
2955 Some(RequestType::RemoveBackend(backend)) => {
2956 let response = self.remove_backend(req_id, &backend);
2957 debug_assert_eq!(
2958 response.status,
2959 ResponseStatus::Ok as i32,
2960 "Server::remove_backend always answers ok"
2961 );
2962 Ok(())
2963 }
2964 other => {
2965 debug_assert!(
2966 false,
2967 "cluster_removal_requests only returns frontend and backend removals, got {other:?}"
2968 );
2969 Ok(())
2970 }
2971 };
2972 if let Err(error) = result {
2973 warn!(
2974 "{} removing cluster {}: could not remove one of its objects: {}",
2975 req_id, cluster_id, error
2976 );
2977 }
2978 }
2979 self.backends.borrow_mut().remove_cluster(cluster_id);
2980 debug_assert!(
2981 !self.backends.borrow().backends.contains_key(cluster_id),
2982 "a removed cluster must leave no backend list behind"
2983 );
2984 }
2985
2986 fn remove_health_check_state(&mut self, cluster_id: &str) {
2991 self.health_checker.remove_cluster(cluster_id);
2992 self.backends
2993 .borrow_mut()
2994 .set_health_check_config(cluster_id, None);
2995 }
2996
2997 fn remove_backend(&mut self, req_id: &str, backend: &RemoveBackend) -> WorkerResponse {
2998 let address = backend.address.into();
2999 let id_still_live = {
3006 let mut backends = self.backends.borrow_mut();
3007 backends.remove_backend(&backend.cluster_id, &backend.backend_id, &address);
3008 backends.has_backend_id(&backend.cluster_id, &backend.backend_id)
3009 };
3010 if !id_still_live {
3011 METRICS.with(|metrics| {
3012 (*metrics.borrow_mut()).remove_backend(&backend.cluster_id, &backend.backend_id);
3013 });
3014 }
3015
3016 WorkerResponse::ok(req_id)
3017 }
3018
3019 fn notify_add_http_listener(
3020 &mut self,
3021 req_id: &str,
3022 listener: HttpListenerConfig,
3023 ) -> WorkerResponse {
3024 debug!("{} add http listener {:?}", req_id, listener);
3025
3026 if self.sessions.borrow().at_capacity() {
3027 return worker_response_error(req_id, "session list is full, cannot add a listener");
3028 }
3029
3030 let mut session_manager = self.sessions.borrow_mut();
3031 let slab_before = session_manager.slab.len();
3033 debug_assert!(
3034 !session_manager
3035 .slab
3036 .contains(session_manager.slab.vacant_key()),
3037 "the next vacant slab key must be free before insertion"
3038 );
3039 let entry = session_manager.slab.vacant_entry();
3040 let token = Token(entry.key());
3041
3042 match self.http.borrow_mut().add_listener(listener, token) {
3043 Ok(_token) => {
3044 entry.insert(Rc::new(RefCell::new(ListenSession {
3045 protocol: Protocol::HTTPListen,
3046 })));
3047 debug_assert!(
3050 session_manager.slab.contains(token.0),
3051 "listener insert must occupy the token's slab key"
3052 );
3053 debug_assert_eq!(
3054 session_manager.slab.len(),
3055 slab_before + 1,
3056 "adding a listener must occupy exactly one slab slot"
3057 );
3058 self.base_sessions_count += 1;
3059 WorkerResponse::ok(req_id)
3060 }
3061 Err(e) => worker_response_error(req_id, format!("Could not add HTTP listener: {e}")),
3062 }
3063 }
3064
3065 fn notify_add_https_listener(
3066 &mut self,
3067 req_id: &str,
3068 listener: HttpsListenerConfig,
3069 ) -> WorkerResponse {
3070 debug!("{} add https listener {:?}", req_id, listener);
3071
3072 if self.sessions.borrow().at_capacity() {
3073 return worker_response_error(req_id, "session list is full, cannot add a listener");
3074 }
3075
3076 let mut session_manager = self.sessions.borrow_mut();
3077 let slab_before = session_manager.slab.len();
3078 debug_assert!(
3079 !session_manager
3080 .slab
3081 .contains(session_manager.slab.vacant_key()),
3082 "the next vacant slab key must be free before insertion"
3083 );
3084 let entry = session_manager.slab.vacant_entry();
3085 let token = Token(entry.key());
3086
3087 match self
3088 .https
3089 .borrow_mut()
3090 .add_listener(listener.clone(), token)
3091 {
3092 Ok(_token) => {
3093 entry.insert(Rc::new(RefCell::new(ListenSession {
3094 protocol: Protocol::HTTPSListen,
3095 })));
3096 debug_assert!(
3097 session_manager.slab.contains(token.0),
3098 "listener insert must occupy the token's slab key"
3099 );
3100 debug_assert_eq!(
3101 session_manager.slab.len(),
3102 slab_before + 1,
3103 "adding a listener must occupy exactly one slab slot"
3104 );
3105 self.base_sessions_count += 1;
3106 WorkerResponse::ok(req_id)
3107 }
3108 Err(e) => worker_response_error(req_id, format!("Could not add HTTPS listener: {e}")),
3109 }
3110 }
3111
3112 fn notify_add_tcp_listener(
3113 &mut self,
3114 req_id: &str,
3115 listener: CommandTcpListener,
3116 ) -> WorkerResponse {
3117 debug!("{} add tcp listener {:?}", req_id, listener);
3118
3119 if self.sessions.borrow().at_capacity() {
3120 return worker_response_error(req_id, "session list is full, cannot add a listener");
3121 }
3122
3123 let mut session_manager = self.sessions.borrow_mut();
3124 let slab_before = session_manager.slab.len();
3125 debug_assert!(
3126 !session_manager
3127 .slab
3128 .contains(session_manager.slab.vacant_key()),
3129 "the next vacant slab key must be free before insertion"
3130 );
3131 let entry = session_manager.slab.vacant_entry();
3132 let token = Token(entry.key());
3133
3134 match self.tcp.borrow_mut().add_listener(listener, token) {
3135 Ok(_token) => {
3136 entry.insert(Rc::new(RefCell::new(ListenSession {
3137 protocol: Protocol::TCPListen,
3138 })));
3139 debug_assert!(
3140 session_manager.slab.contains(token.0),
3141 "listener insert must occupy the token's slab key"
3142 );
3143 debug_assert_eq!(
3144 session_manager.slab.len(),
3145 slab_before + 1,
3146 "adding a listener must occupy exactly one slab slot"
3147 );
3148 self.base_sessions_count += 1;
3149 WorkerResponse::ok(req_id)
3150 }
3151 Err(e) => worker_response_error(req_id, format!("Could not add TCP listener: {e}")),
3152 }
3153 }
3154
3155 fn notify_add_udp_listener(
3156 &mut self,
3157 req_id: &str,
3158 listener: CommandUdpListener,
3159 ) -> WorkerResponse {
3160 debug!("{} add udp listener {:?}", req_id, listener);
3161
3162 if self.sessions.borrow().at_capacity() {
3163 return worker_response_error(req_id, "session list is full, cannot add a listener");
3164 }
3165
3166 let mut session_manager = self.sessions.borrow_mut();
3167 let entry = session_manager.slab.vacant_entry();
3168 let token = Token(entry.key());
3169
3170 match self.udp.borrow_mut().add_listener(listener, token) {
3171 Ok(_token) => {
3172 entry.insert(Rc::new(RefCell::new(ListenSession {
3173 protocol: Protocol::UDPListen,
3174 })));
3175 self.base_sessions_count += 1;
3176 WorkerResponse::ok(req_id)
3177 }
3178 Err(e) => worker_response_error(req_id, format!("Could not add UDP listener: {e}")),
3179 }
3180 }
3181
3182 fn notify_update_udp_listener(
3183 &mut self,
3184 req_id: &str,
3185 patch: UpdateUdpListenerConfig,
3186 ) -> WorkerResponse {
3187 debug!("{} update udp listener {:?}", req_id, patch.address);
3188 match self.udp.borrow_mut().update_listener(patch) {
3189 Ok(()) => WorkerResponse::ok(req_id),
3190 Err(e) => worker_response_error(req_id, format!("Could not update UDP listener: {e}")),
3191 }
3192 }
3193
3194 fn notify_update_http_listener(
3195 &mut self,
3196 req_id: &str,
3197 patch: UpdateHttpListenerConfig,
3198 ) -> WorkerResponse {
3199 debug!("{} update http listener {:?}", req_id, patch.address);
3200 match self.http.borrow_mut().update_listener(patch) {
3201 Ok(()) => WorkerResponse::ok(req_id),
3202 Err(e) => worker_response_error(req_id, format!("Could not update HTTP listener: {e}")),
3203 }
3204 }
3205
3206 fn notify_update_https_listener(
3207 &mut self,
3208 req_id: &str,
3209 patch: UpdateHttpsListenerConfig,
3210 ) -> WorkerResponse {
3211 debug!("{} update https listener {:?}", req_id, patch.address);
3212 match self.https.borrow_mut().update_listener(patch) {
3213 Ok(()) => WorkerResponse::ok(req_id),
3214 Err(e) => {
3215 worker_response_error(req_id, format!("Could not update HTTPS listener: {e}"))
3216 }
3217 }
3218 }
3219
3220 fn notify_update_tcp_listener(
3221 &mut self,
3222 req_id: &str,
3223 patch: UpdateTcpListenerConfig,
3224 ) -> WorkerResponse {
3225 debug!("{} update tcp listener {:?}", req_id, patch.address);
3226 match self.tcp.borrow_mut().update_listener(patch) {
3227 Ok(()) => WorkerResponse::ok(req_id),
3228 Err(e) => worker_response_error(req_id, format!("Could not update TCP listener: {e}")),
3229 }
3230 }
3231
3232 fn reserve_listen_token(&mut self, token: Token, protocol: Protocol) {
3267 let mut sessions = self.sessions.borrow_mut();
3268 match sessions.slab.get_mut(token.0) {
3269 Some(slot) => {
3270 *slot = Rc::new(RefCell::new(ListenSession { protocol }));
3271 info!("reserved listen token {:?} for {:?}", token, protocol);
3272 }
3273 None => error!(
3277 "listen token {:?} ({:?}) has no slab slot to reserve; the listener would not be reachable if reactivated",
3278 token, protocol
3279 ),
3280 }
3281 }
3282
3283 fn report_unclaimed_inherited_sockets(&self) {
3303 let Some(scm_listeners) = self.scm_listeners.as_ref() else {
3304 return;
3305 };
3306 let leftovers: [(&str, &Vec<(ListenerKey, RawFd)>); 4] = [
3307 ("HTTP", &scm_listeners.http),
3308 ("HTTPS", &scm_listeners.tls),
3309 ("TCP", &scm_listeners.tcp),
3310 ("UDP", &scm_listeners.udp),
3311 ];
3312 for (label, table) in leftovers {
3313 for (address, fd) in table {
3314 let has_listener = match label {
3315 "HTTP" => self.http.borrow().listener_token(address).is_some(),
3316 "HTTPS" => self.https.borrow().listener_token(address).is_some(),
3317 "TCP" => self.tcp.borrow().listener_token(address).is_some(),
3318 _ => self.udp.borrow().listener_token(address).is_some(),
3319 };
3320 if has_listener {
3321 info!(
3322 "inherited {} listening socket for {} (fd {}) is held for an \
3323 ActivateListener this worker has not processed yet",
3324 label, address, fd
3325 );
3326 } else {
3327 warn!(
3328 "inherited {} listening socket for {} (fd {}) is held with no listener \
3329 at that address: until an AddListener plus ActivateListener for {} \
3330 adopts it, it is expected to keep taking a share of new connections \
3331 that nothing accepts (inferred from SO_REUSEPORT semantics, not \
3332 measured here)",
3333 label, address, fd, address
3334 );
3335 }
3336 }
3337 }
3338 }
3339
3340 fn notify_activate_listener(
3341 &mut self,
3342 req_id: &str,
3343 activate: &ActivateListener,
3344 ) -> WorkerResponse {
3345 use crate::InheritedSocketFate;
3346
3347 debug!(
3348 "{} activate {:?} listener {:?}",
3349 req_id, activate.proxy, activate
3350 );
3351
3352 let address = activate.listener_key();
3353
3354 match ListenerType::try_from(activate.proxy) {
3355 Ok(ListenerType::Http) => {
3356 let listener = match self.http.borrow().inherited_socket_fate(&address) {
3357 InheritedSocketFate::Adopted => self
3358 .scm_listeners
3359 .as_mut()
3360 .and_then(|listeners| listeners.get_http(&address))
3361 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) }),
3366 InheritedSocketFate::Refused => {
3367 discard_inherited_socket::<MioTcpListener>(
3368 self.scm_listeners
3369 .as_mut()
3370 .and_then(|listeners| listeners.get_http(&address)),
3371 &address,
3372 "HTTP",
3373 );
3374 None
3375 }
3376 InheritedSocketFate::Unclaimed => None,
3379 };
3380
3381 let activated_token = self.http.borrow_mut().activate_listener(&address, listener);
3382 match activated_token {
3383 Ok(token) => {
3384 self.accept(ListenToken(token.0), Protocol::HTTPListen);
3385 WorkerResponse::ok(req_id)
3386 }
3387 Err(activate_error) => worker_response_error(
3388 req_id,
3389 format!("Could not activate HTTP listener: {activate_error}"),
3390 ),
3391 }
3392 }
3393 Ok(ListenerType::Https) => {
3394 let listener = match self.https.borrow().inherited_socket_fate(&address) {
3395 InheritedSocketFate::Adopted => self
3396 .scm_listeners
3397 .as_mut()
3398 .and_then(|listeners| listeners.get_https(&address))
3399 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) }),
3404 InheritedSocketFate::Refused => {
3405 discard_inherited_socket::<MioTcpListener>(
3406 self.scm_listeners
3407 .as_mut()
3408 .and_then(|listeners| listeners.get_https(&address)),
3409 &address,
3410 "HTTPS",
3411 );
3412 None
3413 }
3414 InheritedSocketFate::Unclaimed => None,
3417 };
3418
3419 let activated_token = self
3420 .https
3421 .borrow_mut()
3422 .activate_listener(&address, listener);
3423 match activated_token {
3424 Ok(token) => {
3425 self.accept(ListenToken(token.0), Protocol::HTTPSListen);
3426 WorkerResponse::ok(req_id)
3427 }
3428 Err(activate_error) => worker_response_error(
3429 req_id,
3430 format!("Could not activate HTTPS listener: {activate_error}"),
3431 ),
3432 }
3433 }
3434 Ok(ListenerType::Tcp) => {
3435 let listener = match self.tcp.borrow().inherited_socket_fate(&address) {
3436 InheritedSocketFate::Adopted => self
3437 .scm_listeners
3438 .as_mut()
3439 .and_then(|listeners| listeners.get_tcp(&address))
3440 .map(|fd| unsafe { MioTcpListener::from_raw_fd(fd) }),
3445 InheritedSocketFate::Refused => {
3446 discard_inherited_socket::<MioTcpListener>(
3447 self.scm_listeners
3448 .as_mut()
3449 .and_then(|listeners| listeners.get_tcp(&address)),
3450 &address,
3451 "TCP",
3452 );
3453 None
3454 }
3455 InheritedSocketFate::Unclaimed => None,
3458 };
3459
3460 let listener_token = self.tcp.borrow_mut().activate_listener(&address, listener);
3461 match listener_token {
3462 Ok(token) => {
3463 self.accept(ListenToken(token.0), Protocol::TCPListen);
3464 WorkerResponse::ok(req_id)
3465 }
3466 Err(activate_error) => worker_response_error(
3467 req_id,
3468 format!("Could not activate TCP listener: {activate_error}"),
3469 ),
3470 }
3471 }
3472 Ok(ListenerType::Udp) => {
3473 let socket = match self.udp.borrow().inherited_socket_fate(&address) {
3474 InheritedSocketFate::Adopted => self
3475 .scm_listeners
3476 .as_mut()
3477 .and_then(|listeners| listeners.get_udp(&address))
3478 .map(|fd| unsafe { MioUdpSocket::from_raw_fd(fd) }),
3486 InheritedSocketFate::Refused => {
3487 discard_inherited_socket::<MioUdpSocket>(
3488 self.scm_listeners
3489 .as_mut()
3490 .and_then(|listeners| listeners.get_udp(&address)),
3491 &address,
3492 "UDP",
3493 );
3494 None
3495 }
3496 InheritedSocketFate::Unclaimed => None,
3499 };
3500
3501 let activated_token = self.udp.borrow_mut().activate_listener(&address, socket);
3502 match activated_token {
3503 Ok(token) => {
3504 let session_installed = self.udp.borrow().has_listener_session(token)
3554 && self.sessions.borrow().slab.contains(token.0);
3555 if !session_installed {
3556 let session = match self.udp.borrow_mut().build_session(token) {
3563 Some(session) => session,
3564 None => {
3565 return worker_response_error(
3566 req_id,
3567 format!(
3568 "Could not build the UDP listener session for {address}"
3569 ),
3570 );
3571 }
3572 };
3573 let mut sessions = self.sessions.borrow_mut();
3574 match sessions.slab.get_mut(token.0) {
3575 Some(slot) => *slot = session,
3576 None => {
3577 return worker_response_error(
3578 req_id,
3579 format!(
3580 "UDP listener {address} has no session slot at {token:?}"
3581 ),
3582 );
3583 }
3584 }
3585 }
3586 WorkerResponse::ok(req_id)
3587 }
3588 Err(activate_error) => worker_response_error(
3589 req_id,
3590 format!("Could not activate UDP listener: {activate_error}"),
3591 ),
3592 }
3593 }
3594 Err(_) => worker_response_error(req_id, "Wrong variant for ListenerType on request"),
3595 }
3596 }
3597
3598 fn notify_deactivate_listener(
3599 &mut self,
3600 req_id: &str,
3601 deactivate: &DeactivateListener,
3602 ) -> WorkerResponse {
3603 debug!(
3604 "{} deactivate {:?} listener {:?}",
3605 req_id, deactivate.proxy, deactivate
3606 );
3607
3608 let address = deactivate.listener_key();
3609
3610 match ListenerType::try_from(deactivate.proxy) {
3611 Ok(ListenerType::Http) => {
3612 let (token, mut listener) =
3613 match self.http.borrow_mut().give_back_listener(&address) {
3614 Ok((token, listener)) => (token, listener),
3615 Err(e) => {
3616 return worker_response_error(
3617 req_id,
3618 format!("Couldn't deactivate HTTP listener at {address}: {e}"),
3619 );
3620 }
3621 };
3622
3623 if let Err(e) = self.poll.registry().deregister(&mut listener) {
3624 error!(
3625 "error deregistering HTTP listen socket({:?}): {:?}",
3626 deactivate, e
3627 );
3628 }
3629
3630 self.reserve_listen_token(token, Protocol::HTTPListen);
3635 self.accept_ready.remove(&ListenToken(token.0));
3641
3642 if deactivate.to_scm {
3643 self.unblock_scm_socket();
3644 let listeners = Listeners {
3645 http: vec![(address.clone(), listener.as_raw_fd())],
3646 tls: vec![],
3647 tcp: vec![],
3648 udp: vec![],
3649 };
3650 info!("sending HTTP listener: {:?}", listeners);
3651 let res = self.scm.send_listeners(&listeners);
3652
3653 self.block_scm_socket();
3654
3655 info!("sent HTTP listener: {:?}", res);
3656 }
3657 WorkerResponse::ok(req_id)
3658 }
3659 Ok(ListenerType::Https) => {
3660 let (token, mut listener) =
3661 match self.https.borrow_mut().give_back_listener(&address) {
3662 Ok((token, listener)) => (token, listener),
3663 Err(e) => {
3664 return worker_response_error(
3665 req_id,
3666 format!("Couldn't deactivate HTTPS listener at {address}: {e}",),
3667 );
3668 }
3669 };
3670 if let Err(e) = self.poll.registry().deregister(&mut listener) {
3671 error!(
3672 "error deregistering HTTPS listen socket({:?}): {:?}",
3673 deactivate, e
3674 );
3675 }
3676 self.reserve_listen_token(token, Protocol::HTTPSListen);
3679 self.accept_ready.remove(&ListenToken(token.0));
3680
3681 if deactivate.to_scm {
3682 self.unblock_scm_socket();
3683 let listeners = Listeners {
3684 http: vec![],
3685 tls: vec![(address.clone(), listener.as_raw_fd())],
3686 tcp: vec![],
3687 udp: vec![],
3688 };
3689 info!("sending HTTPS listener: {:?}", listeners);
3690 let res = self.scm.send_listeners(&listeners);
3691
3692 self.block_scm_socket();
3693
3694 info!("sent HTTPS listener: {:?}", res);
3695 }
3696 WorkerResponse::ok(req_id)
3697 }
3698 Ok(ListenerType::Tcp) => {
3699 let (token, mut listener) = match self.tcp.borrow_mut().give_back_listener(&address)
3700 {
3701 Ok((token, listener)) => (token, listener),
3702 Err(e) => {
3703 return worker_response_error(
3704 req_id,
3705 format!("Could not deactivate TCP listener at {address}: {e}"),
3706 );
3707 }
3708 };
3709
3710 if let Err(e) = self.poll.registry().deregister(&mut listener) {
3711 error!(
3712 "error deregistering TCP listen socket({:?}): {:?}",
3713 deactivate, e
3714 );
3715 }
3716 self.reserve_listen_token(token, Protocol::TCPListen);
3719 self.accept_ready.remove(&ListenToken(token.0));
3720
3721 if deactivate.to_scm {
3722 self.unblock_scm_socket();
3723 let listeners = Listeners {
3724 http: vec![],
3725 tls: vec![],
3726 tcp: vec![(address.clone(), listener.as_raw_fd())],
3727 udp: vec![],
3728 };
3729 info!("sending TCP listener: {:?}", listeners);
3730 let res = self.scm.send_listeners(&listeners);
3731
3732 self.block_scm_socket();
3733
3734 info!("sent TCP listener: {:?}", res);
3735 }
3736 WorkerResponse::ok(req_id)
3737 }
3738 Ok(ListenerType::Udp) => {
3739 let (token, mut listener) = match self.udp.borrow_mut().give_back_listener(&address)
3740 {
3741 Ok((token, listener)) => (token, listener),
3742 Err(e) => {
3743 return worker_response_error(
3744 req_id,
3745 format!("Could not deactivate UDP listener at {address}: {e}"),
3746 );
3747 }
3748 };
3749
3750 if let Err(e) = self.poll.registry().deregister(&mut listener) {
3751 error!(
3752 "error deregistering UDP listen socket({:?}): {:?}",
3753 deactivate, e
3754 );
3755 }
3756 self.reserve_listen_token(token, Protocol::UDPListen);
3761 self.accept_ready.remove(&ListenToken(token.0));
3765
3766 if deactivate.to_scm {
3767 self.unblock_scm_socket();
3768 let listeners = Listeners {
3769 http: vec![],
3770 tls: vec![],
3771 tcp: vec![],
3772 udp: vec![(address.clone(), listener.as_raw_fd())],
3773 };
3774 info!("sending UDP listener: {:?}", listeners);
3775 let res = self.scm.send_listeners(&listeners);
3776
3777 self.block_scm_socket();
3778
3779 info!("sent UDP listener: {:?}", res);
3780 }
3781 WorkerResponse::ok(req_id)
3782 }
3783 Err(_) => worker_response_error(req_id, "Wrong variant for ListenerType on request"),
3784 }
3785 }
3786
3787 pub fn return_listen_sockets(&mut self) -> Result<(), ScmSocketError> {
3789 self.unblock_scm_socket();
3790
3791 let mut http_listeners = self.http.borrow_mut().give_back_listeners();
3792 for &mut (_, ref mut sock) in http_listeners.iter_mut() {
3793 if let Err(e) = self.poll.registry().deregister(sock) {
3794 error!(
3795 "error deregistering HTTP listen socket({:?}): {:?}",
3796 sock, e
3797 );
3798 }
3799 }
3800
3801 let mut https_listeners = self.https.borrow_mut().give_back_listeners();
3802 for &mut (_, ref mut sock) in https_listeners.iter_mut() {
3803 if let Err(e) = self.poll.registry().deregister(sock) {
3804 error!(
3805 "error deregistering HTTPS listen socket({:?}): {:?}",
3806 sock, e
3807 );
3808 }
3809 }
3810
3811 let mut tcp_listeners = self.tcp.borrow_mut().give_back_listeners();
3812 for &mut (_, ref mut sock) in tcp_listeners.iter_mut() {
3813 if let Err(e) = self.poll.registry().deregister(sock) {
3814 error!("error deregistering TCP listen socket({:?}): {:?}", sock, e);
3815 }
3816 }
3817
3818 let mut udp_listeners = self.udp.borrow_mut().give_back_listeners();
3819 for &mut (_, ref mut sock) in udp_listeners.iter_mut() {
3820 if let Err(e) = self.poll.registry().deregister(sock) {
3821 error!("error deregistering UDP listen socket({:?}): {:?}", sock, e);
3822 }
3823 }
3824
3825 let listeners = Listeners {
3827 http: http_listeners
3828 .iter()
3829 .map(|(key, listener)| (key.clone(), listener.as_raw_fd()))
3830 .collect(),
3831 tls: https_listeners
3832 .iter()
3833 .map(|(key, listener)| (key.clone(), listener.as_raw_fd()))
3834 .collect(),
3835 tcp: tcp_listeners
3836 .iter()
3837 .map(|(key, listener)| (key.clone(), listener.as_raw_fd()))
3838 .collect(),
3839 udp: udp_listeners
3840 .iter()
3841 .map(|(key, listener)| (key.clone(), listener.as_raw_fd()))
3842 .collect(),
3843 };
3844 debug_assert_eq!(
3848 listeners.http.len(),
3849 http_listeners.len(),
3850 "every HTTP listener must be collected exactly once"
3851 );
3852 debug_assert_eq!(
3853 listeners.tls.len(),
3854 https_listeners.len(),
3855 "every HTTPS listener must be collected exactly once"
3856 );
3857 debug_assert_eq!(
3858 listeners.tcp.len(),
3859 tcp_listeners.len(),
3860 "every TCP listener must be collected exactly once"
3861 );
3862 info!("sending default listeners: {:?}", listeners);
3863 let res = self.scm.send_listeners(&listeners);
3864
3865 self.block_scm_socket();
3866
3867 info!("sent default listeners: {:?}", res);
3868 res
3869 }
3870
3871 fn block_scm_socket(&mut self) {
3872 if let Err(e) = self.scm.set_blocking(true) {
3873 error!("Could not block scm socket: {}", e);
3874 }
3875 }
3876
3877 fn unblock_scm_socket(&mut self) {
3878 if let Err(e) = self.scm.set_blocking(false) {
3879 error!("Could not unblock scm socket: {}", e);
3880 }
3881 }
3882
3883 pub fn to_session(&self, token: Token) -> SessionToken {
3884 SessionToken(token.0)
3885 }
3886
3887 pub fn from_session(&self, token: SessionToken) -> Token {
3888 Token(token.0)
3889 }
3890
3891 pub fn accept(&mut self, token: ListenToken, protocol: Protocol) {
3892 let (proto_key, accepted_protocol) = match protocol {
3905 Protocol::TCPListen => ("listener.accepted.tcp", Protocol::TCPListen),
3906 Protocol::HTTPListen => ("listener.accepted.http", Protocol::HTTPListen),
3907 Protocol::HTTPSListen => ("listener.accepted.https", Protocol::HTTPSListen),
3908 other => {
3909 warn!(
3910 "accept() called with non-listen protocol {:?} on token {:?}; skipping",
3911 other, token
3912 );
3913 return;
3914 }
3915 };
3916
3917 debug_assert!(
3920 matches!(
3921 accepted_protocol,
3922 Protocol::TCPListen | Protocol::HTTPListen | Protocol::HTTPSListen
3923 ),
3924 "accept dispatch must run with a listen protocol only"
3925 );
3926
3927 loop {
3928 let result = match accepted_protocol {
3929 Protocol::TCPListen => self.tcp.borrow_mut().accept(token),
3930 Protocol::HTTPListen => self.http.borrow_mut().accept(token),
3931 Protocol::HTTPSListen => self.https.borrow_mut().accept(token),
3932 other => unreachable!(
3936 "accept dispatch reached non-listen protocol {:?} after outer guard",
3937 other
3938 ),
3939 };
3940 match result {
3941 Ok((sock, peer)) => {
3942 incr!(names::listener::ACCEPTED_TOTAL);
3946 incr!(proto_key);
3947 incr!(per_source_bucket(&peer));
3948 let queue_before = self.accept_queue.len();
3949 self.accept_queue.push_back((
3950 sock,
3951 token,
3952 accepted_protocol,
3953 Instant::now(),
3954 peer,
3955 ));
3956 debug_assert_eq!(
3958 self.accept_queue.len(),
3959 queue_before + 1,
3960 "each accepted socket must enqueue exactly one entry"
3961 );
3962 }
3963 Err(AcceptError::WouldBlock) => {
3964 self.accept_ready.remove(&token);
3965 break;
3966 }
3967 Err(other) => {
3968 error!(
3969 "error accepting {:?} sockets: {:?}",
3970 accepted_protocol, other
3971 );
3972 self.accept_ready.remove(&token);
3973 break;
3974 }
3975 }
3976 }
3977
3978 gauge!(names::accept_queue::CONNECTIONS, self.accept_queue.len());
3979 }
3980
3981 pub fn create_sessions(&mut self) {
3982 while let Some((sock, token, protocol, timestamp, peer)) = self.accept_queue.pop_back() {
3983 let wait_time = Instant::now() - timestamp;
3984 time!(names::accept_queue::WAIT_TIME, wait_time.as_millis());
3985 if wait_time > self.accept_queue_timeout {
3986 incr!(names::accept_queue::TIMEOUT);
3987 continue;
3988 }
3989
3990 if !self.sessions.borrow_mut().check_limits() {
3991 if !self.evict_on_queue_full {
3997 incr!(names::listener::CONNECTION_CAPPED);
3998 break;
3999 }
4000
4001 if self.shutting_down.is_some() {
4005 incr!(names::listener::CONNECTION_CAPPED);
4006 break;
4007 }
4008
4009 let to_evict = (self.sessions.borrow().max_connections / 100).max(1);
4018 let evicted = self.evict_least_active_sessions(to_evict);
4019 if evicted == 0 {
4020 warn!("evict_on_queue_full enabled but no candidate sessions to evict");
4026 incr!(names::listener::CONNECTION_CAPPED);
4027 break;
4028 }
4029
4030 count!(names::sessions::EVICTED, evicted as i64);
4031 warn!(
4032 "evicted {} least recently active sessions to make room",
4033 evicted
4034 );
4035
4036 if !self.sessions.borrow_mut().check_limits() {
4037 incr!(names::listener::CONNECTION_CAPPED);
4038 break;
4039 }
4040 }
4041
4042 debug_assert!(
4049 matches!(
4050 protocol,
4051 Protocol::TCPListen | Protocol::HTTPListen | Protocol::HTTPSListen
4052 ),
4053 "accept queue must only hold listen protocols, got {protocol:?}"
4054 );
4055 match protocol {
4056 Protocol::TCPListen => {
4057 let proxy = self.tcp.clone();
4058 if self
4059 .tcp
4060 .borrow_mut()
4061 .create_session(sock, peer, token, wait_time, proxy)
4062 .is_err()
4063 {
4064 break;
4065 }
4066 }
4067 Protocol::HTTPListen => {
4068 let proxy = self.http.clone();
4069 if self
4070 .http
4071 .borrow_mut()
4072 .create_session(sock, peer, token, wait_time, proxy)
4073 .is_err()
4074 {
4075 break;
4076 }
4077 }
4078 Protocol::HTTPSListen => {
4079 if self
4080 .https
4081 .borrow_mut()
4082 .create_session(sock, peer, token, wait_time, self.https.clone())
4083 .is_err()
4084 {
4085 break;
4086 }
4087 }
4088 _ => panic!("should not call accept() on a HTTP, HTTPS or TCP session"),
4089 };
4090 let nb_before = self.sessions.borrow().nb_connections;
4091 self.sessions.borrow_mut().incr();
4092 debug_assert_eq!(
4094 self.sessions.borrow().nb_connections,
4095 nb_before + 1,
4096 "create_sessions must account exactly one new connection per created session"
4097 );
4098 }
4099
4100 gauge!(names::accept_queue::CONNECTIONS, self.accept_queue.len());
4101 }
4102
4103 fn snapshot_event_owners(
4106 &self,
4107 tokens: impl Iterator<Item = Token>,
4108 owners: &mut Vec<Option<Rc<RefCell<dyn ProxySession>>>>,
4109 ) {
4110 debug_assert!(
4111 owners.is_empty(),
4112 "the previous turn must have consumed every event owner"
4113 );
4114 let sessions = self.sessions.borrow();
4115 owners.extend(tokens.map(|token| sessions.slab.get(token.0).cloned()));
4116 }
4117
4118 fn ready_if_still_owned(
4140 &mut self,
4141 token: Token,
4142 events: Ready,
4143 owner: Option<Rc<RefCell<dyn ProxySession>>>,
4144 ) {
4145 let still_owned = owner.is_some_and(|owner| {
4146 self.sessions
4147 .borrow()
4148 .slab
4149 .get(token.0)
4150 .is_some_and(|current| Rc::ptr_eq(current, &owner))
4151 });
4152 if !still_owned {
4153 trace!(
4154 "PROXY\t{:?} dropping events {:?} from a socket whose session closed earlier in this epoll result",
4155 token, events
4156 );
4157 return;
4158 }
4159 self.ready(token, events);
4160 }
4161
4162 pub fn ready(&mut self, token: Token, events: Ready) {
4163 trace!("PROXY\t{:?} got events: {:?}", token, events);
4164
4165 let session_token = token.0;
4166 if self.sessions.borrow().slab.contains(session_token) {
4167 let protocol = self.sessions.borrow().slab[session_token]
4169 .borrow()
4170 .protocol();
4171 match protocol {
4180 Protocol::HTTPListen | Protocol::HTTPSListen | Protocol::TCPListen => {
4181 if events.is_readable() {
4183 self.accept_ready.insert(ListenToken(token.0));
4184 if self.sessions.borrow().can_accept {
4185 self.accept(ListenToken(token.0), protocol);
4186 }
4187 return;
4188 }
4189
4190 if events.is_writable() {
4191 error!(
4192 "received writable for listener {:?}, this should not happen",
4193 token
4194 );
4195 return;
4196 }
4197
4198 if events.is_hup() {
4199 error!("should not happen: server {:?} closed", token);
4200 return;
4201 }
4202
4203 unreachable!();
4204 }
4205 _ => {}
4206 }
4207
4208 let session = self.sessions.borrow_mut().slab[session_token].clone();
4209 session.borrow_mut().update_readiness(token, events);
4210 if session.borrow_mut().ready(session.clone()) {
4211 debug!(
4212 "Server killing session from ready: token={:?}, protocol={:?}, events={:?}",
4213 token, protocol, events
4214 );
4215 self.kill_session(session);
4216 }
4217 }
4218 }
4219
4220 pub fn timeout(&mut self, token: Token) {
4221 trace!("PROXY\t{:?} got timeout", token);
4222
4223 let session_token = token.0;
4224 if self.sessions.borrow().slab.contains(session_token) {
4225 let session = self.sessions.borrow_mut().slab[session_token].clone();
4226 if session.borrow_mut().timeout(token) {
4227 debug!(
4228 "Server killing session from timeout: token={:?}, protocol={:?}",
4229 token,
4230 session.borrow().protocol()
4231 );
4232 self.kill_session(session);
4233 } else if session.borrow().needs_ready_pass() {
4234 if session.borrow_mut().ready(session.clone()) {
4239 debug!(
4240 "Server killing session from ready after timeout: token={:?}, protocol={:?}",
4241 token,
4242 session.borrow().protocol()
4243 );
4244 self.kill_session(session);
4245 }
4246 }
4247 }
4248 }
4249
4250 pub fn handle_remaining_readiness(&mut self) {
4251 if self.sessions.borrow().can_accept && !self.accept_ready.is_empty() {
4254 while let Some(token) = self
4255 .accept_ready
4256 .iter()
4257 .next()
4258 .map(|token| ListenToken(token.0))
4259 {
4260 let protocol = self
4277 .sessions
4278 .borrow()
4279 .slab
4280 .get(token.0)
4281 .map(|session| session.borrow().protocol());
4282 let Some(protocol) = protocol else {
4283 error!(
4284 "accept_ready holds listen token {:?}, which no longer has a session; dropping it",
4285 token
4286 );
4287 self.accept_ready.remove(&token);
4288 continue;
4289 };
4290 self.accept(token, protocol);
4291 if !self.sessions.borrow().can_accept || self.accept_ready.is_empty() {
4292 break;
4293 }
4294 }
4295 }
4296 }
4297 fn block_channel(&mut self) {
4298 if let Err(e) = self.channel.blocking() {
4299 error!("Could not block channel: {}", e);
4300 }
4301 }
4302 fn unblock_channel(&mut self) {
4303 if let Err(e) = self.channel.nonblocking() {
4304 error!("Could not block channel: {}", e);
4305 }
4306 }
4307
4308 fn evict_least_active_sessions(&self, count: usize) -> usize {
4320 if count == 0 {
4321 return 0;
4322 }
4323
4324 let tokens = {
4325 let sessions = self.sessions.borrow();
4326 let mut candidates: Vec<(Token, Instant)> = sessions
4327 .slab
4328 .iter()
4329 .filter(|(_, session)| {
4330 !matches!(
4331 session.borrow().protocol(),
4332 Protocol::HTTPListen
4333 | Protocol::HTTPSListen
4334 | Protocol::TCPListen
4335 | Protocol::UDPListen
4336 | Protocol::Channel
4337 | Protocol::Metrics
4338 | Protocol::Timer
4339 )
4340 })
4341 .map(|(_, session)| {
4342 let s = session.borrow();
4343 (s.frontend_token(), s.last_event())
4344 })
4345 .collect();
4346
4347 if candidates.is_empty() {
4350 return 0;
4351 }
4352
4353 let pivot = count.min(candidates.len()) - 1;
4354 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
4355
4356 candidates[..=pivot]
4357 .iter()
4358 .map(|&(token, _)| token)
4359 .collect::<HashSet<Token>>()
4360 };
4361
4362 let evicted = tokens.len();
4363 self.shut_down_sessions_by_frontend_tokens(tokens);
4364 evicted
4365 }
4366}
4367
4368fn discard_inherited_socket<T: FromRawFd>(
4388 fd: Option<RawFd>,
4389 address: &ListenerKey,
4390 protocol: &str,
4391) {
4392 let Some(fd) = fd else {
4393 return;
4394 };
4395 warn!(
4396 "closing the inherited {} listening socket for {}: this worker already has an active \
4397 listener there, so nothing will adopt this descriptor unless that listener is \
4398 deactivated and reactivated, and until then it is expected to keep taking a share of \
4399 new connections that nothing accepts (inferred from SO_REUSEPORT semantics, not \
4400 measured here)",
4401 protocol, address
4402 );
4403 drop(unsafe { T::from_raw_fd(fd) });
4407}
4408
4409fn worker_response_error<S: ToString, T: ToString>(request_id: S, error: T) -> WorkerResponse {
4412 error!(
4413 "error on request {}, {}",
4414 request_id.to_string(),
4415 error.to_string()
4416 );
4417 WorkerResponse::error(request_id, error)
4418}
4419
4420pub struct ListenSession {
4421 pub protocol: Protocol,
4422}
4423
4424impl ProxySession for ListenSession {
4425 fn last_event(&self) -> Instant {
4426 Instant::now()
4427 }
4428
4429 fn print_session(&self) {}
4430
4431 fn frontend_token(&self) -> Token {
4432 Token(0)
4433 }
4434
4435 fn protocol(&self) -> Protocol {
4436 self.protocol
4437 }
4438
4439 fn ready(&mut self, _session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
4440 false
4441 }
4442
4443 fn shutting_down(&mut self) -> SessionIsToBeClosed {
4444 false
4445 }
4446
4447 fn update_readiness(&mut self, _token: Token, _events: Ready) {}
4448
4449 fn close(&mut self) {}
4450
4451 fn timeout(&mut self, _token: Token) -> SessionIsToBeClosed {
4452 error!(
4453 "called ProxySession::timeout(token={:?}, time) on ListenSession {{ protocol: {:?} }}",
4454 _token, self.protocol
4455 );
4456 false
4457 }
4458}
4459
4460#[cfg(test)]
4461mod accept_telemetry_tests {
4462 use super::*;
4463
4464 #[test]
4467 fn per_source_bucket_collapses_ipv4_slash24() {
4468 let a: SocketAddr = "203.0.113.5:1234".parse().unwrap();
4469 let b: SocketAddr = "203.0.113.250:9999".parse().unwrap();
4470 assert_eq!(
4471 per_source_bucket(&a),
4472 per_source_bucket(&b),
4473 "addresses in the same /24 must land in the same bucket"
4474 );
4475 }
4476
4477 #[test]
4479 fn per_source_bucket_collapses_ipv6_slash48() {
4480 let a: SocketAddr = "[2001:db8:1234::1]:443".parse().unwrap();
4481 let b: SocketAddr = "[2001:db8:1234:abcd::ffff]:8443".parse().unwrap();
4482 assert_eq!(
4483 per_source_bucket(&a),
4484 per_source_bucket(&b),
4485 "addresses in the same /48 must land in the same bucket"
4486 );
4487 }
4488
4489 #[test]
4492 fn per_source_bucket_keys_are_bounded() {
4493 assert_eq!(PER_SOURCE_BUCKET_KEYS.len(), PER_SOURCE_BUCKETS);
4494 for (i, key) in PER_SOURCE_BUCKET_KEYS.iter().enumerate() {
4495 let expected = format!("client.connect.per_source.bucket_{i:03}");
4496 assert_eq!(*key, expected.as_str());
4497 }
4498 }
4499
4500 #[test]
4503 fn per_source_bucket_distributes_distinct_subnets() {
4504 let mut hits = std::collections::HashSet::new();
4505 for i in 0..200u8 {
4506 let addr: SocketAddr = format!("10.0.{i}.42:80").parse().unwrap();
4507 hits.insert(per_source_bucket(&addr));
4508 }
4509 assert!(
4513 hits.len() >= 100,
4514 "expected at least 100 distinct buckets across 200 /24s, got {}",
4515 hits.len()
4516 );
4517 }
4518}
4519
4520#[cfg(test)]
4521mod state_error_log_tests {
4522 use sozu_command::state::StateError;
4523
4524 #[test]
4525 fn worker_state_dispatch_error_sink_bounds_the_reason() {
4526 const REASON_SECRET: &str = "WORKER_STATE_ERROR_REASON_SECRET_SENTINEL";
4527
4528 let reason = format!("{REASON_SECRET}{}", "x".repeat(4096));
4529 let reason_len = reason.len();
4530 let output = crate::capture_test_logs(move || {
4531 let error = StateError::InvalidTcpFrontend {
4532 address: "127.0.0.1:443"
4533 .parse()
4534 .expect("test TCP frontend address must parse"),
4535 reason,
4536 };
4537 error!("Could not execute order on config state: {}", error);
4538 });
4539
4540 assert!(
4541 !output.contains(REASON_SECRET),
4542 "worker state-error sink leaked the reason: {output}"
4543 );
4544 assert!(
4545 output.contains(&format!("reason_bytes={reason_len}")),
4546 "worker state-error sink omitted bounded reason metadata: {output}"
4547 );
4548 assert!(
4549 output.len() <= 512,
4550 "worker state-error sink is not bounded: {} bytes",
4551 output.len()
4552 );
4553 }
4554}
4555
4556#[cfg(test)]
4557mod eviction_tests {
4558 use std::collections::HashSet;
4559 use std::time::{Duration, Instant};
4560
4561 use mio::Token;
4562
4563 #[test]
4567 fn select_nth_finds_oldest_sessions() {
4568 let now = Instant::now();
4569 let mut candidates = [
4570 (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)), ];
4576
4577 let count = 2;
4578 let pivot = count.min(candidates.len()) - 1;
4579 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
4580
4581 let selected: HashSet<Token> = candidates[..=pivot]
4582 .iter()
4583 .map(|&(token, _)| token)
4584 .collect();
4585
4586 assert_eq!(selected.len(), 2);
4587 assert!(
4588 selected.contains(&Token(2)),
4589 "should contain 50s-old session"
4590 );
4591 assert!(
4592 selected.contains(&Token(4)),
4593 "should contain 30s-old session"
4594 );
4595 }
4596
4597 #[test]
4601 fn select_nth_with_count_exceeding_candidates() {
4602 let now = Instant::now();
4603 let mut candidates = [(Token(1), now - Duration::from_secs(10))];
4604
4605 let count = 5;
4606 let pivot = count.min(candidates.len()) - 1;
4607 candidates.select_nth_unstable_by_key(pivot, |&(_, last_event)| last_event);
4608
4609 let selected: HashSet<Token> = candidates[..=pivot]
4610 .iter()
4611 .map(|&(token, _)| token)
4612 .collect();
4613
4614 assert_eq!(selected.len(), 1);
4615 assert!(selected.contains(&Token(1)));
4616 }
4617}
4618
4619#[cfg(test)]
4620mod accept_ready_tests {
4621 use sozu_command::{
4622 config::ListenerBuilder,
4623 proto::command::{DeactivateListener, ListenerType, SocketAddress},
4624 };
4625
4626 use super::*;
4627 use crate::testing::{ServerParts, prebuild_server, provide_port};
4628
4629 pub(super) fn server_with_tcp_listener() -> (Server, Token, SocketAddress) {
4634 let ServerParts {
4635 event_loop,
4636 registry,
4637 sessions,
4638 pool,
4639 backends,
4640 server_scm_socket,
4641 server_config,
4642 ..
4643 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
4648 let (_command_channel, proxy_channel) =
4649 Channel::generate(1000, 10000).expect("could not generate a test channel");
4650
4651 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
4652 let listener_config = ListenerBuilder::new_tcp(address)
4653 .to_tcp(None)
4654 .expect("could not build a TcpListenerConfig for the test");
4655
4656 let listen_token = {
4657 let mut session_manager = sessions.borrow_mut();
4658 let entry = session_manager.slab.vacant_entry();
4659 let token = Token(entry.key());
4660 entry.insert(Rc::new(RefCell::new(ListenSession {
4661 protocol: Protocol::TCPListen,
4662 })));
4663 token
4664 };
4665
4666 let mut tcp_proxy =
4667 tcp::TcpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
4668 tcp_proxy
4669 .add_listener(listener_config, listen_token)
4670 .expect("could not add the test TCP listener");
4671 tcp_proxy
4672 .activate_listener(&address.into(), None)
4673 .expect("could not activate the test TCP listener");
4674
4675 let server = Server::new(
4676 event_loop,
4677 proxy_channel,
4678 server_scm_socket,
4679 sessions,
4680 pool,
4681 backends,
4682 None,
4683 None,
4684 Some(tcp_proxy),
4685 server_config,
4686 None,
4687 false,
4688 )
4689 .expect("could not build the test server");
4690
4691 (server, listen_token, address)
4694 }
4695
4696 #[test]
4708 fn deactivating_a_listener_drops_its_pending_accept_token() {
4709 let (mut server, listen_token, address) = server_with_tcp_listener();
4710
4711 server.accept_ready.insert(ListenToken(listen_token.0));
4713
4714 let response = server.notify_deactivate_listener(
4715 "test-deactivate",
4716 &DeactivateListener {
4717 interface: None,
4718 address,
4719 proxy: ListenerType::Tcp as i32,
4720 to_scm: false,
4721 },
4722 );
4723 assert_eq!(
4724 response.status,
4725 ResponseStatus::Ok as i32,
4726 "deactivating an activated TCP listener must succeed: {response:?}"
4727 );
4728 assert!(
4729 server.sessions.borrow().slab.contains(listen_token.0),
4730 "deactivating a listener must KEEP its slab slot reserved — see \
4731 `reserve_listen_token`; the accept purge below is what stops the \
4732 deferred pass from accepting on a socket-less listener"
4733 );
4734 assert!(
4735 !server.accept_ready.contains(&ListenToken(listen_token.0)),
4736 "a deactivated listener must not stay queued for a deferred accept"
4737 );
4738
4739 server.handle_remaining_readiness();
4741 }
4742
4743 #[test]
4754 fn a_stale_accept_token_is_dropped_instead_of_panicking() {
4755 let (mut server, listen_token, _address) = server_with_tcp_listener();
4756
4757 server.sessions.borrow_mut().slab.remove(listen_token.0);
4758 server.accept_ready.insert(ListenToken(listen_token.0));
4759
4760 server.handle_remaining_readiness();
4761
4762 assert!(
4763 server.accept_ready.is_empty(),
4764 "a listen token with no session must be dropped from accept_ready"
4765 );
4766 }
4767}
4768#[cfg(test)]
4773mod event_owner_tests {
4774 use super::*;
4775
4776 struct ClosingSession {
4779 sessions: Rc<RefCell<SessionManager>>,
4780 frontend: Token,
4781 backend: Token,
4782 }
4783
4784 impl ProxySession for ClosingSession {
4785 fn protocol(&self) -> Protocol {
4786 Protocol::TCP
4787 }
4788 fn ready(&mut self, _session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
4789 true
4790 }
4791 fn shutting_down(&mut self) -> SessionIsToBeClosed {
4792 true
4793 }
4794 fn update_readiness(&mut self, _token: Token, _events: Ready) {}
4795 fn close(&mut self) {
4796 self.sessions.borrow_mut().slab.try_remove(self.backend.0);
4797 }
4798 fn timeout(&mut self, _token: Token) -> SessionIsToBeClosed {
4799 false
4800 }
4801 fn last_event(&self) -> Instant {
4802 Instant::now()
4803 }
4804 fn print_session(&self) {}
4805 fn frontend_token(&self) -> Token {
4806 self.frontend
4807 }
4808 }
4809
4810 struct DialingSession {
4814 sessions: Rc<RefCell<SessionManager>>,
4815 frontend: Token,
4816 backend: Option<Token>,
4817 delivered: Vec<Token>,
4818 }
4819
4820 impl ProxySession for DialingSession {
4821 fn protocol(&self) -> Protocol {
4822 Protocol::TCP
4823 }
4824 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
4825 if self.backend.is_none() {
4826 self.backend = Some(Token(self.sessions.borrow_mut().slab.insert(session)));
4827 }
4828 false
4829 }
4830 fn shutting_down(&mut self) -> SessionIsToBeClosed {
4831 true
4832 }
4833 fn update_readiness(&mut self, token: Token, _events: Ready) {
4834 self.delivered.push(token);
4835 }
4836 fn close(&mut self) {}
4837 fn timeout(&mut self, _token: Token) -> SessionIsToBeClosed {
4838 false
4839 }
4840 fn last_event(&self) -> Instant {
4841 Instant::now()
4842 }
4843 fn print_session(&self) {}
4844 fn frontend_token(&self) -> Token {
4845 self.frontend
4846 }
4847 }
4848
4849 #[test]
4857 fn an_event_of_a_closed_session_is_not_delivered_to_the_session_reusing_its_token() {
4858 let (mut server, _listen_token, _address) =
4859 super::accept_ready_tests::server_with_tcp_listener();
4860 let sessions = server.sessions.clone();
4861
4862 let closing = Rc::new(RefCell::new(ClosingSession {
4863 sessions: sessions.clone(),
4864 frontend: Token(0),
4865 backend: Token(0),
4866 }));
4867 let dialing = Rc::new(RefCell::new(DialingSession {
4868 sessions: sessions.clone(),
4869 frontend: Token(0),
4870 backend: None,
4871 delivered: Vec::new(),
4872 }));
4873 {
4874 let mut sessions = sessions.borrow_mut();
4875 let closing_session: Rc<RefCell<dyn ProxySession>> = closing.clone();
4876 let frontend = Token(sessions.slab.insert(closing_session.clone()));
4877 let backend = Token(sessions.slab.insert(closing_session));
4878 let mut closing = closing.borrow_mut();
4879 closing.frontend = frontend;
4880 closing.backend = backend;
4881 let dialing_session: Rc<RefCell<dyn ProxySession>> = dialing.clone();
4882 dialing.borrow_mut().frontend = Token(sessions.slab.insert(dialing_session));
4883 sessions.incr();
4884 sessions.incr();
4885 }
4886 let closed_frontend = closing.borrow().frontend;
4887 let closed_backend = closing.borrow().backend;
4888 let dialing_frontend = dialing.borrow().frontend;
4889
4890 let batch = [
4891 (closed_frontend, Ready::READABLE | Ready::HUP),
4892 (dialing_frontend, Ready::READABLE | Ready::WRITABLE),
4893 (
4894 closed_backend,
4895 Ready::READABLE | Ready::WRITABLE | Ready::HUP,
4896 ),
4897 ];
4898 let mut owners = Vec::new();
4899 server.snapshot_event_owners(batch.iter().map(|(token, _)| *token), &mut owners);
4900 for ((token, events), owner) in batch.into_iter().zip(owners.drain(..)) {
4901 server.ready_if_still_owned(token, events, owner);
4902 }
4903
4904 assert_eq!(
4905 dialing.borrow().backend,
4906 Some(closed_backend),
4907 "precondition: the dial must reuse the key the closed session freed in this batch"
4908 );
4909 assert!(
4910 !sessions.borrow().slab.contains(closed_frontend.0),
4911 "the closed session must have left the slab"
4912 );
4913 assert_eq!(
4914 dialing.borrow().delivered,
4915 vec![dialing_frontend],
4916 "the closed backend's HUP must not reach the session that reused its token"
4917 );
4918 }
4919}
4920#[cfg(test)]
4925mod listener_lifecycle_tests {
4926 use std::net::UdpSocket as StdUdpSocket;
4927
4928 use sozu_command::{
4929 config::ListenerBuilder,
4930 proto::command::{
4931 ActivateListener, DeactivateListener, ListenerType, LoadBalancingParams,
4932 RemoveListener, RequestUdpFrontend, SocketAddress, filtered_metrics,
4933 },
4934 };
4935
4936 use super::accept_ready_tests::server_with_tcp_listener;
4937 use super::*;
4938 use crate::{
4939 metrics::{METRICS, names},
4940 testing::{ServerParts, prebuild_server, provide_port},
4941 };
4942
4943 pub(super) fn bare_server() -> Server {
4948 let ServerParts {
4949 event_loop,
4950 sessions,
4951 pool,
4952 backends,
4953 server_scm_socket,
4954 server_config,
4955 ..
4956 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
4957 let (_command_channel, proxy_channel) =
4958 Channel::generate(1000, 10000).expect("could not generate a test channel");
4959
4960 Server::new(
4961 event_loop,
4962 proxy_channel,
4963 server_scm_socket,
4964 sessions,
4965 pool,
4966 backends,
4967 None,
4968 None,
4969 None,
4970 server_config,
4971 None,
4972 false,
4973 )
4974 .expect("could not build the test server")
4975 }
4976
4977 fn add_udp_listener(server: &mut Server, address: SocketAddress) -> Token {
4978 let listener_config = ListenerBuilder::new_udp(address)
4979 .to_udp(None)
4980 .expect("could not build a UdpListenerConfig for the test");
4981 let response = server.notify_add_udp_listener("test-add-udp", listener_config);
4982 assert_eq!(
4983 response.status,
4984 ResponseStatus::Ok as i32,
4985 "adding a UDP listener must succeed: {response:?}"
4986 );
4987 server
4988 .udp
4989 .borrow()
4990 .listener_token(&address.into())
4991 .expect("the added UDP listener must own a token")
4992 }
4993
4994 fn activate(server: &mut Server, address: SocketAddress, proxy: ListenerType) {
4995 let response = server.notify_activate_listener(
4996 "test-activate",
4997 &ActivateListener {
4998 interface: None,
4999 address,
5000 proxy: proxy as i32,
5001 from_scm: false,
5002 },
5003 );
5004 assert_eq!(
5005 response.status,
5006 ResponseStatus::Ok as i32,
5007 "activating a {proxy:?} listener must succeed: {response:?}"
5008 );
5009 }
5010
5011 fn deactivate(server: &mut Server, address: SocketAddress, proxy: ListenerType) {
5012 let response = server.notify_deactivate_listener(
5013 "test-deactivate",
5014 &DeactivateListener {
5015 interface: None,
5016 address,
5017 proxy: proxy as i32,
5018 to_scm: false,
5019 },
5020 );
5021 assert_eq!(
5022 response.status,
5023 ResponseStatus::Ok as i32,
5024 "deactivating a {proxy:?} listener must succeed: {response:?}"
5025 );
5026 }
5027
5028 fn slot_state(server: &Server, token: Token) -> Option<(Protocol, bool)> {
5034 let sessions = server.sessions.borrow();
5035 let session = sessions.slab.get(token.0)?;
5036 let session = session.borrow();
5037 Some((session.protocol(), session.frontend_token() == Token(0)))
5038 }
5039
5040 #[test]
5061 fn a_reactivated_tcp_listener_is_reachable_from_the_event_loop() {
5062 let (mut server, listen_token, address) = server_with_tcp_listener();
5063
5064 deactivate(&mut server, address, ListenerType::Tcp);
5065 activate(&mut server, address, ListenerType::Tcp);
5066
5067 server.sessions.borrow_mut().can_accept = false;
5068 server.ready(listen_token, Ready::READABLE);
5069
5070 assert!(
5071 server.accept_ready.contains(&ListenToken(listen_token.0)),
5072 "a reactivated listener must still be dispatched by `ready()`"
5073 );
5074 }
5075
5076 #[test]
5088 fn a_reactivated_udp_listener_gets_its_session_back() {
5089 let mut server = bare_server();
5090 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5091 let listen_token = add_udp_listener(&mut server, address);
5092
5093 assert_eq!(
5094 slot_state(&server, listen_token),
5095 Some((Protocol::UDPListen, true)),
5096 "an added, not-yet-activated UDP listener holds the placeholder"
5097 );
5098
5099 activate(&mut server, address, ListenerType::Udp);
5100 assert_eq!(
5101 slot_state(&server, listen_token),
5102 Some((Protocol::UDPListen, false)),
5103 "activating must install the real UdpListenerSession"
5104 );
5105
5106 deactivate(&mut server, address, ListenerType::Udp);
5107 activate(&mut server, address, ListenerType::Udp);
5108
5109 assert_eq!(
5110 slot_state(&server, listen_token),
5111 Some((Protocol::UDPListen, false)),
5112 "reactivating must reinstall the real UdpListenerSession"
5113 );
5114 }
5115
5116 #[test]
5140 fn a_deactivated_udp_listeners_key_is_not_handed_to_another_session() {
5141 let mut server = bare_server();
5142 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5143 let listen_token = add_udp_listener(&mut server, address);
5144 activate(&mut server, address, ListenerType::Udp);
5145 deactivate(&mut server, address, ListenerType::Udp);
5146
5147 let interloper = {
5150 let mut sessions = server.sessions.borrow_mut();
5151 let entry = sessions.slab.vacant_entry();
5152 let key = entry.key();
5153 entry.insert(Rc::new(RefCell::new(ListenSession {
5154 protocol: Protocol::Channel,
5155 })));
5156 Token(key)
5157 };
5158 assert_ne!(
5159 interloper, listen_token,
5160 "a deactivated listener's key must not be handed to another session"
5161 );
5162
5163 activate(&mut server, address, ListenerType::Udp);
5164
5165 assert_eq!(
5166 slot_state(&server, interloper),
5167 Some((Protocol::Channel, true)),
5168 "reactivating a listener must not overwrite another session's slot"
5169 );
5170 }
5171
5172 const UDP_FLOW_CLUSTER: &str = "udp-duplicate-activate";
5174
5175 fn slab_session(server: &Server, token: Token) -> Rc<RefCell<dyn ProxySession>> {
5181 server
5182 .sessions
5183 .borrow()
5184 .slab
5185 .get(token.0)
5186 .expect("the listener must own a slab slot")
5187 .clone()
5188 }
5189
5190 fn active_flows_gauge() -> i64 {
5194 METRICS.with(|metrics| {
5195 metrics
5196 .borrow_mut()
5197 .dump_local_proxy_metrics()
5198 .get(names::udp::ACTIVE_FLOWS)
5199 .and_then(|metric| match metric.inner {
5200 Some(filtered_metrics::Inner::Gauge(value)) => Some(value as i64),
5201 _ => None,
5202 })
5203 .unwrap_or(0)
5204 })
5205 }
5206
5207 fn udp_worker_with_backend(
5213 server: &mut Server,
5214 address: SocketAddress,
5215 ) -> (StdUdpSocket, StdUdpSocket) {
5216 server.notify_proxys(WorkerRequest {
5217 id: "test-add-udp-front".to_owned(),
5218 content: RequestType::AddUdpFrontend(RequestUdpFrontend {
5219 cluster_id: UDP_FLOW_CLUSTER.to_owned(),
5220 address,
5221 tags: Default::default(),
5222 })
5223 .into(),
5224 });
5225
5226 let backend_socket =
5227 StdUdpSocket::bind("127.0.0.1:0").expect("could not bind the test UDP backend");
5228 backend_socket
5229 .set_read_timeout(Some(Duration::from_millis(500)))
5230 .expect("could not set the backend read timeout");
5231 let backend_address = backend_socket
5232 .local_addr()
5233 .expect("the test UDP backend must have a local address");
5234
5235 server.notify_proxys(WorkerRequest {
5236 id: "test-add-udp-backend".to_owned(),
5237 content: RequestType::AddBackend(AddBackend {
5238 cluster_id: UDP_FLOW_CLUSTER.to_owned(),
5239 backend_id: format!("{UDP_FLOW_CLUSTER}-0"),
5240 address: backend_address.into(),
5241 load_balancing_parameters: Some(LoadBalancingParams::default()),
5242 sticky_id: None,
5243 backup: None,
5244 })
5245 .into(),
5246 });
5247
5248 let client_socket =
5249 StdUdpSocket::bind("127.0.0.1:0").expect("could not bind the test UDP client");
5250 (client_socket, backend_socket)
5251 }
5252
5253 fn forward_one(
5259 server: &mut Server,
5260 listen_token: Token,
5261 listen_address: SocketAddress,
5262 client: &StdUdpSocket,
5263 backend: &StdUdpSocket,
5264 payload: &[u8],
5265 ) -> Option<Vec<u8>> {
5266 let target: std::net::SocketAddr = listen_address.into();
5267 client
5268 .send_to(payload, target)
5269 .expect("the test client must reach the UDP listener");
5270 server.ready(listen_token, Ready::READABLE);
5271
5272 let mut received = [0u8; 64];
5273 backend
5274 .recv_from(&mut received)
5275 .ok()
5276 .map(|(len, _)| received[..len].to_vec())
5277 }
5278
5279 #[test]
5294 fn a_duplicate_udp_activate_keeps_the_live_listener_session() {
5295 let mut server = bare_server();
5296 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5297 let listen_token = add_udp_listener(&mut server, address);
5298 activate(&mut server, address, ListenerType::Udp);
5299
5300 let installed = slab_session(&server, listen_token);
5301
5302 let response = server.notify_activate_listener(
5303 "test-activate-twice",
5304 &ActivateListener {
5305 interface: None,
5306 address,
5307 proxy: ListenerType::Udp as i32,
5308 from_scm: false,
5309 },
5310 );
5311 assert_eq!(
5318 response.status,
5319 ResponseStatus::Ok as i32,
5320 "a repeated ActivateListener on an active UDP listener must answer ok: {response:?}"
5321 );
5322 assert_eq!(
5323 slot_state(&server, listen_token),
5324 Some((Protocol::UDPListen, false)),
5325 "the real UdpListenerSession must still be the one in the slab"
5326 );
5327 assert!(
5328 Rc::ptr_eq(&installed, &slab_session(&server, listen_token)),
5329 "a repeated ActivateListener must not replace the live UDP listener session"
5330 );
5331 }
5332
5333 #[test]
5345 fn in_flight_udp_flows_survive_a_duplicate_udp_activate() {
5346 let mut server = bare_server();
5347 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5348 let listen_token = add_udp_listener(&mut server, address);
5349 activate(&mut server, address, ListenerType::Udp);
5350 let (client, backend) = udp_worker_with_backend(&mut server, address);
5351
5352 assert_eq!(
5353 forward_one(
5354 &mut server,
5355 listen_token,
5356 address,
5357 &client,
5358 &backend,
5359 b"before"
5360 )
5361 .as_deref(),
5362 Some(&b"before"[..]),
5363 "the flow must be established before the duplicate activate"
5364 );
5365 assert_eq!(
5366 active_flows_gauge(),
5367 1,
5368 "one established flow must be on the gauge"
5369 );
5370
5371 activate(&mut server, address, ListenerType::Udp);
5372
5373 assert_eq!(
5378 active_flows_gauge(),
5379 1,
5380 "a repeated ActivateListener must neither open nor evict a flow"
5381 );
5382 assert_eq!(
5383 forward_one(
5384 &mut server,
5385 listen_token,
5386 address,
5387 &client,
5388 &backend,
5389 b"after"
5390 )
5391 .as_deref(),
5392 Some(&b"after"[..]),
5393 "an in-flight UDP flow must survive a repeated ActivateListener"
5394 );
5395 }
5396
5397 #[test]
5408 fn a_duplicate_udp_activate_strands_no_upstream_slab_slot() {
5409 let mut server = bare_server();
5410 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5411 let listen_token = add_udp_listener(&mut server, address);
5412 activate(&mut server, address, ListenerType::Udp);
5413 let (client, backend) = udp_worker_with_backend(&mut server, address);
5414
5415 let baseline = server.sessions.borrow().slab.len();
5418
5419 assert!(
5420 forward_one(
5421 &mut server,
5422 listen_token,
5423 address,
5424 &client,
5425 &backend,
5426 b"flow"
5427 )
5428 .is_some(),
5429 "the flow must be established before the duplicate activate"
5430 );
5431 assert_eq!(
5432 server.sessions.borrow().slab.len(),
5433 baseline + 1,
5434 "an established flow owns exactly one upstream slab slot"
5435 );
5436
5437 activate(&mut server, address, ListenerType::Udp);
5438 deactivate(&mut server, address, ListenerType::Udp);
5439
5440 assert_eq!(
5441 server.sessions.borrow().slab.len(),
5442 baseline,
5443 "tearing the listener down must release every per-flow slab slot"
5444 );
5445 assert_eq!(
5446 active_flows_gauge(),
5447 0,
5448 "tearing the listener down must return the active-flows gauge to zero"
5449 );
5450 }
5451
5452 #[test]
5468 fn replaying_activate_listener_is_a_clean_no_op_for_an_active_udp_listener() {
5469 let mut server = bare_server();
5470 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5471 let listener_config = ListenerBuilder::new_udp(address)
5472 .to_udp(None)
5473 .expect("could not build a UdpListenerConfig for the test");
5474
5475 server.notify_proxys(WorkerRequest {
5478 id: "test-add-udp".to_owned(),
5479 content: RequestType::AddUdpListener(listener_config).into(),
5480 });
5481 server.notify_proxys(WorkerRequest {
5482 id: "test-activate".to_owned(),
5483 content: RequestType::ActivateListener(ActivateListener {
5484 interface: None,
5485 address,
5486 proxy: ListenerType::Udp as i32,
5487 from_scm: false,
5488 })
5489 .into(),
5490 });
5491 let listen_token = server
5492 .udp
5493 .borrow()
5494 .listener_token(&address.into())
5495 .expect("the added UDP listener must own a token");
5496 let installed = slab_session(&server, listen_token);
5497
5498 let replayed: Vec<ActivateListener> = server
5499 .config_state
5500 .generate_activate_requests()
5501 .into_iter()
5502 .filter_map(|request| match request.request_type {
5503 Some(RequestType::ActivateListener(activate)) => Some(activate),
5504 _ => None,
5505 })
5506 .collect();
5507 assert_eq!(
5508 replayed.len(),
5509 1,
5510 "an active UDP listener must be replayed exactly once: {replayed:?}"
5511 );
5512
5513 for activate in &replayed {
5514 let response = server.notify_activate_listener("test-replay", activate);
5515 assert_eq!(
5516 response.status,
5517 ResponseStatus::Ok as i32,
5518 "a replayed ActivateListener must answer ok: {response:?}"
5519 );
5520 }
5521
5522 assert_eq!(
5523 slot_state(&server, listen_token),
5524 Some((Protocol::UDPListen, false)),
5525 "the replay must leave the real UdpListenerSession in the slab"
5526 );
5527 assert!(
5528 Rc::ptr_eq(&installed, &slab_session(&server, listen_token)),
5529 "replaying ActivateListener must leave the live UDP listener session in place"
5530 );
5531 }
5532
5533 #[test]
5552 fn removing_a_listener_releases_its_reserved_slab_slot() {
5553 let mut server = bare_server();
5554 let baseline = server.sessions.borrow().slab.len();
5555 let base_sessions_count = server.base_sessions_count;
5556
5557 for cycle in 0..3 {
5558 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5559 let listen_token = add_udp_listener(&mut server, address);
5560 activate(&mut server, address, ListenerType::Udp);
5561 if cycle % 2 == 0 {
5562 deactivate(&mut server, address, ListenerType::Udp);
5563 }
5564
5565 server.notify_proxys(WorkerRequest {
5566 id: "test-remove".to_owned(),
5567 content: RequestType::RemoveListener(RemoveListener {
5568 interface: None,
5569 address,
5570 proxy: ListenerType::Udp as i32,
5571 })
5572 .into(),
5573 });
5574
5575 assert!(
5576 !server.sessions.borrow().slab.contains(listen_token.0),
5577 "cycle {cycle}: removing a listener must release its reserved slot"
5578 );
5579 assert_eq!(
5580 server.sessions.borrow().slab.len(),
5581 baseline,
5582 "cycle {cycle}: the slab must return to its baseline occupancy"
5583 );
5584 assert_eq!(
5585 server.base_sessions_count, base_sessions_count,
5586 "cycle {cycle}: base_sessions_count must track the reserved slots"
5587 );
5588 }
5589 }
5590
5591 #[test]
5602 fn udp_flow_limits_come_from_the_cluster_not_the_global_defaults() {
5603 use std::{net::SocketAddr, time::Instant};
5604
5605 use crate::protocol::udp::{
5606 BackendId, BackendSource, ManagerInput, MetricEvent, Output, UdpManager,
5607 };
5608
5609 struct OneBackend;
5610 impl BackendSource for OneBackend {
5611 fn select(
5612 &mut self,
5613 _cluster: &str,
5614 _key: Option<u64>,
5615 _now: Instant,
5616 ) -> Option<(BackendId, SocketAddr)> {
5617 Some(("b".to_owned(), SocketAddr::from(([127, 0, 0, 1], 5353))))
5618 }
5619 }
5620 fn admit(manager: &RefCell<UdpManager>, port: u16) -> bool {
5623 let mut manager = manager.borrow_mut();
5624 manager.handle_input(
5625 ManagerInput::ClientDatagram {
5626 src: SocketAddr::from(([192, 0, 2, 1], port)),
5627 payload: b"q",
5628 backends: &mut OneBackend,
5629 },
5630 Instant::now(),
5631 );
5632 let mut opened = false;
5633 let mut shed = false;
5634 while let Some(out) = manager.poll_output() {
5635 opened |= matches!(out, Output::OpenUpstream { .. });
5636 shed |= matches!(out, Output::Metric(MetricEvent::FlowShedSourceLimit));
5637 }
5638 assert_ne!(opened, shed, "a datagram is either admitted or shed");
5639 opened
5640 }
5641 fn add_cluster(server: &mut Server, max_connections_per_ip: Option<u64>) {
5642 server.notify_proxys(WorkerRequest {
5643 id: "test-add-cluster".to_owned(),
5644 content: RequestType::AddCluster(Cluster {
5645 cluster_id: "udp-limits".to_owned(),
5646 max_connections_per_ip,
5647 ..Default::default()
5648 })
5649 .into(),
5650 });
5651 }
5652
5653 let mut server = bare_server();
5654 let address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
5655 let token = add_udp_listener(&mut server, address);
5656 server.notify(WorkerRequest {
5657 id: "test-set-per-ip".to_owned(),
5658 content: RequestType::SetMaxConnectionsPerIp(1).into(),
5659 });
5660 server.notify(WorkerRequest {
5661 id: "test-set-per-subnet".to_owned(),
5662 content: RequestType::SetMaxConnectionsPerSubnet(1).into(),
5663 });
5664 add_cluster(&mut server, None);
5665 server.notify_proxys(WorkerRequest {
5666 id: "test-add-udp-front".to_owned(),
5667 content: RequestType::AddUdpFrontend(RequestUdpFrontend {
5668 cluster_id: "udp-limits".to_owned(),
5669 address,
5670 tags: Default::default(),
5671 })
5672 .into(),
5673 });
5674 let manager = server
5675 .udp
5676 .borrow()
5677 .manager(token)
5678 .expect("the UDP listener must own a flow manager");
5679
5680 {
5681 let manager = manager.borrow();
5682 let cfg = manager.cluster_config();
5683 assert_eq!(
5684 cfg.max_flows_per_ip, 0,
5685 "the global per-IP default must not apply to UDP"
5686 );
5687 assert_eq!(
5688 cfg.max_flows_per_subnet, 0,
5689 "the global per-subnet default must not apply to UDP"
5690 );
5691 }
5692 assert!(admit(&manager, 1000));
5693 assert!(
5694 admit(&manager, 1001),
5695 "a global limit of 1 must not shed a second UDP flow"
5696 );
5697
5698 add_cluster(&mut server, Some(2));
5699 assert_eq!(manager.borrow().cluster_config().max_flows_per_ip, 2);
5700 assert!(
5701 !admit(&manager, 1002),
5702 "the cluster's own limit of 2 counts the two open flows and sheds a third"
5703 );
5704 }
5705}
5706
5707#[cfg(test)]
5708mod add_cluster_validation_tests {
5709 use sozu_command::proto::command::{LoadBalancingParams, ShardMode};
5710
5711 use super::listener_lifecycle_tests::bare_server;
5712 use super::*;
5713 use crate::{backends::ShardOutcome, load_balancing::affinity_key_from_ip};
5714
5715 const CLUSTER: &str = "sharded";
5716 const ADD_CLUSTER_ID: &str = "test-add-invalid-shard";
5717
5718 #[test]
5728 fn an_add_cluster_with_an_invalid_shard_percent_is_refused_and_unsharded() {
5729 let mut server = bare_server();
5730 server.notify_proxys(WorkerRequest {
5731 id: ADD_CLUSTER_ID.to_owned(),
5732 content: RequestType::AddCluster(Cluster {
5733 cluster_id: CLUSTER.to_owned(),
5734 load_balancing: LoadBalancingAlgorithms::RoundRobin as i32,
5735 shard_percent: Some(0),
5738 shard_min_backends: Some(2),
5739 shard_mode: Some(ShardMode::Strict as i32),
5740 ..Default::default()
5741 })
5742 .into(),
5743 });
5744 let response = QUEUE
5745 .with(|queue| {
5746 queue
5747 .borrow()
5748 .iter()
5749 .find(|response| response.id == ADD_CLUSTER_ID)
5750 .cloned()
5751 })
5752 .expect("the worker must answer the AddCluster");
5753 assert_eq!(
5754 response.status,
5755 ResponseStatus::Failure as i32,
5756 "an invalid shard_percent must be refused: {response:?}"
5757 );
5758 assert_eq!(response.message, "shard_percent must lie in 1..=100");
5759
5760 for index in 0..4u16 {
5761 server.notify_proxys(WorkerRequest {
5762 id: format!("test-add-backend-{index}"),
5763 content: RequestType::AddBackend(AddBackend {
5764 cluster_id: CLUSTER.to_owned(),
5765 backend_id: format!("{CLUSTER}-{index}"),
5766 address: SocketAddr::from(([127, 0, 0, 1], 23_000 + index)).into(),
5767 load_balancing_parameters: Some(LoadBalancingParams::default()),
5768 sticky_id: None,
5769 backup: None,
5770 })
5771 .into(),
5772 });
5773 }
5774 let key = affinity_key_from_ip(IpAddr::V4(Ipv4Addr::LOCALHOST));
5775 let mut backends = server.backends.borrow_mut();
5776 let list = backends
5777 .backends
5778 .get_mut(CLUSTER)
5779 .expect("the backends must have created the cluster's list");
5780 assert_eq!(
5781 list.select_with_key(Some(key), Instant::now()).1,
5782 ShardOutcome::Unsharded,
5783 "a refused AddCluster must not arm a shard"
5784 );
5785 }
5786}
5787
5788#[cfg(test)]
5791mod remove_health_check_tests {
5792 use sozu_command::proto::command::{HealthCheckConfig, LoadBalancingParams};
5793
5794 use super::listener_lifecycle_tests::bare_server;
5795 use super::*;
5796
5797 const CLUSTER: &str = "health-checked";
5798
5799 fn health_check() -> HealthCheckConfig {
5800 HealthCheckConfig {
5801 uri: "/livez".to_owned(),
5802 interval: 1,
5803 timeout: 1,
5804 healthy_threshold: 1,
5805 unhealthy_threshold: 1,
5806 ..Default::default()
5807 }
5808 }
5809
5810 fn add_cluster(server: &mut Server, health_check: Option<HealthCheckConfig>) {
5811 server.notify_proxys(WorkerRequest {
5812 id: "test-add-cluster".to_owned(),
5813 content: RequestType::AddCluster(Cluster {
5814 cluster_id: CLUSTER.to_owned(),
5815 health_check,
5816 ..Default::default()
5817 })
5818 .into(),
5819 });
5820 }
5821
5822 fn server_with_down_backend() -> Server {
5825 let mut server = bare_server();
5826 add_cluster(&mut server, Some(health_check()));
5827 server.notify_proxys(WorkerRequest {
5828 id: "test-add-backend".to_owned(),
5829 content: RequestType::AddBackend(AddBackend {
5830 cluster_id: CLUSTER.to_owned(),
5831 backend_id: format!("{CLUSTER}-0"),
5832 address: SocketAddr::from(([127, 0, 0, 1], 23_100)).into(),
5833 load_balancing_parameters: Some(LoadBalancingParams::default()),
5834 sticky_id: None,
5835 backup: None,
5836 })
5837 .into(),
5838 });
5839 server.backends.borrow().backends[CLUSTER].backends[0]
5840 .borrow_mut()
5841 .health
5842 .record_failure(1);
5843 assert!(!backend_is_healthy(&server), "test setup: backend DOWN");
5844 server
5845 }
5846
5847 fn backend_is_healthy(server: &Server) -> bool {
5848 server.backends.borrow().backends[CLUSTER].backends[0]
5849 .borrow()
5850 .health
5851 .is_healthy()
5852 }
5853
5854 #[test]
5858 fn remove_health_check_resets_a_backend_marked_down() {
5859 let mut server = server_with_down_backend();
5860 server.notify_proxys(WorkerRequest {
5861 id: "test-remove-health-check".to_owned(),
5862 content: RequestType::RemoveHealthCheck(CLUSTER.to_owned()).into(),
5863 });
5864 assert!(
5865 !server
5866 .backends
5867 .borrow()
5868 .health_check_configs
5869 .contains_key(CLUSTER),
5870 "RemoveHealthCheck must forget the cluster's configuration"
5871 );
5872 assert!(
5873 backend_is_healthy(&server),
5874 "RemoveHealthCheck must reset a backend a probe marked DOWN"
5875 );
5876 }
5877
5878 #[test]
5884 fn add_cluster_without_health_check_resets_a_backend_marked_down() {
5885 let mut server = server_with_down_backend();
5886 add_cluster(&mut server, None);
5887 assert!(
5888 !server
5889 .backends
5890 .borrow()
5891 .health_check_configs
5892 .contains_key(CLUSTER),
5893 "an AddCluster without a health check must forget the configuration"
5894 );
5895 assert!(
5896 backend_is_healthy(&server),
5897 "an AddCluster without a health check must reset a backend marked DOWN"
5898 );
5899 }
5900}
5901
5902#[cfg(test)]
5909mod remove_cluster_cascade_tests {
5910 use sozu_command::{
5911 config::ListenerBuilder,
5912 proto::command::{
5913 LoadBalancingParams, PathRule, RequestHttpFrontend, RequestTcpFrontend,
5914 RequestUdpFrontend, RulePosition, SocketAddress,
5915 },
5916 };
5917
5918 use super::listener_lifecycle_tests::bare_server;
5919 use super::*;
5920 use crate::{L7ListenerHandler, protocol::http::parser::Method, testing::provide_port};
5921
5922 const REMOVED: &str = "cascade_removed";
5923 const KEPT: &str = "cascade_kept";
5924
5925 fn send(server: &mut Server, id: &str, request: RequestType) -> Vec<WorkerResponse> {
5929 server.notify_proxys(WorkerRequest {
5930 id: id.to_owned(),
5931 content: request.into(),
5932 });
5933 QUEUE.with(|queue| {
5934 queue
5935 .borrow_mut()
5936 .drain(..)
5937 .filter(|response| response.id != "EVENT")
5938 .collect()
5939 })
5940 }
5941
5942 fn http_front(cluster_id: Option<&str>, hostname: &str, path: &str) -> RequestHttpFrontend {
5943 RequestHttpFrontend {
5944 cluster_id: cluster_id.map(str::to_owned),
5945 hostname: hostname.to_owned(),
5946 path: PathRule::prefix(path.to_owned()),
5947 address: SocketAddress::new_v4(127, 0, 0, 1, 0),
5948 ..Default::default()
5949 }
5950 }
5951
5952 fn backend(cluster_id: &str, port: u16) -> AddBackend {
5953 AddBackend {
5954 cluster_id: cluster_id.to_owned(),
5955 backend_id: format!("{cluster_id}-0"),
5956 address: SocketAddress::new_v4(127, 0, 0, 1, port),
5957 load_balancing_parameters: Some(LoadBalancingParams::default()),
5958 ..Default::default()
5959 }
5960 }
5961
5962 #[test]
5973 fn remove_then_readd_same_cluster_id_preserves_and_releases_live_admission_leases() {
5974 let mut server = bare_server();
5975 let cluster_id = ClusterId::from(REMOVED);
5976 let source: IpAddr = "203.0.113.9".parse().expect("test address must parse");
5977 let subnet = server.sessions.borrow().subnet_key(&source);
5978 let old_token = Token(60_001);
5979 let new_token = Token(60_002);
5980
5981 for response in send(
5982 &mut server,
5983 "add-old-incarnation",
5984 RequestType::AddCluster(Cluster {
5985 cluster_id: REMOVED.to_owned(),
5986 max_connections_per_ip: Some(2),
5987 max_connections_per_subnet: Some(2),
5988 ..Default::default()
5989 }),
5990 ) {
5991 assert_eq!(response.status, ResponseStatus::Ok as i32);
5992 }
5993 server.sessions.borrow_mut().track_cluster_connection(
5994 old_token,
5995 cluster_id.clone(),
5996 source,
5997 Some(2),
5998 );
5999
6000 for response in send(
6001 &mut server,
6002 "remove-old-incarnation",
6003 RequestType::RemoveCluster(REMOVED.to_owned()),
6004 ) {
6005 assert_eq!(response.status, ResponseStatus::Ok as i32);
6006 }
6007 for response in send(
6008 &mut server,
6009 "add-new-incarnation",
6010 RequestType::AddCluster(Cluster {
6011 cluster_id: REMOVED.to_owned(),
6012 max_connections_per_ip: Some(2),
6013 max_connections_per_subnet: Some(2),
6014 ..Default::default()
6015 }),
6016 ) {
6017 assert_eq!(response.status, ResponseStatus::Ok as i32);
6018 }
6019
6020 {
6021 let mut sessions = server.sessions.borrow_mut();
6022 assert_eq!(sessions.connections_per_cluster_ip[REMOVED][&source], 1);
6023 assert_eq!(sessions.connections_per_cluster_subnet[REMOVED][&subnet], 1);
6024 sessions.track_cluster_connection(new_token, cluster_id, source, Some(2));
6025 assert_eq!(sessions.connections_per_cluster_ip[REMOVED][&source], 2);
6026 assert_eq!(sessions.connections_per_cluster_subnet[REMOVED][&subnet], 2);
6027
6028 sessions.untrack_all_cluster_ip(old_token);
6029 assert_eq!(sessions.connections_per_cluster_ip[REMOVED][&source], 1);
6030 assert_eq!(sessions.connections_per_cluster_subnet[REMOVED][&subnet], 1);
6031 assert!(sessions.cluster_ip_tracks.contains_key(&new_token));
6032 assert!(sessions.cluster_subnet_tracks.contains_key(&new_token));
6033
6034 sessions.untrack_all_cluster_ip(new_token);
6035 assert!(!sessions.connections_per_cluster_ip.contains_key(REMOVED));
6036 assert!(
6037 !sessions
6038 .connections_per_cluster_subnet
6039 .contains_key(REMOVED)
6040 );
6041 }
6042 }
6043
6044 fn http_route(
6048 server: &Server,
6049 address: SocketAddress,
6050 hostname: &str,
6051 path: &str,
6052 ) -> Option<Option<String>> {
6053 let http = server.http.borrow();
6054 let token = http
6055 .listener_token(&SocketAddr::from(address).into())
6056 .expect("the test HTTP listener must own a token");
6057 let listener = http
6058 .get_listener(&token)
6059 .expect("the test HTTP listener must exist");
6060 listener
6061 .borrow()
6062 .frontend_from_request(hostname, path, &Method::Get)
6063 .ok()
6064 .map(|route| route.cluster_id.map(|id| id.to_string()))
6065 }
6066
6067 #[test]
6074 fn remove_cluster_removes_its_routes_and_backends_from_the_worker() {
6075 let mut server = bare_server();
6076 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6077 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6078
6079 let mut removed_front = http_front(Some(REMOVED), "removed.test", "/");
6080 removed_front.address = http_address;
6081 removed_front.position = RulePosition::Pre.into();
6084 let mut deny_front = http_front(None, "removed.test", "/deny");
6085 deny_front.address = http_address;
6086 let mut kept_front = http_front(Some(KEPT), "kept.test", "/");
6087 kept_front.address = http_address;
6088 let removed_tcp_front = RequestTcpFrontend {
6089 cluster_id: REMOVED.to_owned(),
6090 address: tcp_address,
6091 ..Default::default()
6092 };
6093
6094 let setup = vec![
6095 RequestType::AddHttpListener(
6096 ListenerBuilder::new_http(http_address)
6097 .to_http(None)
6098 .expect("could not build the test HTTP listener config"),
6099 ),
6100 RequestType::AddTcpListener(
6101 ListenerBuilder::new_tcp(tcp_address)
6102 .to_tcp(None)
6103 .expect("could not build the test TCP listener config"),
6104 ),
6105 RequestType::AddCluster(Cluster {
6106 cluster_id: REMOVED.to_owned(),
6107 ..Default::default()
6108 }),
6109 RequestType::AddCluster(Cluster {
6110 cluster_id: KEPT.to_owned(),
6111 ..Default::default()
6112 }),
6113 RequestType::AddHttpFrontend(removed_front.clone()),
6114 RequestType::AddHttpFrontend(deny_front),
6115 RequestType::AddHttpFrontend(kept_front),
6116 RequestType::AddTcpFrontend(removed_tcp_front.clone()),
6117 RequestType::AddBackend(backend(REMOVED, 1026)),
6118 RequestType::AddBackend(backend(KEPT, 1027)),
6119 ];
6120 for (index, request) in setup.into_iter().enumerate() {
6121 for response in send(&mut server, &format!("setup-{index}"), request) {
6122 assert_eq!(
6123 response.status,
6124 ResponseStatus::Ok as i32,
6125 "setup must succeed: {response:?}"
6126 );
6127 }
6128 }
6129 assert_eq!(
6130 http_route(&server, http_address, "removed.test", "/"),
6131 Some(Some(REMOVED.to_owned())),
6132 "premise: the removed cluster's hostname routes to it"
6133 );
6134
6135 let responses = send(
6136 &mut server,
6137 "remove-cluster",
6138 RequestType::RemoveCluster(REMOVED.to_owned()),
6139 );
6140 assert_eq!(
6141 responses.iter().map(|r| r.id.as_str()).collect::<Vec<_>>(),
6142 vec!["remove-cluster"],
6143 "the worker must answer the RemoveCluster exactly once: {responses:?}"
6144 );
6145 assert_eq!(
6146 responses[0].status,
6147 ResponseStatus::Ok as i32,
6148 "RemoveCluster must succeed: {responses:?}"
6149 );
6150
6151 assert_eq!(
6152 http_route(&server, http_address, "removed.test", "/"),
6153 None,
6154 "the removed cluster's hostname must no longer route"
6155 );
6156 assert_eq!(
6157 http_route(&server, http_address, "removed.test", "/deny"),
6158 Some(None),
6159 "a route that names no cluster must survive the removal of a cluster on its hostname"
6160 );
6161 assert_eq!(
6162 http_route(&server, http_address, "kept.test", "/"),
6163 Some(Some(KEPT.to_owned())),
6164 "another cluster's route must stay"
6165 );
6166 let backends = server.backends.borrow();
6167 assert!(
6168 !backends.backends.contains_key(REMOVED),
6169 "the removed cluster's backends must be gone from the BackendMap"
6170 );
6171 assert!(
6172 backends.backends.contains_key(KEPT),
6173 "another cluster's backends must stay"
6174 );
6175 drop(backends);
6176
6177 for (index, request) in [
6178 RequestType::RemoveHttpFrontend(removed_front),
6179 RequestType::RemoveTcpFrontend(removed_tcp_front),
6180 RequestType::RemoveBackend(RemoveBackend {
6181 cluster_id: REMOVED.to_owned(),
6182 backend_id: format!("{REMOVED}-0"),
6183 address: SocketAddress::new_v4(127, 0, 0, 1, 1026),
6184 }),
6185 ]
6186 .into_iter()
6187 .enumerate()
6188 {
6189 let responses = send(&mut server, &format!("follow-up-{index}"), request);
6190 assert!(
6191 !responses.is_empty()
6192 && responses
6193 .iter()
6194 .all(|r| r.status == ResponseStatus::Ok as i32),
6195 "a removal the cascade already performed must answer ok: {responses:?}"
6196 );
6197 }
6198 }
6199
6200 #[test]
6205 fn a_stale_frontend_removal_never_removes_another_clusters_route() {
6206 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6207 let route = |cluster_id: &str| {
6208 let mut front = http_front(Some(cluster_id), "reused.test", "/");
6209 front.address = http_address;
6210 front
6211 };
6212 let cluster = |cluster_id: &str| {
6213 RequestType::AddCluster(Cluster {
6214 cluster_id: cluster_id.to_owned(),
6215 ..Default::default()
6216 })
6217 };
6218 let listener = || {
6219 RequestType::AddHttpListener(
6220 ListenerBuilder::new_http(http_address)
6221 .to_http(None)
6222 .expect("could not build the test HTTP listener config"),
6223 )
6224 };
6225
6226 for (a_is_gone, setup, expected_status) in [
6227 (
6228 true,
6229 vec![
6230 listener(),
6231 cluster("stale_a"),
6232 RequestType::AddHttpFrontend(route("stale_a")),
6233 RequestType::RemoveCluster("stale_a".to_owned()),
6234 cluster("stale_b"),
6235 RequestType::AddHttpFrontend(route("stale_b")),
6236 ],
6237 ResponseStatus::Ok,
6238 ),
6239 (
6240 false,
6241 vec![
6242 listener(),
6243 cluster("stale_a"),
6244 cluster("stale_b"),
6245 RequestType::AddHttpFrontend(route("stale_b")),
6246 ],
6247 ResponseStatus::Failure,
6248 ),
6249 ] {
6250 let mut server = bare_server();
6251 for (index, request) in setup.into_iter().enumerate() {
6252 for response in send(&mut server, &format!("setup-{index}"), request) {
6253 assert_eq!(
6254 response.status,
6255 ResponseStatus::Ok as i32,
6256 "setup must succeed: {response:?}"
6257 );
6258 }
6259 }
6260 assert_eq!(
6261 http_route(&server, http_address, "reused.test", "/"),
6262 Some(Some("stale_b".to_owned())),
6263 "premise: cluster B owns the route"
6264 );
6265
6266 let responses = send(
6267 &mut server,
6268 "stale-removal",
6269 RequestType::RemoveHttpFrontend(route("stale_a")),
6270 );
6271 assert_eq!(
6272 responses.iter().map(|r| r.status).collect::<Vec<_>>(),
6273 vec![expected_status as i32],
6274 "A gone: {a_is_gone}, answers: {responses:?}"
6275 );
6276 assert_eq!(
6277 http_route(&server, http_address, "reused.test", "/"),
6278 Some(Some("stale_b".to_owned())),
6279 "cluster B's route must survive a stale removal naming cluster A (A gone: {a_is_gone})"
6280 );
6281 }
6282 }
6283
6284 #[test]
6290 fn a_stale_tcp_or_udp_frontend_removal_never_unmaps_another_clusters_listener() {
6291 let cluster = |cluster_id: &str| {
6292 RequestType::AddCluster(Cluster {
6293 cluster_id: cluster_id.to_owned(),
6294 ..Default::default()
6295 })
6296 };
6297 for udp in [false, true] {
6298 let x = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6299 let y = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6300 let listener = |address: SocketAddress| {
6301 if udp {
6302 RequestType::AddUdpListener(
6303 ListenerBuilder::new_udp(address)
6304 .to_udp(None)
6305 .expect("could not build the test UDP listener config"),
6306 )
6307 } else {
6308 RequestType::AddTcpListener(
6309 ListenerBuilder::new_tcp(address)
6310 .to_tcp(None)
6311 .expect("could not build the test TCP listener config"),
6312 )
6313 }
6314 };
6315 let front = |cluster_id: &str, address: SocketAddress| {
6316 if udp {
6317 (
6318 RequestType::AddUdpFrontend(RequestUdpFrontend {
6319 cluster_id: cluster_id.to_owned(),
6320 address,
6321 ..Default::default()
6322 }),
6323 RequestType::RemoveUdpFrontend(RequestUdpFrontend {
6324 cluster_id: cluster_id.to_owned(),
6325 address,
6326 ..Default::default()
6327 }),
6328 )
6329 } else {
6330 (
6331 RequestType::AddTcpFrontend(RequestTcpFrontend {
6332 cluster_id: cluster_id.to_owned(),
6333 address,
6334 ..Default::default()
6335 }),
6336 RequestType::RemoveTcpFrontend(RequestTcpFrontend {
6337 cluster_id: cluster_id.to_owned(),
6338 address,
6339 ..Default::default()
6340 }),
6341 )
6342 }
6343 };
6344 let owner = |server: &Server| {
6345 let key = SocketAddr::from(x).into();
6346 if udp {
6347 server.udp.borrow().listener_cluster(&key)
6348 } else {
6349 server.tcp.borrow().listener_cluster(&key)
6350 }
6351 .map(|id| id.to_string())
6352 };
6353
6354 let mut server = bare_server();
6355 for (index, request) in [
6356 listener(x),
6357 listener(y),
6358 cluster("stale_a"),
6359 front("stale_a", x).0,
6360 RequestType::RemoveCluster("stale_a".to_owned()),
6361 cluster("stale_b"),
6362 front("stale_b", x).0,
6363 cluster("stale_a"),
6364 front("stale_a", y).0,
6365 ]
6366 .into_iter()
6367 .enumerate()
6368 {
6369 for response in send(&mut server, &format!("setup-{index}"), request) {
6370 assert_eq!(
6371 response.status,
6372 ResponseStatus::Ok as i32,
6373 "setup must succeed (udp: {udp}): {response:?}"
6374 );
6375 }
6376 }
6377 assert_eq!(
6378 owner(&server).as_deref(),
6379 Some("stale_b"),
6380 "premise: cluster B owns the listener on X (udp: {udp})"
6381 );
6382
6383 let responses = send(&mut server, "stale-removal", front("stale_a", x).1);
6384 assert_eq!(
6385 responses.iter().map(|r| r.status).collect::<Vec<_>>(),
6386 vec![ResponseStatus::Failure as i32],
6387 "the stale removal must be refused (udp: {udp}): {responses:?}"
6388 );
6389 assert_eq!(
6390 owner(&server).as_deref(),
6391 Some("stale_b"),
6392 "cluster B must keep the listener on X after a stale removal naming A (udp: {udp})"
6393 );
6394 }
6395 }
6396}
6397
6398#[cfg(test)]
6399mod scm_listener_handoff_tests {
6400 use std::{
6401 net::{TcpStream as StdTcpStream, UdpSocket as StdUdpSocket},
6402 os::fd::{IntoRawFd, RawFd},
6403 };
6404
6405 use sozu_command::{config::ListenerBuilder, proto::command::SocketAddress};
6406
6407 use super::*;
6408 use crate::{
6409 ProxyError,
6410 socket::{server_bind, udp_bind},
6411 testing::{ServerParts, prebuild_server, provide_port},
6412 };
6413
6414 fn state_with_four_active_listeners(
6417 http_address: SocketAddress,
6418 https_address: SocketAddress,
6419 tcp_address: SocketAddress,
6420 udp_address: SocketAddress,
6421 ) -> ConfigState {
6422 let mut state = ConfigState::new();
6423 let adds: Vec<(Request, SocketAddress, ListenerType)> = vec![
6424 (
6425 RequestType::AddHttpListener(
6426 ListenerBuilder::new_http(http_address)
6427 .to_http(None)
6428 .expect("could not build the test HTTP listener config"),
6429 )
6430 .into(),
6431 http_address,
6432 ListenerType::Http,
6433 ),
6434 (
6435 RequestType::AddHttpsListener(
6436 ListenerBuilder::new_https(https_address)
6437 .to_tls(None)
6438 .expect("could not build the test HTTPS listener config"),
6439 )
6440 .into(),
6441 https_address,
6442 ListenerType::Https,
6443 ),
6444 (
6445 RequestType::AddTcpListener(
6446 ListenerBuilder::new_tcp(tcp_address)
6447 .to_tcp(None)
6448 .expect("could not build the test TCP listener config"),
6449 )
6450 .into(),
6451 tcp_address,
6452 ListenerType::Tcp,
6453 ),
6454 (
6455 RequestType::AddUdpListener(
6456 ListenerBuilder::new_udp(udp_address)
6457 .to_udp(None)
6458 .expect("could not build the test UDP listener config"),
6459 )
6460 .into(),
6461 udp_address,
6462 ListenerType::Udp,
6463 ),
6464 ];
6465 for (add, address, proxy) in adds {
6466 state.dispatch(&add).expect("could not add the listener");
6467 state
6468 .dispatch(
6469 &RequestType::ActivateListener(ActivateListener {
6470 interface: None,
6471 address,
6472 proxy: proxy.into(),
6473 from_scm: false,
6474 })
6475 .into(),
6476 )
6477 .expect("could not mark the listener active");
6478 }
6479 state
6480 }
6481
6482 fn inherited_table<'a>(server: &'a Server, label: &str) -> &'a Vec<(ListenerKey, RawFd)> {
6484 let scm_listeners = server
6485 .scm_listeners
6486 .as_ref()
6487 .expect("scm_listeners must be present");
6488 match label {
6489 "HTTP" => &scm_listeners.http,
6490 "HTTPS" => &scm_listeners.tls,
6491 "TCP" => &scm_listeners.tcp,
6492 "UDP" => &scm_listeners.udp,
6493 other => panic!("unknown protocol label {other}"),
6494 }
6495 }
6496
6497 fn descriptor_is_socket_on_port(fd: RawFd, port: u16) -> bool {
6507 let mut storage: libc::sockaddr_storage = unsafe { std::mem::zeroed() };
6508 let mut length = std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
6509 let result = unsafe {
6513 libc::getsockname(
6514 fd,
6515 (&raw mut storage).cast::<libc::sockaddr>(),
6516 &raw mut length,
6517 )
6518 };
6519 if result != 0 || storage.ss_family != libc::AF_INET as libc::sa_family_t {
6520 return false;
6521 }
6522 let inet = unsafe { &*(&raw const storage).cast::<libc::sockaddr_in>() };
6525 u16::from_be(inet.sin_port) == port
6526 }
6527
6528 const QUEUED_DATAGRAM: &[u8] = b"queued-before-the-handoff";
6530
6531 #[test]
6561 fn inherited_listener_sockets_are_adopted_by_the_initial_activation() {
6562 let ServerParts {
6563 event_loop,
6564 sessions,
6565 pool,
6566 backends,
6567 client_scm_socket,
6568 server_scm_socket,
6569 server_config,
6570 ..
6571 } = prebuild_server(16, 16384, false).expect("could not prebuild a test server");
6572 let (_command_channel, proxy_channel) =
6573 Channel::generate(1000, 10000).expect("could not generate a test channel");
6574
6575 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6576 let https_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6577 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6578 let udp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6579
6580 let http_listener = server_bind(http_address.into(), None)
6583 .expect("could not bind the inherited HTTP socket");
6584 let https_listener = server_bind(https_address.into(), None)
6585 .expect("could not bind the inherited HTTPS socket");
6586 let tcp_listener =
6587 server_bind(tcp_address.into(), None).expect("could not bind the inherited TCP socket");
6588 let udp_socket =
6589 udp_bind(udp_address.into(), None).expect("could not bind the inherited UDP socket");
6590
6591 let http_client = StdTcpStream::connect::<SocketAddr>(http_address.into())
6596 .expect("could not queue a connection on the inherited HTTP socket");
6597 let https_client = StdTcpStream::connect::<SocketAddr>(https_address.into())
6598 .expect("could not queue a connection on the inherited HTTPS socket");
6599 let tcp_client = StdTcpStream::connect::<SocketAddr>(tcp_address.into())
6600 .expect("could not queue a connection on the inherited TCP socket");
6601 let datagram_sender =
6602 StdUdpSocket::bind("127.0.0.1:0").expect("could not bind the test datagram sender");
6603 datagram_sender
6604 .send_to(QUEUED_DATAGRAM, SocketAddr::from(udp_address))
6605 .expect("could not queue a datagram on the inherited UDP socket");
6606
6607 let listeners = Listeners {
6610 http: vec![(http_address.into(), http_listener.into_raw_fd())],
6611 tls: vec![(https_address.into(), https_listener.into_raw_fd())],
6612 tcp: vec![(tcp_address.into(), tcp_listener.into_raw_fd())],
6613 udp: vec![(udp_address.into(), udp_socket.into_raw_fd())],
6614 };
6615 client_scm_socket
6616 .send_listeners(&listeners)
6617 .expect("could not send the inherited listeners");
6618 listeners.close();
6619
6620 let initial_state =
6626 state_with_four_active_listeners(http_address, https_address, tcp_address, udp_address)
6627 .produce_initial_state();
6628 assert_eq!(
6629 initial_state.requests.len(),
6630 8,
6631 "the generator must emit one Add and one Activate per active listener"
6632 );
6633
6634 let server = Server::new(
6635 event_loop,
6636 proxy_channel,
6637 server_scm_socket,
6638 sessions,
6639 pool,
6640 backends,
6641 None,
6642 None,
6643 None,
6644 server_config,
6645 Some(initial_state),
6646 false,
6647 )
6648 .expect("could not build the test server");
6649
6650 let accepted: Vec<Protocol> = server
6651 .accept_queue
6652 .iter()
6653 .map(|(_, _, protocol, _, _)| *protocol)
6654 .collect();
6655 assert!(
6656 accepted.contains(&Protocol::HTTPListen),
6657 "the connection queued on the inherited HTTP socket must survive the hand-off, got {accepted:?}"
6658 );
6659 assert!(
6660 accepted.contains(&Protocol::HTTPSListen),
6661 "the connection queued on the inherited HTTPS socket must survive the hand-off, got {accepted:?}"
6662 );
6663 assert!(
6664 accepted.contains(&Protocol::TCPListen),
6665 "the connection queued on the inherited TCP socket must survive the hand-off, got {accepted:?}"
6666 );
6667
6668 for (protocol, client) in [
6676 (Protocol::HTTPListen, &http_client),
6677 (Protocol::HTTPSListen, &https_client),
6678 (Protocol::TCPListen, &tcp_client),
6679 ] {
6680 let (sock, _, _, _, peer) = server
6681 .accept_queue
6682 .iter()
6683 .find(|(_, _, queued, _, _)| *queued == protocol)
6684 .expect("the queued connection was asserted above");
6685 assert_eq!(
6686 socket2::SockRef::from(sock).tcp_nodelay().ok(),
6687 Some(true),
6688 "a {protocol:?} connection queued before the hand-off must carry TCP_NODELAY"
6689 );
6690 assert_eq!(
6691 *peer,
6692 client.local_addr().expect("the test client has an address"),
6693 "the {protocol:?} peer address must be the client's"
6694 );
6695 }
6696
6697 let (_, adopted_udp_socket) = server
6698 .udp
6699 .borrow_mut()
6700 .give_back_listeners()
6701 .pop()
6702 .expect("the UDP listener must hold a socket after activation");
6703 let mut buffer = [0u8; 64];
6704 let received = adopted_udp_socket.recv_from(&mut buffer);
6705 match received {
6706 Ok((length, _)) => assert_eq!(
6707 &buffer[..length],
6708 QUEUED_DATAGRAM,
6709 "the datagram queued on the inherited UDP socket must survive the hand-off"
6710 ),
6711 Err(error) => panic!(
6712 "the datagram queued on the inherited UDP socket must survive the hand-off, got {error:?}"
6713 ),
6714 }
6715 }
6716
6717 #[test]
6741 fn a_repeated_activation_closes_the_descriptor_it_cannot_adopt_now() {
6742 let ServerParts {
6743 event_loop,
6744 sessions,
6745 pool,
6746 backends,
6747 server_scm_socket,
6748 server_config,
6749 ..
6750 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
6751 let (_command_channel, proxy_channel) =
6752 Channel::generate(1000, 10000).expect("could not generate a test channel");
6753
6754 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6755 let https_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6756 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6757 let udp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6758
6759 let initial_state =
6762 state_with_four_active_listeners(http_address, https_address, tcp_address, udp_address)
6763 .produce_initial_state();
6764 let mut server = Server::new(
6765 event_loop,
6766 proxy_channel,
6767 server_scm_socket,
6768 sessions,
6769 pool,
6770 backends,
6771 None,
6772 None,
6773 None,
6774 server_config,
6775 Some(initial_state),
6776 false,
6777 )
6778 .expect("could not build the test server");
6779
6780 let http_fd = server_bind(http_address.into(), None)
6782 .expect("could not bind the spare HTTP socket")
6783 .into_raw_fd();
6784 let https_fd = server_bind(https_address.into(), None)
6785 .expect("could not bind the spare HTTPS socket")
6786 .into_raw_fd();
6787 let tcp_fd = server_bind(tcp_address.into(), None)
6788 .expect("could not bind the spare TCP socket")
6789 .into_raw_fd();
6790 let udp_fd = udp_bind(udp_address.into(), None)
6791 .expect("could not bind the spare UDP socket")
6792 .into_raw_fd();
6793 {
6794 let scm_listeners = server
6795 .scm_listeners
6796 .as_mut()
6797 .expect("Server::new must have populated scm_listeners");
6798 scm_listeners.http.push((http_address.into(), http_fd));
6799 scm_listeners.tls.push((https_address.into(), https_fd));
6800 scm_listeners.tcp.push((tcp_address.into(), tcp_fd));
6801 scm_listeners.udp.push((udp_address.into(), udp_fd));
6802 }
6803
6804 for (address, proxy) in [
6805 (http_address, ListenerType::Http),
6806 (https_address, ListenerType::Https),
6807 (tcp_address, ListenerType::Tcp),
6808 (udp_address, ListenerType::Udp),
6809 ] {
6810 let response = server.notify_activate_listener(
6811 "test-repeat",
6812 &ActivateListener {
6813 interface: None,
6814 address,
6815 proxy: proxy.into(),
6816 from_scm: false,
6817 },
6818 );
6819 assert_eq!(
6820 response.status,
6821 ResponseStatus::Ok as i32,
6822 "a repeated {proxy:?} activation must still answer ok: {response:?}"
6823 );
6824 }
6825
6826 let scm_listeners = server
6827 .scm_listeners
6828 .as_ref()
6829 .expect("scm_listeners must still be present");
6830 for (label, table, fd, port) in [
6831 (
6832 "HTTP",
6833 &scm_listeners.http,
6834 http_fd,
6835 http_address.port as u16,
6836 ),
6837 (
6838 "HTTPS",
6839 &scm_listeners.tls,
6840 https_fd,
6841 https_address.port as u16,
6842 ),
6843 ("TCP", &scm_listeners.tcp, tcp_fd, tcp_address.port as u16),
6844 ("UDP", &scm_listeners.udp, udp_fd, udp_address.port as u16),
6845 ] {
6846 assert!(
6847 !table.iter().any(|(_, entry)| *entry == fd),
6848 "the inherited {label} descriptor this activation cannot adopt must leave the SCM table"
6849 );
6850 assert!(
6851 !descriptor_is_socket_on_port(fd, port),
6852 "the inherited {label} descriptor this activation cannot adopt must be closed, \
6853 not left bound in the address's SO_REUSEPORT group, where it is expected — \
6854 inferred, not measured here — to go on taking a share of new connections"
6855 );
6856 }
6857 }
6858
6859 #[test]
6876 fn an_inherited_descriptor_with_no_listener_yet_is_adopted_by_a_later_activation() {
6877 let ServerParts {
6878 event_loop,
6879 sessions,
6880 pool,
6881 backends,
6882 server_scm_socket,
6883 server_config,
6884 ..
6885 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
6886 let (_command_channel, proxy_channel) =
6887 Channel::generate(1000, 10000).expect("could not generate a test channel");
6888
6889 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6890 let https_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6891 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6892 let udp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
6893
6894 let mut server = Server::new(
6895 event_loop,
6896 proxy_channel,
6897 server_scm_socket,
6898 sessions,
6899 pool,
6900 backends,
6901 None,
6902 None,
6903 None,
6904 server_config,
6905 None,
6906 false,
6907 )
6908 .expect("could not build the test server");
6909
6910 let http_listener = server_bind(http_address.into(), None)
6914 .expect("could not bind the inherited HTTP socket");
6915 let https_listener = server_bind(https_address.into(), None)
6916 .expect("could not bind the inherited HTTPS socket");
6917 let tcp_listener =
6918 server_bind(tcp_address.into(), None).expect("could not bind the inherited TCP socket");
6919 let udp_socket =
6920 udp_bind(udp_address.into(), None).expect("could not bind the inherited UDP socket");
6921 let _http_client = StdTcpStream::connect::<SocketAddr>(http_address.into())
6922 .expect("could not queue a connection on the inherited HTTP socket");
6923 let _https_client = StdTcpStream::connect::<SocketAddr>(https_address.into())
6924 .expect("could not queue a connection on the inherited HTTPS socket");
6925 let _tcp_client = StdTcpStream::connect::<SocketAddr>(tcp_address.into())
6926 .expect("could not queue a connection on the inherited TCP socket");
6927 let (http_fd, https_fd, tcp_fd, udp_fd) = (
6928 http_listener.into_raw_fd(),
6929 https_listener.into_raw_fd(),
6930 tcp_listener.into_raw_fd(),
6931 udp_socket.into_raw_fd(),
6932 );
6933 {
6934 let scm_listeners = server
6935 .scm_listeners
6936 .as_mut()
6937 .expect("Server::new must have populated scm_listeners");
6938 scm_listeners.http.push((http_address.into(), http_fd));
6939 scm_listeners.tls.push((https_address.into(), https_fd));
6940 scm_listeners.tcp.push((tcp_address.into(), tcp_fd));
6941 scm_listeners.udp.push((udp_address.into(), udp_fd));
6942 }
6943
6944 let add_requests =
6945 state_with_four_active_listeners(http_address, https_address, tcp_address, udp_address);
6946 let cases = [
6947 ("HTTP", http_address, ListenerType::Http, http_fd),
6948 ("HTTPS", https_address, ListenerType::Https, https_fd),
6949 ("TCP", tcp_address, ListenerType::Tcp, tcp_fd),
6950 ("UDP", udp_address, ListenerType::Udp, udp_fd),
6951 ];
6952
6953 for (label, address, proxy, fd) in cases {
6956 let response = server.notify_activate_listener(
6957 "test-early",
6958 &ActivateListener {
6959 interface: None,
6960 address,
6961 proxy: proxy.into(),
6962 from_scm: false,
6963 },
6964 );
6965 assert_ne!(
6966 response.status,
6967 ResponseStatus::Ok as i32,
6968 "activating {label} with no listener must fail: {response:?}"
6969 );
6970 assert!(
6971 inherited_table(&server, label)
6972 .iter()
6973 .any(|(_, e)| *e == fd),
6974 "the {label} descriptor must stay in the SCM table while no listener owns \
6975 its address"
6976 );
6977 assert!(
6978 descriptor_is_socket_on_port(fd, address.port as u16),
6979 "the {label} descriptor must stay open while no listener owns its address"
6980 );
6981 }
6982
6983 for request in add_requests.produce_initial_state().requests {
6986 server.notify_proxys(request);
6987 }
6988 for (label, _address, _proxy, fd) in cases {
6989 assert!(
6990 !inherited_table(&server, label)
6991 .iter()
6992 .any(|(_, e)| *e == fd),
6993 "the retained {label} descriptor must be adopted by the later activation"
6994 );
6995 }
6996 let accepted: Vec<Protocol> = server
6997 .accept_queue
6998 .iter()
6999 .map(|(_, _, protocol, _, _)| *protocol)
7000 .collect();
7001 for expected in [
7002 Protocol::HTTPListen,
7003 Protocol::HTTPSListen,
7004 Protocol::TCPListen,
7005 ] {
7006 assert!(
7007 accepted.contains(&expected),
7008 "the connection queued on the retained {expected:?} descriptor must be served \
7009 by the later activation, got {accepted:?}"
7010 );
7011 }
7012 }
7013
7014 #[test]
7039 fn a_socket_parked_by_a_failed_registration_is_not_mistaken_for_a_live_one() {
7040 let ServerParts {
7041 registry,
7042 sessions,
7043 pool,
7044 backends,
7045 ..
7046 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
7047
7048 let token_for = |protocol: Protocol| {
7049 let mut manager = sessions.borrow_mut();
7050 let entry = manager.slab.vacant_entry();
7051 let token = Token(entry.key());
7052 entry.insert(Rc::new(RefCell::new(ListenSession { protocol })));
7053 token
7054 };
7055 let pre_registered = |address: SocketAddress| {
7058 let mut socket = server_bind(address.into(), None)
7059 .expect("could not bind the test listening socket");
7060 registry
7061 .register(&mut socket, Token(usize::MAX - 2), Interest::READABLE)
7062 .expect("could not pre-register the test socket");
7063 socket
7064 };
7065
7066 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7067 let mut http_proxy = http::HttpProxy::new(
7068 registry.try_clone().expect("could not clone the registry"),
7069 sessions.clone(),
7070 pool.clone(),
7071 backends.clone(),
7072 );
7073 http_proxy
7074 .add_listener(
7075 ListenerBuilder::new_http(http_address)
7076 .to_http(None)
7077 .expect("could not build the test HTTP listener config"),
7078 token_for(Protocol::HTTPListen),
7079 )
7080 .expect("could not add the test HTTP listener");
7081 assert!(
7082 http_proxy
7083 .activate_listener(&http_address.into(), Some(pre_registered(http_address)))
7084 .is_err(),
7085 "the pre-registered descriptor must make the HTTP registration fail"
7086 );
7087 assert!(
7088 matches!(
7089 http_proxy.give_back_listener(&http_address.into()),
7090 Err(ProxyError::UnactivatedListener)
7091 ),
7092 "an HTTP listener holding only a parked socket must not answer as activated"
7093 );
7094 assert!(
7095 http_proxy.soft_stop().is_ok(),
7096 "a parked socket must not fail an HTTP soft stop"
7097 );
7098
7099 let https_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7100 let mut https_proxy = https::HttpsProxy::new(
7101 registry.try_clone().expect("could not clone the registry"),
7102 sessions.clone(),
7103 pool.clone(),
7104 backends.clone(),
7105 );
7106 https_proxy
7107 .add_listener(
7108 ListenerBuilder::new_https(https_address)
7109 .to_tls(None)
7110 .expect("could not build the test HTTPS listener config"),
7111 token_for(Protocol::HTTPSListen),
7112 )
7113 .expect("could not add the test HTTPS listener");
7114 assert!(
7115 https_proxy
7116 .activate_listener(&https_address.into(), Some(pre_registered(https_address)))
7117 .is_err(),
7118 "the pre-registered descriptor must make the HTTPS registration fail"
7119 );
7120 assert!(
7121 matches!(
7122 https_proxy.give_back_listener(&https_address.into()),
7123 Err(ProxyError::UnactivatedListener)
7124 ),
7125 "an HTTPS listener holding only a parked socket must not answer as activated"
7126 );
7127 assert!(
7128 https_proxy.hard_stop().is_ok(),
7129 "a parked socket must not fail an HTTPS hard stop"
7130 );
7131
7132 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7133 let mut tcp_proxy = tcp::TcpProxy::new(
7134 registry.try_clone().expect("could not clone the registry"),
7135 sessions.clone(),
7136 pool.clone(),
7137 backends.clone(),
7138 );
7139 tcp_proxy
7140 .add_listener(
7141 ListenerBuilder::new_tcp(tcp_address)
7142 .to_tcp(None)
7143 .expect("could not build the test TCP listener config"),
7144 token_for(Protocol::TCPListen),
7145 )
7146 .expect("could not add the test TCP listener");
7147 assert!(
7148 tcp_proxy
7149 .activate_listener(&tcp_address.into(), Some(pre_registered(tcp_address)))
7150 .is_err(),
7151 "the pre-registered descriptor must make the TCP registration fail"
7152 );
7153 assert!(
7154 matches!(
7155 tcp_proxy.give_back_listener(&tcp_address.into()),
7156 Err(ProxyError::UnactivatedListener)
7157 ),
7158 "a TCP listener holding only a parked socket must not answer as activated"
7159 );
7160
7161 let udp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7162 let mut udp_proxy = udp::UdpProxy::new(
7163 registry.try_clone().expect("could not clone the registry"),
7164 sessions.clone(),
7165 pool.clone(),
7166 backends.clone(),
7167 16,
7168 16384,
7169 );
7170 udp_proxy
7171 .add_listener(
7172 ListenerBuilder::new_udp(udp_address)
7173 .to_udp(None)
7174 .expect("could not build the test UDP listener config"),
7175 token_for(Protocol::UDP),
7176 )
7177 .expect("could not add the test UDP listener");
7178 let mut udp_socket =
7179 udp_bind(udp_address.into(), None).expect("could not bind the test UDP socket");
7180 registry
7181 .register(&mut udp_socket, Token(usize::MAX - 2), Interest::READABLE)
7182 .expect("could not pre-register the test UDP socket");
7183 assert!(
7184 udp_proxy
7185 .activate_listener(&udp_address.into(), Some(udp_socket))
7186 .is_err(),
7187 "the pre-registered descriptor must make the UDP registration fail"
7188 );
7189 assert!(
7190 matches!(
7191 udp_proxy.give_back_listener(&udp_address.into()),
7192 Err(ProxyError::UnactivatedListener)
7193 ),
7194 "a UDP listener holding only a parked socket must not answer as activated"
7195 );
7196 }
7197
7198 #[test]
7212 fn a_failed_registration_does_not_close_the_socket_it_was_handed() {
7213 let ServerParts {
7214 registry,
7215 sessions,
7216 pool,
7217 backends,
7218 ..
7219 } = prebuild_server(16, 16384, true).expect("could not prebuild a test server");
7220
7221 let token_for = |protocol: Protocol| {
7222 let mut manager = sessions.borrow_mut();
7223 let entry = manager.slab.vacant_entry();
7224 let token = Token(entry.key());
7225 entry.insert(Rc::new(RefCell::new(ListenSession { protocol })));
7226 token
7227 };
7228
7229 let handed_out = |address: SocketAddress| {
7232 let mut socket = server_bind(address.into(), None)
7233 .expect("could not bind the test listening socket");
7234 registry
7235 .register(&mut socket, Token(usize::MAX - 1), Interest::READABLE)
7236 .expect("could not pre-register the test socket");
7237 let fd = socket.as_raw_fd();
7238 (socket, fd)
7239 };
7240
7241 let http_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7242 let token = token_for(Protocol::HTTPListen);
7243 let mut http_proxy = http::HttpProxy::new(
7244 registry.try_clone().expect("could not clone the registry"),
7245 sessions.clone(),
7246 pool.clone(),
7247 backends.clone(),
7248 );
7249 http_proxy
7250 .add_listener(
7251 ListenerBuilder::new_http(http_address)
7252 .to_http(None)
7253 .expect("could not build the test HTTP listener config"),
7254 token,
7255 )
7256 .expect("could not add the test HTTP listener");
7257 let (socket, http_fd) = handed_out(http_address);
7258 let result = http_proxy.activate_listener(&http_address.into(), Some(socket));
7259 assert!(
7260 result.is_err(),
7261 "the pre-registered descriptor must make the HTTP registration fail"
7262 );
7263 assert!(
7264 descriptor_is_socket_on_port(http_fd, http_address.port as u16),
7265 "a failed HTTP registration must not close the socket it was handed"
7266 );
7267
7268 let tcp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7269 let token = token_for(Protocol::TCPListen);
7270 let mut tcp_proxy = tcp::TcpProxy::new(
7271 registry.try_clone().expect("could not clone the registry"),
7272 sessions.clone(),
7273 pool.clone(),
7274 backends.clone(),
7275 );
7276 tcp_proxy
7277 .add_listener(
7278 ListenerBuilder::new_tcp(tcp_address)
7279 .to_tcp(None)
7280 .expect("could not build the test TCP listener config"),
7281 token,
7282 )
7283 .expect("could not add the test TCP listener");
7284 let (socket, tcp_fd) = handed_out(tcp_address);
7285 let result = tcp_proxy.activate_listener(&tcp_address.into(), Some(socket));
7286 assert!(
7287 result.is_err(),
7288 "the pre-registered descriptor must make the TCP registration fail"
7289 );
7290 assert!(
7291 descriptor_is_socket_on_port(tcp_fd, tcp_address.port as u16),
7292 "a failed TCP registration must not close the socket it was handed"
7293 );
7294
7295 let https_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7296 let token = token_for(Protocol::HTTPSListen);
7297 let mut https_proxy = https::HttpsProxy::new(
7298 registry.try_clone().expect("could not clone the registry"),
7299 sessions.clone(),
7300 pool.clone(),
7301 backends.clone(),
7302 );
7303 https_proxy
7304 .add_listener(
7305 ListenerBuilder::new_https(https_address)
7306 .to_tls(None)
7307 .expect("could not build the test HTTPS listener config"),
7308 token,
7309 )
7310 .expect("could not add the test HTTPS listener");
7311 let (socket, https_fd) = handed_out(https_address);
7312 let result = https_proxy.activate_listener(&https_address.into(), Some(socket));
7313 assert!(
7314 result.is_err(),
7315 "the pre-registered descriptor must make the HTTPS registration fail"
7316 );
7317 assert!(
7318 descriptor_is_socket_on_port(https_fd, https_address.port as u16),
7319 "a failed HTTPS registration must not close the socket it was handed"
7320 );
7321
7322 let udp_address = SocketAddress::new_v4(127, 0, 0, 1, provide_port());
7323 let token = token_for(Protocol::UDP);
7324 let mut udp_proxy = udp::UdpProxy::new(
7325 registry.try_clone().expect("could not clone the registry"),
7326 sessions.clone(),
7327 pool.clone(),
7328 backends.clone(),
7329 16,
7330 16384,
7331 );
7332 udp_proxy
7333 .add_listener(
7334 ListenerBuilder::new_udp(udp_address)
7335 .to_udp(None)
7336 .expect("could not build the test UDP listener config"),
7337 token,
7338 )
7339 .expect("could not add the test UDP listener");
7340 let mut socket =
7341 udp_bind(udp_address.into(), None).expect("could not bind the test UDP socket");
7342 registry
7343 .register(&mut socket, Token(usize::MAX - 1), Interest::READABLE)
7344 .expect("could not pre-register the test UDP socket");
7345 let udp_fd = socket.as_raw_fd();
7346 let result = udp_proxy.activate_listener(&udp_address.into(), Some(socket));
7347 assert!(
7348 result.is_err(),
7349 "the pre-registered descriptor must make the UDP registration fail"
7350 );
7351 assert!(
7352 descriptor_is_socket_on_port(udp_fd, udp_address.port as u16),
7353 "a failed UDP registration must not close the socket it was handed"
7354 );
7355 }
7356}
7357
7358#[cfg(test)]
7359mod tests {
7360 use super::{ClusterId, SessionManager, mask_ipv4, mask_ipv6, subnet_key};
7361 use mio::Token;
7362 use slab::Slab;
7363 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
7364
7365 #[test]
7372 fn a_cluster_override_dropping_to_zero_after_a_track_is_a_no_op() {
7373 let manager = SessionManager::new(Slab::with_capacity(8), 8, 0, 0, 0, 24, 56);
7374 let token = Token(1);
7375 let cluster = ClusterId::from("api");
7376 let ip: IpAddr = "203.0.113.9".parse().expect("test address must parse");
7377
7378 manager
7380 .borrow_mut()
7381 .track_cluster_subnet(token, cluster.clone(), ip, Some(5));
7382 assert!(
7383 !manager.borrow().subnet_tracking_is_empty(),
7384 "premise: the positive override must have recorded a slot"
7385 );
7386
7387 manager
7391 .borrow_mut()
7392 .track_cluster_subnet(token, cluster.clone(), ip, Some(0));
7393
7394 manager.borrow_mut().untrack_all_cluster_ip(token);
7396 assert!(
7397 manager.borrow().subnet_tracking_is_empty(),
7398 "teardown must drain the slot even though the cap was disabled in between"
7399 );
7400 }
7401
7402 #[test]
7407 fn masking_handles_both_shift_overflowing_prefix_bounds() {
7408 let v4: Ipv4Addr = "203.0.113.45".parse().expect("test address must parse");
7409 assert_eq!(
7410 mask_ipv4(v4, 32),
7411 v4,
7412 "a /32 must be the address itself, not a wrapped-shift artefact"
7413 );
7414 assert_eq!(
7415 mask_ipv4(v4, 0),
7416 Ipv4Addr::UNSPECIFIED,
7417 "a /0 must mask every bit away"
7418 );
7419
7420 let v6: Ipv6Addr = "2001:db8:dead:beef::1"
7421 .parse()
7422 .expect("test address must parse");
7423 assert_eq!(
7424 mask_ipv6(v6, 128),
7425 v6,
7426 "a /128 must be the address itself, not a wrapped-shift artefact"
7427 );
7428 assert_eq!(
7429 mask_ipv6(v6, 0),
7430 Ipv6Addr::UNSPECIFIED,
7431 "a /0 must mask every bit away"
7432 );
7433
7434 assert_eq!(
7437 mask_ipv4(v4, 33),
7438 v4,
7439 "an over-wide IPv4 prefix must clamp to the address, not panic or wrap"
7440 );
7441 assert_eq!(
7442 mask_ipv6(v6, 129),
7443 v6,
7444 "an over-wide IPv6 prefix must clamp to the address, not panic or wrap"
7445 );
7446 }
7447
7448 #[test]
7451 fn masking_groups_addresses_at_the_recommended_prefixes() {
7452 let parse_v4 = |s: &str| -> Ipv4Addr { s.parse().expect("test address must parse") };
7453 assert_eq!(
7454 mask_ipv4(parse_v4("203.0.113.1"), 24),
7455 mask_ipv4(parse_v4("203.0.113.254"), 24),
7456 "two hosts in one /24 must share a subnet key"
7457 );
7458 assert_ne!(
7459 mask_ipv4(parse_v4("203.0.113.1"), 24),
7460 mask_ipv4(parse_v4("203.0.114.1"), 24),
7461 "hosts in different /24s must NOT share a subnet key"
7462 );
7463
7464 let parse_v6 = |s: &str| -> Ipv6Addr { s.parse().expect("test address must parse") };
7465 assert_eq!(
7466 mask_ipv6(parse_v6("2001:db8:abcd:0000::1"), 56),
7467 mask_ipv6(parse_v6("2001:db8:abcd:00ff::9999"), 56),
7468 "two addresses in one /56 must share a subnet key"
7469 );
7470 assert_ne!(
7471 mask_ipv6(parse_v6("2001:db8:abcd:0000::1"), 56),
7472 mask_ipv6(parse_v6("2001:db8:abcd:0100::1"), 56),
7473 "addresses in different /56s must NOT share a subnet key"
7474 );
7475
7476 assert_eq!(
7479 mask_ipv6(parse_v6("2001:db8:abcd:1234::1"), 56),
7480 mask_ipv6(parse_v6("2001:db8:abcd:1234:ffff:ffff:ffff:ffff"), 56),
7481 "every address a /64 holder can mint must collapse to one /56 key — that \
7482 collapse IS the mitigation for sozu-proxy/sozu#1270"
7483 );
7484 }
7485
7486 #[test]
7491 fn an_ipv4_mapped_source_is_charged_to_the_ipv4_prefix() {
7492 let mapped: IpAddr = "::ffff:203.0.113.7".parse().expect("must parse");
7493 let native: IpAddr = "203.0.113.7".parse().expect("must parse");
7494 assert_eq!(
7495 subnet_key(&mapped, 24, 56),
7496 subnet_key(&native, 24, 56),
7497 "a mapped IPv4 source must key identically to the same address arriving natively"
7498 );
7499 assert!(
7500 subnet_key(&mapped, 24, 56).is_ipv4(),
7501 "the key for a mapped source must be an IPv4 key"
7502 );
7503
7504 let other: IpAddr = "::ffff:198.51.100.7".parse().expect("must parse");
7508 assert_ne!(
7509 subnet_key(&mapped, 24, 56),
7510 subnet_key(&other, 24, 56),
7511 "mapped sources from different IPv4 /24s must NOT share a subnet key — if they \
7512 do, every IPv4 client on a dual-stack listener shares one bucket"
7513 );
7514
7515 let genuine: IpAddr = "2001:db8::1".parse().expect("must parse");
7517 assert!(
7518 subnet_key(&genuine, 24, 56).is_ipv6(),
7519 "a genuine IPv6 source must keep an IPv6 subnet key"
7520 );
7521 }
7522}