1#[macro_use]
308extern crate sozu_command_lib as sozu_command;
309
310#[macro_use]
311pub mod util;
312#[macro_use]
313pub mod metrics;
314
315pub mod backends;
316pub mod crypto;
317pub mod features;
318pub mod health_check;
319pub mod http;
320pub mod load_balancing;
321pub mod pool;
322pub mod protocol;
323pub mod retry;
324pub mod router;
325pub mod socket;
326pub mod timer;
327pub mod tls;
328
329#[cfg(all(target_os = "linux", feature = "splice"))]
332pub(crate) mod splice;
333
334pub mod server;
335pub mod tcp;
336pub mod udp;
337
338pub mod https;
339
340use std::{
341 cell::RefCell,
342 collections::{BTreeMap, HashMap},
343 fmt::{self, Display, Formatter},
344 net::SocketAddr,
345 rc::Rc,
346 str,
347 time::{Duration, Instant, SystemTime},
348};
349
350use backends::BackendError;
351use hex::FromHexError;
352use mio::{Interest, Token, net::TcpStream};
353use protocol::http::{answers::HttpAnswers, answers::TemplateError, parser::Method};
354use router::RouterError;
355use socket::ServerBindError;
356use sozu_command::{
357 AsStr, ObjectKind,
358 logging::{CachedTags, LogContext},
359 proto::command::{Cluster, ListenerType, RequestHttpFrontend, WorkerRequest, WorkerResponse},
360 ready::Ready,
361 state::ClusterId,
362};
363use tls::CertificateResolverError;
364
365use crate::{backends::BackendMap, metrics::names, router::RouteResult};
366
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
369pub enum Protocol {
370 HTTP,
371 HTTPS,
372 TCP,
373 UDP,
374 HTTPListen,
375 HTTPSListen,
376 TCPListen,
377 UDPListen,
378 Channel,
379 Metrics,
380 Timer,
381}
382
383pub trait ProxySession {
385 fn protocol(&self) -> Protocol;
390 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed;
394 fn update_readiness(&mut self, token: Token, events: Ready);
397 fn close(&mut self);
400 fn timeout(&mut self, t: Token) -> SessionIsToBeClosed;
403 fn last_event(&self) -> Instant;
405 fn print_session(&self);
407 fn frontend_token(&self) -> Token;
409 fn shutting_down(&mut self) -> SessionIsToBeClosed;
414 fn cluster_id(&self) -> Option<String> {
423 None
424 }
425 fn session_address(&self) -> Option<SocketAddr> {
431 None
432 }
433}
434
435#[macro_export]
436macro_rules! branch {
437 (if $($value:ident)? == $expected:ident { $($then:tt)* } else { $($else:tt)* }) => {
438 macro_rules! expect {
439 ($expected) => {$($then)*};
440 ($a:ident) => {$($else)*};
441 () => {$($else)*}
442 }
443 expect!($($value)?);
444 };
445 (if $($value:ident)? == $expected:ident { $($then:tt)* } ) => {
446 macro_rules! expect {
447 ($expected) => {$($then)*};
448 }
449 expect!($($value)?);
450 };
451}
452
453#[macro_export]
454macro_rules! fallback {
455 ({} $($default:tt)*) => {
456 $($default)*
457 };
458 ({$($value:tt)+} $($default:tt)*) => {
459 $($value)+
460 };
461}
462
463#[macro_export]
464macro_rules! StateMachineBuilder {
465 (
466 ($d:tt)
467 $(#[$($state_macros:tt)*])*
468 enum $state_name:ident $(impl $trait:ident)? {
469 $($(#[$($variant_macros:tt)*])*
470 $variant_name:ident($state:ty$(,$($aux:ty),+)?) $(-> $override:expr)?),+ $(,)?
471 }
472 ) => {
473 #[derive(Clone, Copy, Debug)]
475 pub enum StateMarker {
476 $($variant_name,)+
477 }
478
479 $(#[$($state_macros)*])*
480 #[allow(clippy::large_enum_variant)]
481 pub enum $state_name {
482 $(
483 $(#[$($variant_macros)*])*
484 $variant_name($state$(,$($aux),+)?),
485 )+
486 FailedUpgrade(StateMarker),
488 }
489
490 macro_rules! _fn_impl {
491 ($function:ident(&$d($mut:ident)?, self $d(,$arg_name:ident: $arg_type:ty)*) $d(-> $ret:ty)? $d(| $marker:tt => $fail:expr)?) => {
492 fn $function(&$d($mut)? self $d(,$arg_name: $arg_type)*) $d(-> $ret)? {
493 match self {
494 $($state_name::$variant_name(_state, ..) => $crate::fallback!({$($override)?} _state.$function($d($arg_name),*)),)+
495 $state_name::FailedUpgrade($crate::fallback!({$d($marker)?} _)) => $crate::fallback!({$d($fail)?} unreachable!())
496 }
497 }
498 };
499 }
500
501 impl $state_name {
502 fn marker(&self) -> StateMarker {
504 match self {
505 $($state_name::$variant_name(..) => StateMarker::$variant_name,)+
506 $state_name::FailedUpgrade(marker) => *marker,
507 }
508 }
509 fn failed(&self) -> bool {
511 match self {
512 $state_name::FailedUpgrade(_) => true,
513 _ => false,
514 }
515 }
516 fn take(&mut self) -> $state_name {
520 let mut owned_state = $state_name::FailedUpgrade(self.marker());
521 std::mem::swap(&mut owned_state, self);
522 owned_state
523 }
524 _fn_impl!{front_socket(&, self) -> &mio::net::TcpStream}
525 }
526
527 $crate::branch!{
528 if $($trait)? == SessionState {
529 impl SessionState for $state_name {
530 _fn_impl!{ready(&mut, self, session: Rc<RefCell<dyn ProxySession>>, proxy: Rc<RefCell<dyn L7Proxy>>, metrics: &mut SessionMetrics) -> SessionResult}
531 _fn_impl!{update_readiness(&mut, self, token: Token, events: Ready)}
532 _fn_impl!{timeout(&mut, self, token: Token, metrics: &mut SessionMetrics) -> StateResult}
533 _fn_impl!{cancel_timeouts(&mut, self)}
534 _fn_impl!{print_state(&, self, context: &str) | marker => error!("{} Session(FailedUpgrade({:?}))", context, marker)}
535 _fn_impl!{close(&mut, self, proxy: Rc<RefCell<dyn L7Proxy>>, metrics: &mut SessionMetrics) | _ => {}}
536 _fn_impl!{shutting_down(&mut, self) -> SessionIsToBeClosed | _ => true}
537 }
538 } else {}
539 }
540 };
541 ($($tt:tt)+) => {
542 StateMachineBuilder!{($) $($tt)+}
543 }
544}
545
546pub trait ListenerHandler {
547 fn get_addr(&self) -> &SocketAddr;
548
549 fn get_tags(&self, key: &str) -> Option<&CachedTags>;
550
551 fn get_concatenated_tags(&self, key: &str) -> Option<&str> {
552 self.get_tags(key).map(|tags| tags.concatenated.as_str())
553 }
554
555 fn set_tags(&mut self, key: String, tags: Option<BTreeMap<String, String>>);
556
557 fn protocol(&self) -> Protocol;
558
559 fn public_address(&self) -> SocketAddr;
560}
561
562#[derive(thiserror::Error, Debug)]
563pub enum FrontendFromRequestError {
564 #[error("Could not parse hostname from '{host}': {error}")]
565 HostParse { host: String, error: String },
566 #[error("invalid remaining chars after hostname. Host: {0}")]
567 InvalidCharsAfterHost(String),
568 #[error("no cluster: {0}")]
569 NoClusterFound(RouterError),
570}
571
572pub trait L7ListenerHandler {
573 fn get_sticky_name(&self) -> &str;
574
575 fn get_sozu_id_header(&self) -> &str {
579 "Sozu-Id"
580 }
581
582 fn get_connect_timeout(&self) -> u32;
583
584 fn frontend_from_request(
586 &self,
587 host: &str,
588 uri: &str,
589 method: &Method,
590 ) -> Result<RouteResult, FrontendFromRequestError>;
591
592 fn get_answers(&self) -> &Rc<RefCell<HttpAnswers>>;
594
595 fn get_h2_flood_config(&self) -> protocol::mux::H2FloodConfig {
598 protocol::mux::H2FloodConfig::default()
599 }
600
601 fn get_h2_connection_config(&self) -> protocol::mux::H2ConnectionConfig {
604 protocol::mux::H2ConnectionConfig::default()
605 }
606
607 fn get_strict_sni_binding(&self) -> bool {
618 true
619 }
620
621 fn get_elide_x_real_ip(&self) -> bool {
632 false
633 }
634
635 fn get_send_x_real_ip(&self) -> bool {
647 false
648 }
649
650 fn get_h2_stream_idle_timeout(&self) -> std::time::Duration {
663 std::time::Duration::from_secs(30)
664 }
665
666 fn get_h2_graceful_shutdown_deadline(&self) -> Option<std::time::Duration> {
676 Some(std::time::Duration::from_secs(5))
677 }
678}
679
680#[derive(Clone, Copy, Debug, PartialEq, Eq)]
681pub enum BackendConnectionStatus {
682 NotConnected,
683 Connecting(Instant),
684 Connected,
685}
686
687impl BackendConnectionStatus {
688 pub fn is_connecting(&self) -> bool {
689 matches!(self, BackendConnectionStatus::Connecting(_))
690 }
691}
692
693#[derive(Debug, PartialEq, Eq)]
694pub enum BackendConnectAction {
695 New,
696 Reuse,
697 Replace,
698}
699
700#[derive(thiserror::Error, Debug)]
701pub enum BackendConnectionError {
702 #[error("Not found: {0:?}")]
703 NotFound(ObjectKind),
704 #[error("Too many connections on cluster {0:?}")]
705 MaxConnectionRetries(Option<String>),
706 #[error("the sessions slab has reached maximum capacity")]
707 MaxSessionsMemory,
708 #[error("error from the backend: {0}")]
709 Backend(BackendError),
710 #[error("failed to retrieve the cluster: {0}")]
711 RetrieveClusterError(RetrieveClusterError),
712 #[error("maximum number of buffers reached")]
713 MaxBuffers,
714 #[error("per-(cluster, source-IP) connection limit reached for cluster {cluster_id:?}")]
720 TooManyConnectionsPerIp { cluster_id: String },
721}
722
723#[derive(thiserror::Error)]
725pub enum RetrieveClusterError {
726 #[error("No method given")]
727 NoMethod,
728 #[error("No host given")]
729 NoHost,
730 #[error("No path given")]
731 NoPath,
732 #[error("unauthorized route")]
733 UnauthorizedRoute,
734 #[error("{0}")]
735 RetrieveFrontend(FrontendFromRequestError),
736 #[error("HTTPS redirect required")]
737 HttpsRedirect,
738 #[error("TLS SNI does not match HTTP authority: sni_bytes={} authority_bytes={}", .sni.len(), .authority.len())]
742 SniAuthorityMismatch { sni: String, authority: String },
743}
744
745impl fmt::Debug for RetrieveClusterError {
746 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
747 fmt::Display::fmt(self, f)
748 }
749}
750
751#[derive(Debug, PartialEq, Eq)]
753pub enum AcceptError {
754 IoError,
755 TooManySessions,
756 WouldBlock,
757 RegisterError,
758 WrongSocketAddress,
759 BufferCapacityReached,
760}
761
762#[derive(thiserror::Error)]
764pub enum ListenerError {
765 #[error("failed to handle certificate request, got a resolver error, {0}")]
766 Resolver(CertificateResolverError),
767 #[error("failed to parse pem, {0}")]
768 PemParse(String),
769 #[error(
770 "failed to parse template key_bytes={key_bytes}: {1}",
771 key_bytes = .0.len()
772 )]
773 TemplateParse(String, TemplateError),
774 #[error("failed to build rustls context, {0}")]
775 BuildRustls(String),
776 #[error("could not activate listener with address {address:?}: {error}")]
777 Activation { address: SocketAddr, error: String },
778 #[error("Could not register listener socket: {0}")]
779 SocketRegistration(std::io::Error),
780 #[error("could not add frontend: {0}")]
781 AddFrontend(RouterError),
782 #[error("could not remove frontend: {0}")]
783 RemoveFrontend(RouterError),
784 #[error("invalid value for field '{field}': {reason}")]
785 InvalidValue {
786 field: &'static str,
787 reason: &'static str,
788 },
789 #[error(
795 "UpdateHttpsListenerConfig.hsts is present but `enabled` is unset; the partial-update \
796 contract requires `enabled` whenever the `hsts` block is present"
797 )]
798 HstsEnabledRequired,
799}
800
801impl fmt::Debug for ListenerError {
802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
803 fmt::Display::fmt(self, f)
804 }
805}
806
807impl From<sozu_command::state::StateError> for ListenerError {
813 fn from(err: sozu_command::state::StateError) -> Self {
814 match err {
815 sozu_command::state::StateError::InvalidValue { field, reason } => {
816 ListenerError::InvalidValue { field, reason }
817 }
818 _ => ListenerError::InvalidValue {
819 field: "state",
820 reason: "unexpected state error on worker path",
821 },
822 }
823 }
824}
825
826#[derive(thiserror::Error, Debug)]
828pub enum ProxyError {
829 #[error("error while soft stopping {proxy_protocol} proxy: {error}")]
830 SoftStop {
831 proxy_protocol: String,
832 error: String,
833 },
834 #[error("error while hard stopping {proxy_protocol} proxy: {error}")]
835 HardStop {
836 proxy_protocol: String,
837 error: String,
838 },
839 #[error("found no listener with address {0:?}")]
840 NoListenerFound(SocketAddr),
841 #[error("a listener is already present for this token")]
842 ListenerAlreadyPresent,
843 #[error("could not add listener: {0}")]
844 AddListener(ListenerError),
845 #[error("could not add cluster: {0}")]
846 AddCluster(ListenerError),
847 #[error("failed to activate listener with address {address:?}: {listener_error}")]
848 ListenerActivation {
849 address: SocketAddr,
850 listener_error: ListenerError,
851 },
852 #[error("can not add frontend {front:?}: {error}")]
853 WrongInputFrontend {
854 front: Box<RequestHttpFrontend>,
855 error: String,
856 },
857 #[error("could not add frontend: {0}")]
858 AddFrontend(ListenerError),
859 #[error("could not remove frontend: {0}")]
860 RemoveFrontend(ListenerError),
861 #[error("could not add certificate: {0}")]
862 AddCertificate(CertificateResolverError),
863 #[error("could not remove certificate: {0}")]
864 RemoveCertificate(CertificateResolverError),
865 #[error("could not replace certificate: {0}")]
866 ReplaceCertificate(CertificateResolverError),
867 #[error("wrong certificate fingerprint: {0}")]
868 WrongCertificateFingerprint(FromHexError),
869 #[error("this request is not supported by the proxy")]
870 UnsupportedMessage,
871 #[error("failed to acquire the lock, {0}")]
872 Lock(String),
873 #[error("could not bind to socket {0:?}: {1}")]
874 BindToSocket(SocketAddr, ServerBindError),
875 #[error("error registering socket of listener: {0}")]
876 RegisterListener(std::io::Error),
877 #[error("the listener is not activated")]
878 UnactivatedListener,
879 #[error(
889 "HSTS is only valid on HTTPS frontends; rejecting AddHttpFrontend with hsts.enabled = \
890 true on address {0:?} (RFC 6797 §7.2)"
891 )]
892 HstsOnPlainHttp(SocketAddr),
893 #[error("rejected AddTcpFrontend on listener {address:?}: {reason}")]
905 InvalidTcpFrontend { address: SocketAddr, reason: String },
906}
907
908use self::server::ListenToken;
909pub trait ProxyConfiguration {
910 fn notify(&mut self, message: WorkerRequest) -> WorkerResponse;
911 fn accept(&mut self, token: ListenToken) -> Result<TcpStream, AcceptError>;
912 fn create_session(
913 &mut self,
914 socket: TcpStream,
915 token: ListenToken,
916 wait_time: Duration,
917 proxy: Rc<RefCell<Self>>,
918 ) -> Result<(), AcceptError>;
920}
921
922pub trait L7Proxy {
923 fn kind(&self) -> ListenerType;
924
925 fn register_socket(
926 &self,
927 socket: &mut TcpStream,
928 token: Token,
929 interest: Interest,
930 ) -> Result<(), std::io::Error>;
931
932 fn deregister_socket(&self, tcp_stream: &mut TcpStream) -> Result<(), std::io::Error>;
933
934 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token;
935
936 fn remove_session(&self, token: Token) -> bool;
939
940 fn backends(&self) -> Rc<RefCell<BackendMap>>;
941
942 fn clusters(&self) -> &HashMap<ClusterId, Cluster>;
943
944 fn sessions(&self) -> Rc<RefCell<crate::server::SessionManager>>;
949}
950
951#[derive(Debug, PartialEq, Eq)]
952pub enum RequiredEvents {
953 FrontReadBackNone,
954 FrontWriteBackNone,
955 FrontReadWriteBackNone,
956 FrontNoneBackNone,
957 FrontReadBackRead,
958 FrontWriteBackRead,
959 FrontReadWriteBackRead,
960 FrontNoneBackRead,
961 FrontReadBackWrite,
962 FrontWriteBackWrite,
963 FrontReadWriteBackWrite,
964 FrontNoneBackWrite,
965 FrontReadBackReadWrite,
966 FrontWriteBackReadWrite,
967 FrontReadWriteBackReadWrite,
968 FrontNoneBackReadWrite,
969}
970
971impl RequiredEvents {
972 pub fn front_readable(&self) -> bool {
973 matches!(
974 *self,
975 RequiredEvents::FrontReadBackNone
976 | RequiredEvents::FrontReadWriteBackNone
977 | RequiredEvents::FrontReadBackRead
978 | RequiredEvents::FrontReadWriteBackRead
979 | RequiredEvents::FrontReadBackWrite
980 | RequiredEvents::FrontReadWriteBackWrite
981 | RequiredEvents::FrontReadBackReadWrite
982 | RequiredEvents::FrontReadWriteBackReadWrite
983 )
984 }
985
986 pub fn front_writable(&self) -> bool {
987 matches!(
988 *self,
989 RequiredEvents::FrontWriteBackNone
990 | RequiredEvents::FrontReadWriteBackNone
991 | RequiredEvents::FrontWriteBackRead
992 | RequiredEvents::FrontReadWriteBackRead
993 | RequiredEvents::FrontWriteBackWrite
994 | RequiredEvents::FrontReadWriteBackWrite
995 | RequiredEvents::FrontWriteBackReadWrite
996 | RequiredEvents::FrontReadWriteBackReadWrite
997 )
998 }
999
1000 pub fn back_readable(&self) -> bool {
1001 matches!(
1002 *self,
1003 RequiredEvents::FrontReadBackRead
1004 | RequiredEvents::FrontWriteBackRead
1005 | RequiredEvents::FrontReadWriteBackRead
1006 | RequiredEvents::FrontNoneBackRead
1007 | RequiredEvents::FrontReadBackReadWrite
1008 | RequiredEvents::FrontWriteBackReadWrite
1009 | RequiredEvents::FrontReadWriteBackReadWrite
1010 | RequiredEvents::FrontNoneBackReadWrite
1011 )
1012 }
1013
1014 pub fn back_writable(&self) -> bool {
1015 matches!(
1016 *self,
1017 RequiredEvents::FrontReadBackWrite
1018 | RequiredEvents::FrontWriteBackWrite
1019 | RequiredEvents::FrontReadWriteBackWrite
1020 | RequiredEvents::FrontNoneBackWrite
1021 | RequiredEvents::FrontReadBackReadWrite
1022 | RequiredEvents::FrontWriteBackReadWrite
1023 | RequiredEvents::FrontReadWriteBackReadWrite
1024 | RequiredEvents::FrontNoneBackReadWrite
1025 )
1026 }
1027}
1028
1029#[derive(Debug, PartialEq, Eq)]
1031pub enum StateResult {
1032 CloseBackend,
1034 CloseSession,
1036 ConnectBackend,
1038 Continue,
1040 Upgrade,
1042}
1043
1044#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1046pub enum SessionResult {
1047 Close,
1049 Continue,
1051 Upgrade,
1053}
1054
1055#[derive(Debug, PartialEq, Eq)]
1056pub enum SocketType {
1057 Listener,
1058 FrontClient,
1059}
1060
1061type SessionIsToBeClosed = bool;
1062
1063#[derive(Clone)]
1064pub struct Readiness {
1065 pub event: Ready,
1067 pub interest: Ready,
1069}
1070
1071impl Display for Readiness {
1072 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1073 let i = &mut [b'-'; 4];
1074 let r = &mut [b'-'; 4];
1075 let mixed = &mut [b'-'; 4];
1076
1077 display_ready(i, self.interest);
1078 display_ready(r, self.event);
1079 display_ready(mixed, self.interest & self.event);
1080
1081 write!(
1082 f,
1083 "I({:?})&R({:?})=M({:?})",
1084 String::from_utf8_lossy(i),
1085 String::from_utf8_lossy(r),
1086 String::from_utf8_lossy(mixed)
1087 )
1088 }
1089}
1090
1091impl Default for Readiness {
1092 fn default() -> Self {
1093 Self::new()
1094 }
1095}
1096
1097impl Readiness {
1098 const KNOWN_BITS: Ready =
1104 Ready(Ready::READABLE.0 | Ready::WRITABLE.0 | Ready::ERROR.0 | Ready::HUP.0);
1105
1106 pub const fn new() -> Readiness {
1107 Readiness {
1108 event: Ready::EMPTY,
1109 interest: Ready::EMPTY,
1110 }
1111 }
1112
1113 #[cfg(debug_assertions)]
1118 fn check_invariants(&self) {
1119 debug_assert_eq!(
1120 self.event & Self::KNOWN_BITS,
1121 self.event,
1122 "Readiness.event carries a bit outside READABLE|WRITABLE|ERROR|HUP"
1123 );
1124 debug_assert_eq!(
1125 self.interest & Self::KNOWN_BITS,
1126 self.interest,
1127 "Readiness.interest carries a bit outside READABLE|WRITABLE|ERROR|HUP"
1128 );
1129 }
1130
1131 pub fn reset(&mut self) {
1132 self.event = Ready::EMPTY;
1133 self.interest = Ready::EMPTY;
1134 debug_assert!(
1137 self.event.is_empty() && self.interest.is_empty(),
1138 "reset must clear both event and interest"
1139 );
1140 #[cfg(debug_assertions)]
1141 self.check_invariants();
1142 }
1143
1144 pub fn filter_interest(&self) -> Ready {
1146 #[cfg(debug_assertions)]
1150 self.check_invariants();
1151 let filtered = self.event & self.interest;
1152 debug_assert_eq!(
1155 filtered & Self::KNOWN_BITS,
1156 filtered,
1157 "filter_interest must not yield an unknown bit"
1158 );
1159 debug_assert!(
1160 self.interest.contains(filtered) && self.event.contains(filtered),
1161 "filtered readiness must be present in both interest and event"
1162 );
1163 filtered
1164 }
1165
1166 pub fn signal_pending_write(&mut self) {
1169 let other_event_before = Ready(self.event.0 & !Ready::WRITABLE.0);
1173 self.event.insert(Ready::WRITABLE);
1174 debug_assert!(
1175 self.event.is_writable(),
1176 "signal_pending_write must set the WRITABLE event bit"
1177 );
1178 debug_assert_eq!(
1179 Ready(self.event.0 & !Ready::WRITABLE.0),
1180 other_event_before,
1181 "signal_pending_write must touch only the WRITABLE bit"
1182 );
1183 #[cfg(debug_assertions)]
1184 self.check_invariants();
1185 }
1186
1187 pub fn signal_pending_read(&mut self) {
1190 let other_event_before = Ready(self.event.0 & !Ready::READABLE.0);
1191 self.event.insert(Ready::READABLE);
1192 debug_assert!(
1193 self.event.is_readable(),
1194 "signal_pending_read must set the READABLE event bit"
1195 );
1196 debug_assert_eq!(
1197 Ready(self.event.0 & !Ready::READABLE.0),
1198 other_event_before,
1199 "signal_pending_read must touch only the READABLE bit"
1200 );
1201 #[cfg(debug_assertions)]
1202 self.check_invariants();
1203 }
1204
1205 #[inline]
1209 pub fn arm_writable(&mut self) {
1210 let other_interest_before = Ready(self.interest.0 & !Ready::WRITABLE.0);
1213 let other_event_before = Ready(self.event.0 & !Ready::WRITABLE.0);
1214 self.interest.insert(Ready::WRITABLE);
1215 self.signal_pending_write();
1216 debug_assert!(
1217 self.interest.is_writable() && self.event.is_writable(),
1218 "arm_writable must set WRITABLE in both interest and event"
1219 );
1220 debug_assert_eq!(
1221 Ready(self.interest.0 & !Ready::WRITABLE.0),
1222 other_interest_before,
1223 "arm_writable must touch only the WRITABLE interest bit"
1224 );
1225 debug_assert_eq!(
1226 Ready(self.event.0 & !Ready::WRITABLE.0),
1227 other_event_before,
1228 "arm_writable must touch only the WRITABLE event bit"
1229 );
1230 #[cfg(debug_assertions)]
1231 self.check_invariants();
1232 }
1233}
1234
1235#[cfg(test)]
1236mod readiness_tests {
1237 use super::{Readiness, Ready};
1238
1239 #[test]
1240 fn arm_writable_sets_interest_and_event() {
1241 let mut r = Readiness::new();
1242 r.arm_writable();
1243 assert!(r.interest.is_writable());
1244 assert!(r.event.is_writable());
1245 }
1246
1247 #[test]
1248 fn arm_writable_is_idempotent() {
1249 let mut r = Readiness::new();
1250 r.arm_writable();
1251 r.arm_writable();
1252 assert_eq!(r.interest, Ready::WRITABLE);
1253 assert_eq!(r.event, Ready::WRITABLE);
1254 }
1255}
1256
1257pub fn display_ready(s: &mut [u8], readiness: Ready) {
1258 if readiness.is_readable() {
1259 s[0] = b'R';
1260 }
1261 if readiness.is_writable() {
1262 s[1] = b'W';
1263 }
1264 if readiness.is_error() {
1265 s[2] = b'E';
1266 }
1267 if readiness.is_hup() {
1268 s[3] = b'H';
1269 }
1270}
1271
1272pub fn ready_to_string(readiness: Ready) -> String {
1273 let s = &mut [b'-'; 4];
1274 display_ready(s, readiness);
1275 String::from_utf8(s.to_vec()).unwrap()
1276}
1277
1278impl fmt::Debug for Readiness {
1279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1280 let i = &mut [b'-'; 4];
1281 let r = &mut [b'-'; 4];
1282 let mixed = &mut [b'-'; 4];
1283
1284 display_ready(i, self.interest);
1285 display_ready(r, self.event);
1286 display_ready(mixed, self.interest & self.event);
1287
1288 write!(
1289 f,
1290 "Readiness {{ interest: {}, readiness: {}, mixed: {} }}",
1291 str::from_utf8(i).unwrap(),
1292 str::from_utf8(r).unwrap(),
1293 str::from_utf8(mixed).unwrap()
1294 )
1295 }
1296}
1297
1298#[derive(Clone, Debug)]
1299pub struct SessionMetrics {
1300 pub start: Option<Instant>,
1302 pub start_wall: Option<SystemTime>,
1307 pub service_time: Duration,
1309 pub wait_time: Duration,
1311 pub bin: usize,
1313 pub bout: usize,
1315
1316 pub service_start: Option<Instant>,
1318 pub wait_start: Instant,
1319
1320 pub backend_id: Option<String>,
1321 pub backend_start: Option<Instant>,
1322 pub backend_connected: Option<Instant>,
1323 pub backend_stop: Option<Instant>,
1324 pub backend_bin: usize,
1325 pub backend_bout: usize,
1326}
1327
1328impl SessionMetrics {
1329 pub fn new(wait_time: Option<Duration>) -> SessionMetrics {
1330 SessionMetrics {
1331 start: Some(Instant::now()),
1332 start_wall: Some(SystemTime::now()),
1333 service_time: Duration::from_secs(0),
1334 wait_time: wait_time.unwrap_or_else(|| Duration::from_secs(0)),
1335 bin: 0,
1336 bout: 0,
1337 service_start: None,
1338 wait_start: Instant::now(),
1339 backend_id: None,
1340 backend_start: None,
1341 backend_connected: None,
1342 backend_stop: None,
1343 backend_bin: 0,
1344 backend_bout: 0,
1345 }
1346 }
1347
1348 pub fn reset(&mut self) {
1349 self.start = None;
1350 self.start_wall = None;
1351 self.service_time = Duration::from_secs(0);
1352 self.wait_time = Duration::from_secs(0);
1353 self.bin = 0;
1354 self.bout = 0;
1355 self.service_start = None;
1356 self.backend_start = None;
1357 self.backend_connected = None;
1358 self.backend_stop = None;
1359 self.backend_bin = 0;
1360 self.backend_bout = 0;
1361 }
1362
1363 pub fn service_start(&mut self) {
1364 let now = if self.start.is_none() {
1365 self.mark_request_start()
1366 } else {
1367 Instant::now()
1368 };
1369 self.service_start = Some(now);
1370 self.wait_time += now - self.wait_start;
1371 }
1372
1373 pub fn service_stop(&mut self) {
1374 if let Some(start) = self.service_start.take() {
1375 let duration = Instant::now() - start;
1376 self.service_time += duration;
1377 }
1378 }
1379
1380 pub fn wait_start(&mut self) {
1381 self.wait_start = Instant::now();
1382 }
1383
1384 pub fn service_time(&self) -> Duration {
1385 match self.service_start {
1386 Some(start) => {
1387 let last_duration = Instant::now() - start;
1388 self.service_time + last_duration
1389 }
1390 None => self.service_time,
1391 }
1392 }
1393
1394 pub fn mark_request_start(&mut self) -> Instant {
1400 let now = Instant::now();
1401 self.start = Some(now);
1402 self.start_wall = Some(SystemTime::now());
1403 now
1404 }
1405
1406 pub fn request_time(&self) -> Duration {
1408 match self.start {
1409 Some(start) => Instant::now() - start,
1410 None => Duration::from_secs(0),
1411 }
1412 }
1413
1414 pub fn start_wall_ns(&self) -> Option<i128> {
1417 self.start_wall.and_then(|t| {
1418 t.duration_since(SystemTime::UNIX_EPOCH)
1419 .ok()
1420 .map(|d| d.as_nanos() as i128)
1421 })
1422 }
1423
1424 pub fn backend_start(&mut self) {
1425 self.backend_start = Some(Instant::now());
1426 }
1427
1428 pub fn backend_connected(&mut self) {
1429 self.backend_connected = Some(Instant::now());
1430 }
1431
1432 pub fn backend_stop(&mut self) {
1433 self.backend_stop = Some(Instant::now());
1434 }
1435
1436 pub fn backend_response_time(&self) -> Option<Duration> {
1437 match (self.backend_connected, self.backend_stop) {
1438 (Some(start), Some(end)) => Some(end - start),
1439 (Some(start), None) => Some(Instant::now() - start),
1440 _ => None,
1441 }
1442 }
1443
1444 pub fn backend_connection_time(&self) -> Option<Duration> {
1445 match (self.backend_start, self.backend_connected) {
1446 (Some(start), Some(end)) => Some(end - start),
1447 _ => None,
1448 }
1449 }
1450
1451 pub fn register_end_of_session(&self, context: &LogContext) {
1452 let request_time = self.request_time();
1453 let service_time = self.service_time();
1454
1455 if let Some(cluster_id) = context.cluster_id {
1456 time!(
1457 names::event_loop::REQUEST_TIME,
1458 cluster_id,
1459 request_time.as_millis()
1460 );
1461 time!(
1462 names::event_loop::SERVICE_TIME,
1463 cluster_id,
1464 service_time.as_millis()
1465 );
1466 }
1467 time!(names::event_loop::REQUEST_TIME, request_time.as_millis());
1468 time!(names::event_loop::SERVICE_TIME, service_time.as_millis());
1469
1470 if let Some(backend_id) = self.backend_id.as_ref()
1471 && let Some(backend_response_time) = self.backend_response_time()
1472 {
1473 record_backend_metrics!(
1474 context.cluster_id.as_str_or("-"),
1475 backend_id,
1476 backend_response_time.as_millis(),
1477 self.backend_connection_time(),
1478 self.backend_bin,
1479 self.backend_bout
1480 );
1481 }
1482
1483 incr!(
1484 names::access_logs::COUNT,
1485 context.cluster_id,
1486 context.backend_id
1487 );
1488 }
1489}
1490
1491#[derive(Debug, PartialEq, Clone)]
1495pub struct PeakEWMA {
1496 pub decay: f64,
1500 pub rtt: f64,
1505 pub last_event: Instant,
1507}
1508
1509impl Default for PeakEWMA {
1510 fn default() -> Self {
1511 Self::new()
1512 }
1513}
1514
1515impl PeakEWMA {
1516 pub fn new() -> Self {
1518 PeakEWMA {
1519 decay: 1_000_000_000f64,
1521 rtt: 50_000_000f64,
1523 last_event: Instant::now(),
1524 }
1525 }
1526
1527 pub fn observe(&mut self, rtt: f64) {
1528 let now = Instant::now();
1529 let dur = now - self.last_event;
1530
1531 if rtt > self.rtt {
1533 self.rtt = rtt;
1534 } else {
1535 let weight = (-(dur.as_nanos() as f64) / self.decay).exp();
1537 self.rtt = self.rtt * weight + rtt * (1.0 - weight);
1538 }
1539
1540 self.last_event = now;
1541 }
1542
1543 pub fn get(&mut self, active_requests: usize) -> f64 {
1544 self.observe(0.0);
1547
1548 (active_requests + 1) as f64 * self.rtt
1549 }
1550}
1551
1552pub mod testing {
1553 pub use std::{cell::RefCell, os::fd::IntoRawFd, rc::Rc};
1554
1555 pub use anyhow::Context;
1556 pub use mio::{Poll, Registry, Token, net::UnixStream};
1557 pub use slab::Slab;
1558 pub use sozu_command::{
1559 proto::command::{
1560 HttpListenerConfig, HttpsListenerConfig, ServerConfig, TcpListenerConfig,
1561 },
1562 scm_socket::{Listeners, ScmSocket},
1563 };
1564
1565 pub use crate::{
1566 Protocol, ProxySession,
1567 backends::BackendMap,
1568 http::HttpProxy,
1569 https::HttpsProxy,
1570 pool::Pool,
1571 server::{ListenSession, ProxyChannel, Server, SessionManager},
1572 tcp::TcpProxy,
1573 };
1574
1575 use std::sync::atomic::{AtomicU16, Ordering};
1576
1577 static PORT_PROVIDER: AtomicU16 = AtomicU16::new(10000);
1583
1584 pub fn provide_port() -> u16 {
1587 PORT_PROVIDER.fetch_add(1, Ordering::SeqCst)
1588 }
1589
1590 pub struct ServerParts {
1592 pub event_loop: Poll,
1593 pub registry: Registry,
1594 pub sessions: Rc<RefCell<SessionManager>>,
1595 pub pool: Rc<RefCell<Pool>>,
1596 pub backends: Rc<RefCell<BackendMap>>,
1597 pub client_scm_socket: ScmSocket,
1598 pub server_scm_socket: ScmSocket,
1599 pub server_config: ServerConfig,
1600 }
1601
1602 pub fn prebuild_server(
1604 max_buffers: usize,
1605 buffer_size: usize,
1606 send_scm: bool,
1607 ) -> anyhow::Result<ServerParts> {
1608 let event_loop = Poll::new().with_context(|| "Failed at creating event loop")?;
1609 let backends = Rc::new(RefCell::new(BackendMap::new()));
1610 let server_config = ServerConfig {
1611 max_connections: max_buffers as u64,
1612 ..Default::default()
1613 };
1614
1615 let pool = Rc::new(RefCell::new(Pool::with_capacity(
1616 1,
1617 max_buffers,
1618 buffer_size,
1619 )));
1620
1621 let mut sessions: Slab<Rc<RefCell<dyn ProxySession>>> = Slab::with_capacity(max_buffers);
1622 {
1623 let entry = sessions.vacant_entry();
1624 info!("taking token {:?} for channel", entry.key());
1625 entry.insert(Rc::new(RefCell::new(ListenSession {
1626 protocol: Protocol::Channel,
1627 })));
1628 }
1629 {
1630 let entry = sessions.vacant_entry();
1631 info!("taking token {:?} for timer", entry.key());
1632 entry.insert(Rc::new(RefCell::new(ListenSession {
1633 protocol: Protocol::Timer,
1634 })));
1635 }
1636 {
1637 let entry = sessions.vacant_entry();
1638 info!("taking token {:?} for metrics", entry.key());
1639 entry.insert(Rc::new(RefCell::new(ListenSession {
1640 protocol: Protocol::Metrics,
1641 })));
1642 }
1643 let sessions = SessionManager::new(sessions, max_buffers, 0, 0);
1645
1646 let registry = event_loop
1647 .registry()
1648 .try_clone()
1649 .with_context(|| "Failed at creating a registry")?;
1650
1651 let (scm_server, scm_client) =
1652 UnixStream::pair().with_context(|| "Failed at creating scm unix stream")?;
1653 let client_scm_socket = ScmSocket::new(scm_client.into_raw_fd())
1654 .with_context(|| "Failed at creating the scm client socket")?;
1655 let server_scm_socket = ScmSocket::new(scm_server.into_raw_fd())
1656 .with_context(|| "Failed at creating the scm server socket")?;
1657 if send_scm {
1658 client_scm_socket
1659 .send_listeners(&Listeners::default())
1660 .with_context(|| "Failed at sending empty listeners")?;
1661 }
1662
1663 Ok(ServerParts {
1664 event_loop,
1665 registry,
1666 sessions,
1667 pool,
1668 backends,
1669 client_scm_socket,
1670 server_scm_socket,
1671 server_config,
1672 })
1673 }
1674}
1675
1676#[cfg(test)]
1677pub(crate) fn capture_test_logs(run: impl FnOnce() + Send + 'static) -> String {
1678 capture_test_logs_at_level("info", run)
1679}
1680
1681#[cfg(test)]
1682pub(crate) fn capture_test_logs_at_level(
1683 level: &'static str,
1684 run: impl FnOnce() + Send + 'static,
1685) -> String {
1686 let receiver = std::net::UdpSocket::bind("127.0.0.1:0")
1687 .expect("test log receiver must bind to a loopback port");
1688 let target = format!(
1689 "udp://{}",
1690 receiver
1691 .local_addr()
1692 .expect("test log receiver must have a local address")
1693 );
1694
1695 std::thread::spawn(move || {
1696 sozu_command::logging::Logger::init(
1697 "log-redaction-test".to_owned(),
1698 level,
1699 &target,
1700 false,
1701 None,
1702 None,
1703 None,
1704 )
1705 .expect("test logger must initialize");
1706 run();
1707 })
1708 .join()
1709 .expect("log-producing test thread must not panic");
1710
1711 receiver
1712 .set_nonblocking(true)
1713 .expect("test log receiver must become nonblocking");
1714 let mut output = String::new();
1715 let mut datagram = vec![0; 65_507];
1716 loop {
1717 match receiver.recv(&mut datagram) {
1718 Ok(length) => output.push_str(&String::from_utf8_lossy(&datagram[..length])),
1719 Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => break,
1720 Err(error) => panic!("test log receiver failed: {error}"),
1721 }
1722 }
1723 assert!(!output.is_empty(), "test log capture received no datagrams");
1724 output
1725}
1726
1727#[cfg(test)]
1728mod log_redaction_tests {
1729 use super::*;
1730
1731 #[test]
1732 fn listener_template_parse_error_redacts_custom_answer_key() {
1733 const KEY_SECRET: &str = "CUSTOM_ANSWER_KEY_SECRET_SENTINEL";
1734
1735 let key = format!("{KEY_SECRET}{}", "x".repeat(4096));
1736 let key_len = key.len();
1737 let error = ListenerError::TemplateParse(key, TemplateError::InvalidType);
1738
1739 for (label, output) in [
1740 ("Display", error.to_string()),
1741 ("Debug", format!("{error:?}")),
1742 ] {
1743 assert!(
1744 !output.contains(KEY_SECRET),
1745 "ListenerError {label} leaked custom-answer key {KEY_SECRET}"
1746 );
1747 assert!(
1748 output.contains(&format!("key_bytes={key_len}")),
1749 "ListenerError {label} omitted the bounded key length: {output}"
1750 );
1751 assert!(
1752 output.len() <= 256,
1753 "ListenerError {label} output is not bounded: {} bytes",
1754 output.len()
1755 );
1756 }
1757 }
1758
1759 #[test]
1760 fn sni_authority_mismatch_retains_inputs_but_bounds_textual_formatting() {
1761 const SNI_SECRET: &str = "SNI_MISMATCH_SECRET_SENTINEL";
1762 const AUTHORITY_SECRET: &str = "AUTHORITY_MISMATCH_SECRET_SENTINEL";
1763
1764 let sni = format!("{SNI_SECRET}{}", "x".repeat(4096));
1765 let authority = format!("{AUTHORITY_SECRET}{}", "x".repeat(4096));
1766 let error = RetrieveClusterError::SniAuthorityMismatch {
1767 sni: sni.clone(),
1768 authority: authority.clone(),
1769 };
1770
1771 match &error {
1772 RetrieveClusterError::SniAuthorityMismatch {
1773 sni: retained_sni,
1774 authority: retained_authority,
1775 } => {
1776 assert_eq!(retained_sni, &sni);
1777 assert_eq!(retained_authority, &authority);
1778 }
1779 other => panic!("expected SniAuthorityMismatch, got {other:?}"),
1780 }
1781
1782 for output in [error.to_string(), format!("{error:?}")] {
1783 for secret in [SNI_SECRET, AUTHORITY_SECRET] {
1784 assert!(
1785 !output.contains(secret),
1786 "SNI mismatch formatting leaked {secret}: {output}"
1787 );
1788 }
1789 for metadata in [
1790 format!("sni_bytes={}", sni.len()),
1791 format!("authority_bytes={}", authority.len()),
1792 ] {
1793 assert!(
1794 output.contains(&metadata),
1795 "SNI mismatch formatting omitted {metadata}: {output}"
1796 );
1797 }
1798 assert!(
1799 output.len() <= 256,
1800 "SNI mismatch formatting is not bounded: {} bytes",
1801 output.len()
1802 );
1803 }
1804 }
1805}