Skip to main content

ferron/
main.rs

1mod acme;
2mod config;
3mod handler;
4mod listener_handler_communication;
5mod listeners;
6mod panic;
7mod request_handler;
8mod runtime;
9mod setup;
10mod util;
11
12use std::collections::{HashMap, HashSet};
13use std::error::Error;
14use std::net::{IpAddr, Ipv6Addr, SocketAddr};
15use std::path::Path;
16use std::sync::{Arc, LazyLock, Mutex, OnceLock};
17use std::thread;
18use std::time::Duration;
19
20use arc_swap::ArcSwap;
21use async_channel::{Receiver, Sender};
22use clap::Parser;
23use ferron_common::logging::{ErrorLogger, LogMessage};
24use ferron_common::{get_entry, get_value};
25use ferron_load_modules::{obtain_module_loaders, obtain_observability_backend_loaders};
26#[cfg(feature = "runtime-vibeio")]
27use malloc_best_effort::BEMalloc;
28#[cfg(not(feature = "runtime-vibeio"))]
29use mimalloc::MiMalloc;
30use rustls::server::{ResolvesServerCert, WebPkiClientVerifier};
31use rustls::{RootCertStore, ServerConfig};
32use rustls_native_certs::load_native_certs;
33use shadow_rs::shadow;
34use tempfile::NamedTempFile;
35use tokio_util::sync::CancellationToken;
36
37use crate::acme::{
38  check_certificate_validity_or_install_cached, convert_on_demand_config, get_cached_domains, ACME_TLS_ALPN_NAME,
39};
40use crate::config::adapters::ConfigurationAdapter;
41use crate::config::processing::{
42  load_modules, merge_duplicates, premerge_configuration, remove_and_add_global_configuration,
43};
44use crate::config::ServerConfigurations;
45use crate::handler::{create_http_handler, ReloadableHandlerData};
46use crate::listener_handler_communication::ConnectionData;
47use crate::listeners::{create_quic_listener, create_tcp_listener};
48use crate::panic::install_panic_hook;
49use crate::setup::acme::background_acme_task;
50use crate::setup::cli::{Command, ConfigAdapter, FerronArgs, LogOutput};
51use crate::setup::ocsp::OcspStapler;
52use crate::setup::tls::{
53  handle_automatic_tls, handle_manual_tls, handle_nonencrypted_ports, manual_tls_entry, read_default_port,
54  resolve_sni_hostname, should_skip_server, TlsBuildContext,
55};
56use crate::setup::tls_single::{init_crypto_provider, set_tls_version};
57use crate::util::{load_certs, MultiCancel};
58
59#[cfg(not(feature = "runtime-vibeio"))]
60#[global_allocator]
61static GLOBAL: MiMalloc = MiMalloc;
62#[cfg(feature = "runtime-vibeio")]
63#[global_allocator]
64static GLOBAL: BEMalloc = BEMalloc::new();
65
66shadow!(build);
67
68type LazyLockArc<T> = LazyLock<Arc<T>>;
69type LazyLockMutex<T> = LazyLockArc<Mutex<T>>;
70
71static LISTENER_HANDLER_CHANNEL: LazyLockArc<(Sender<ConnectionData>, Receiver<ConnectionData>)> =
72  LazyLock::new(|| Arc::new(async_channel::unbounded()));
73static TCP_LISTENERS: LazyLockMutex<HashMap<SocketAddr, CancellationToken>> =
74  LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
75#[allow(clippy::type_complexity)]
76static QUIC_LISTENERS: LazyLockMutex<HashMap<SocketAddr, (CancellationToken, Sender<Arc<ServerConfig>>)>> =
77  LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
78static HANDLERS: LazyLockMutex<Vec<(CancellationToken, Sender<()>)>> =
79  LazyLock::new(|| Arc::new(Mutex::new(Vec::new())));
80static SERVER_CONFIG_ARCSWAP: OnceLock<Arc<ArcSwap<ReloadableHandlerData>>> = OnceLock::new();
81static URING_ENABLED: LazyLockMutex<Option<bool>> = LazyLock::new(|| Arc::new(Mutex::new(None)));
82static LISTENER_LOGGING_CHANNEL: LazyLockArc<(Sender<LogMessage>, Receiver<LogMessage>)> =
83  LazyLock::new(|| Arc::new(async_channel::unbounded()));
84
85/// Handles shutdown signals (SIGHUP, SIGTERM and CTRL+C) and returns whether to continue running
86fn handle_shutdown_signals(runtime: &tokio::runtime::Runtime) -> bool {
87  runtime.block_on(async move {
88    #[cfg(unix)]
89    let configuration_reload_future = async {
90      if let Ok(mut signal) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::hangup()) {
91        signal.recv().await
92      } else {
93        futures_util::future::pending().await
94      }
95    };
96    #[cfg(not(unix))]
97    let configuration_reload_future = async { futures_util::future::pending::<Option<()>>().await };
98
99    #[cfg(unix)]
100    let sigterm_future = async {
101      if let Ok(mut signal) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) {
102        signal.recv().await
103      } else {
104        futures_util::future::pending().await
105      }
106    };
107    #[cfg(not(unix))]
108    let sigterm_future = async { futures_util::future::pending::<Option<()>>().await };
109
110    let shutdown_future = async {
111      if tokio::signal::ctrl_c().await.is_err() {
112        futures_util::future::pending().await
113      }
114    };
115
116    let continue_running = tokio::select! {
117      _ = shutdown_future => {
118        false
119      }
120      _ = sigterm_future => {
121        false
122      }
123      _ = configuration_reload_future => {
124        true
125      }
126    };
127    continue_running
128  })
129}
130
131/// Function called before starting a server
132fn before_starting_server(
133  args: FerronArgs,
134  configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
135) -> Result<(), Box<dyn Error + Send + Sync>> {
136  // When a config string is specified, a tempfile is written with the contents of the string and then
137  // the tempfile is used as the configuration path.
138  let temp_config_file: NamedTempFile;
139  // Obtain the argument values
140  let configuration_path: &Path = if let Some(config_string) = args.config_string.as_ref() {
141    temp_config_file = NamedTempFile::new()?;
142    std::fs::write(temp_config_file.path(), config_string)?;
143    temp_config_file.path()
144  } else if let Some(command) = args.command.as_ref() {
145    match command {
146      Command::Serve(http_serve_args) => {
147        let mut config_string = format!(
148          "* {{\n  listen_ip \"{}\"\n  default_http_port {}",
149          http_serve_args.listen_ip, http_serve_args.port
150        );
151        if !http_serve_args.credential.is_empty() {
152          let mut users = Vec::<String>::new();
153          for credential in http_serve_args.credential.iter() {
154            let (user, hashed_password) = credential
155              .rsplit_once(':')
156              .ok_or(anyhow::anyhow!("Invalid credential format: {credential}"))?;
157            users.push(user.to_owned());
158            config_string.push_str(
159              format!(
160                "\n  user \"{}\" \"{}\"",
161                user.escape_default(),
162                hashed_password.escape_default()
163              )
164              .as_str(),
165            );
166          }
167          if http_serve_args.forward_proxy {
168            config_string.push_str(
169              format!(
170                "\n  forward_proxy_auth users=\"{}\" brute_protection=#{}",
171                users.join(",").escape_default(),
172                http_serve_args.disable_brute_protection
173              )
174              .as_str(),
175            );
176          } else {
177            config_string.push_str(
178              format!(
179                "\n  status 401 users=\"{}\" brute_protection=#{}",
180                users.join(",").escape_default(),
181                http_serve_args.disable_brute_protection
182              )
183              .as_str(),
184            );
185          }
186        }
187        match http_serve_args.log {
188          LogOutput::Stdout => {
189            config_string.push_str("\n  log_stdout");
190          }
191          LogOutput::Stderr => {
192            config_string.push_str("\n  log_stderr");
193          }
194          LogOutput::Off => {}
195        }
196        match http_serve_args.error_log {
197          LogOutput::Stdout => {
198            config_string.push_str("\n  error_log_stdout");
199          }
200          LogOutput::Stderr => {
201            config_string.push_str("\n  error_log_stderr");
202          }
203          LogOutput::Off => {}
204        }
205        if http_serve_args.forward_proxy {
206          config_string.push_str("\n  forward_proxy");
207        } else {
208          config_string.push_str(
209            format!(
210              "\n  root \"{}\"",
211              http_serve_args.root.to_string_lossy().into_owned().escape_default()
212            )
213            .as_str(),
214          );
215          config_string.push_str("\n  directory_listing #true");
216        }
217        config_string.push_str("\n}\n");
218        temp_config_file = NamedTempFile::new()?;
219        std::fs::write(temp_config_file.path(), config_string)?;
220        temp_config_file.path()
221      }
222    }
223  } else {
224    args.config.as_path()
225  };
226  let configuration_adapter: &str = if let Some(config_adapter) = args.config_adapter.as_ref() {
227    match config_adapter {
228      ConfigAdapter::Kdl => "kdl",
229      #[cfg(feature = "config-yaml-legacy")]
230      ConfigAdapter::YamlLegacy => "yaml-legacy",
231      #[cfg(feature = "config-docker-auto")]
232      ConfigAdapter::DockerAuto => "docker-auto",
233    }
234  } else if args.config_string.is_some() {
235    // When a config string is specified but no configuration adapter is specified, default to using kdl.
236    "kdl"
237  } else {
238    determine_default_configuration_adapter(configuration_path)
239  };
240
241  // Obtain the configuration adapter
242  let configuration_adapter = configuration_adapters
243    .get(configuration_adapter)
244    .ok_or(anyhow::anyhow!(
245      "The \"{}\" configuration adapter isn't supported",
246      configuration_adapter
247    ))?;
248
249  // Determine the available parallelism
250  let available_parallelism = thread::available_parallelism()?.get();
251
252  // First startup flag
253  let mut first_startup = true;
254
255  // Cancel token for ACME and process metrics
256  let mut background_cancel_token: CancellationToken = CancellationToken::new();
257
258  // Cancel token for OCSP stapling
259  let mut ocsp_cancel_token: CancellationToken = CancellationToken::new();
260
261  // Secondary Tokio runtime
262  let secondary_runtime = tokio::runtime::Builder::new_multi_thread()
263    .worker_threads(match available_parallelism / 2 {
264      0 => 1,
265      non_zero => non_zero,
266    })
267    .thread_name("Secondary runtime")
268    .enable_all()
269    .build()?;
270
271  loop {
272    // Obtain the module loaders
273    let mut module_loaders = obtain_module_loaders();
274
275    // Obtain the observability backend loaders
276    let mut observability_backend_loaders = obtain_observability_backend_loaders();
277
278    // Load the configuration
279    let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
280
281    // Process the configurations
282    let configs_to_process = merge_duplicates(configs_to_process);
283    let configs_to_process = remove_and_add_global_configuration(configs_to_process);
284    let configs_to_process = premerge_configuration(configs_to_process);
285    let (configs_to_process, first_module_error, unused_properties) = load_modules(
286      configs_to_process,
287      &mut module_loaders,
288      &mut observability_backend_loaders,
289      &secondary_runtime,
290    );
291
292    // Finalize the configurations
293    let server_configurations = Arc::new(ServerConfigurations::new(configs_to_process));
294
295    let global_configuration = server_configurations.find_global_configuration();
296    let global_configuration_clone = global_configuration.clone();
297
298    let secondary_runtime_ref = &secondary_runtime;
299
300    // Reference to cancel tokens
301    let background_cancel_token_ref = &mut background_cancel_token;
302    let ocsp_cancel_token_ref = &mut ocsp_cancel_token;
303
304    // Execute the rest
305    let execute_rest = move || {
306      if let Some(first_module_error) = first_module_error {
307        // Error out if there was a module error
308        Err(first_module_error)?;
309      }
310
311      // Log unused properties
312      for unused_property in unused_properties {
313        for logging_tx in global_configuration
314          .as_ref()
315          .map_or(&vec![], |c| &c.observability.log_channels)
316        {
317          logging_tx
318            .send_blocking(LogMessage::new(
319              format!("Unused configuration property detected: \"{unused_property}\""),
320              true,
321            ))
322            .unwrap_or_default();
323        }
324      }
325
326      // Configure cryptography provider for Rustls
327      let crypto_provider = init_crypto_provider(global_configuration.as_deref())?;
328
329      // Install a process-wide cryptography provider. If it fails, then error it out.
330      if crypto_provider.clone().install_default().is_err() && first_startup {
331        Err(anyhow::anyhow!("Cannot install a process-wide cryptography provider"))?;
332      }
333
334      let crypto_provider = Arc::new(crypto_provider);
335
336      // Build TLS configuration
337      let tls_config_builder_wants_versions = ServerConfig::builder_with_provider(crypto_provider.clone());
338      let tls_config_builder_wants_verifier =
339        set_tls_version(tls_config_builder_wants_versions, global_configuration.as_deref())?;
340
341      let tls_config_builder_wants_server_cert = if let Some(client_cert_path) = global_configuration
342        .as_deref()
343        .and_then(|c| get_value!("tls_client_certificate", c))
344        .and_then(|v| v.as_str())
345      {
346        let mut roots = RootCertStore::empty();
347        let client_certificate_cas = load_certs(client_cert_path)?;
348        for cert in client_certificate_cas {
349          roots.add(cert)?;
350        }
351        tls_config_builder_wants_verifier
352          .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
353      } else if global_configuration
354        .as_deref()
355        .and_then(|c| get_value!("tls_client_certificate", c))
356        .and_then(|v| v.as_bool())
357        .unwrap_or(false)
358      {
359        let roots = (|| {
360          let certs_result = load_native_certs();
361          if !certs_result.errors.is_empty() {
362            return None;
363          }
364          let certs = certs_result.certs;
365
366          let mut roots = RootCertStore::empty();
367          for cert in certs {
368            if roots.add(cert).is_err() {
369              return None;
370            }
371          }
372
373          Some(roots)
374        })()
375        .unwrap_or(RootCertStore {
376          roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
377        });
378
379        tls_config_builder_wants_verifier
380          .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
381      } else {
382        tls_config_builder_wants_verifier.with_no_client_auth()
383      };
384
385      let enable_proxy_protocol = global_configuration
386        .as_ref()
387        .and_then(|c| get_value!("protocol_proxy", c))
388        .and_then(|v| v.as_bool())
389        .unwrap_or(false);
390      let protocols = global_configuration
391        .as_ref()
392        .and_then(|c| get_entry!("protocols", c))
393        .map(|e| e.values.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>())
394        .unwrap_or(vec!["h1", "h2"]);
395
396      if enable_proxy_protocol && protocols.contains(&"h3") {
397        Err(anyhow::anyhow!("PROXY protocol isn't supported with HTTP/3"))?
398      }
399
400      let default_http_port = read_default_port(global_configuration.as_deref(), false);
401      let default_https_port = read_default_port(global_configuration.as_deref(), true);
402
403      let mut tls_build_ctx = TlsBuildContext::default();
404      let memory_acme_account_cache_data: Arc<tokio::sync::RwLock<HashMap<String, Vec<u8>>>> = Default::default();
405      let mut invalid_wildcard_domains: HashSet<String> = HashSet::new();
406
407      // Iterate server configurations (TLS configuration)
408      for server in &server_configurations.host_configs {
409        let hostname = server.filters.hostname.as_deref();
410        if let Some(hostname) = hostname {
411          if hostname.contains("*.") && (hostname == "*." || !hostname.starts_with("*.")) {
412            invalid_wildcard_domains.insert(hostname.to_string());
413          }
414        }
415
416        if should_skip_server(server) {
417          continue;
418        }
419
420        let sni_hostname = resolve_sni_hostname(&server.filters);
421        let https_port = server.filters.port.or(default_https_port);
422
423        handle_nonencrypted_ports(&mut tls_build_ctx, server, default_http_port);
424
425        if let Some(https_port) = https_port {
426          let manual_tls_entry_option = manual_tls_entry(server);
427          if get_entry!("auto_tls", server)
428            .and_then(|e| e.values.first())
429            .and_then(|v| v.as_bool())
430            .unwrap_or(server.filters.port.is_none() && manual_tls_entry_option.is_none())
431          {
432            if let Some(error_log_message) = handle_automatic_tls(
433              &mut tls_build_ctx,
434              server,
435              https_port,
436              server.filters.ip,
437              sni_hostname.clone(),
438              crypto_provider.clone(),
439              memory_acme_account_cache_data.clone(),
440            )? {
441              for logging_tx in global_configuration
442                .as_ref()
443                .map_or(&vec![], |c| &c.observability.log_channels)
444              {
445                logging_tx.send_blocking(error_log_message.clone()).unwrap_or_default();
446              }
447            } else {
448              continue;
449            }
450          }
451          if let Some((cert, key)) = manual_tls_entry(server) {
452            handle_manual_tls(
453              &mut tls_build_ctx,
454              &crypto_provider,
455              https_port,
456              server.filters.ip,
457              sni_hostname,
458              cert,
459              key,
460            )?;
461          }
462        }
463      }
464
465      for invalid_wildcard_domain in invalid_wildcard_domains {
466        for logging_tx in global_configuration
467          .as_ref()
468          .map_or(&vec![], |c| &c.observability.log_channels)
469        {
470          logging_tx
471            .send_blocking(LogMessage::new(
472              format!(
473                "Invalid wildcard domain detected: \"{invalid_wildcard_domain}\". \
474                  It should be in the form of \"*.example.com\" (that means wildcard is at the beginning)."
475              ),
476              true,
477            ))
478            .unwrap_or_default();
479        }
480      }
481
482      // If HTTP/1.1 isn't enabled, don't listen to non-encrypted ports
483      if !protocols.contains(&"h1") {
484        tls_build_ctx.nonencrypted_ports.clear();
485      }
486
487      for (_, tls_port) in tls_build_ctx.tls_ports.keys() {
488        if tls_build_ctx.nonencrypted_ports.contains(tls_port) {
489          tls_build_ctx.nonencrypted_ports.remove(tls_port);
490        }
491      }
492
493      // Cancel OCSP stapling background tasks
494      ocsp_cancel_token_ref.cancel();
495      *ocsp_cancel_token_ref = CancellationToken::new();
496
497      // Create TLS server configurations
498      let mut quic_tls_configs = HashMap::new();
499      let mut tls_configs = HashMap::new();
500      let mut acme_tls_alpn_01_configs = HashMap::new();
501      let certified_keys_to_preload = Arc::new(tls_build_ctx.certified_keys_to_preload);
502      for (tls_port, sni_resolver) in tls_build_ctx.tls_ports.into_iter() {
503        let enable_ocsp_stapling = global_configuration
504          .as_ref()
505          .and_then(|c| get_value!("ocsp_stapling", c))
506          .and_then(|v| v.as_bool())
507          .unwrap_or(true);
508        let resolver: Arc<dyn ResolvesServerCert> = if enable_ocsp_stapling {
509          let logging_tx = global_configuration
510            .as_ref()
511            .map_or(vec![], |c| c.observability.log_channels.clone());
512
513          let stapler = OcspStapler::new(Arc::new(sni_resolver), secondary_runtime_ref, logging_tx);
514          if let Some(certified_keys_to_preload) = certified_keys_to_preload.get(&tls_port) {
515            for certified_key in certified_keys_to_preload {
516              stapler.preload(certified_key.clone());
517            }
518          }
519          let stapler_arc = Arc::new(stapler);
520
521          let stapler_arc_clone = stapler_arc.clone();
522          let ocsp_cancel_token_clone = ocsp_cancel_token_ref.clone();
523          secondary_runtime_ref.spawn(async move {
524            ocsp_cancel_token_clone.cancelled().await;
525            stapler_arc_clone.stop().await;
526          });
527
528          stapler_arc
529        } else {
530          Arc::new(sni_resolver)
531        };
532        let mut tls_config = tls_config_builder_wants_server_cert
533          .clone()
534          .with_cert_resolver(resolver);
535        if protocols.contains(&"h3") {
536          // TLS configuration used for QUIC listener
537          let mut quic_tls_config = tls_config.clone();
538          quic_tls_config.max_early_data_size = u32::MAX;
539          quic_tls_config.alpn_protocols.insert(0, b"h3-29".to_vec());
540          quic_tls_config.alpn_protocols.insert(0, b"h3".to_vec());
541          quic_tls_configs.insert(tls_port, Arc::new(quic_tls_config));
542        }
543        if protocols.contains(&"h1") {
544          tls_config.alpn_protocols.insert(0, b"http/1.0".to_vec());
545          tls_config.alpn_protocols.insert(0, b"http/1.1".to_vec());
546        }
547        if protocols.contains(&"h2") {
548          tls_config.alpn_protocols.insert(0, b"h2".to_vec());
549        }
550        tls_configs.insert(tls_port, Arc::new(tls_config));
551      }
552      for (tls_port, sni_resolver) in tls_build_ctx.acme_tls_alpn_01_resolvers.into_iter() {
553        let mut tls_config = tls_config_builder_wants_server_cert
554          .clone()
555          .with_cert_resolver(Arc::new(sni_resolver));
556        tls_config.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()];
557        acme_tls_alpn_01_configs.insert(tls_port, Arc::new(tls_config));
558      }
559
560      let (listener_handler_tx, listener_handler_rx) = &**LISTENER_HANDLER_CHANNEL;
561      let mut tcp_listeners = TCP_LISTENERS
562        .lock()
563        .map_err(|_| anyhow::anyhow!("Can't access the TCP listeners"))?;
564      let mut quic_listeners = QUIC_LISTENERS
565        .lock()
566        .map_err(|_| anyhow::anyhow!("Can't access the QUIC listeners"))?;
567      let mut listened_socket_addresses = Vec::new();
568      let mut quic_listened_socket_addresses = Vec::new();
569      let listen_ip_addr = global_configuration
570        .as_deref()
571        .and_then(|c| get_value!("listen_ip", c))
572        .and_then(|v| v.as_str())
573        .map_or(Ok(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), |a| a.parse())
574        .map_err(|_| anyhow::anyhow!("Invalid IP address to listen to"))?;
575      for (tcp_port, encrypted) in tls_build_ctx
576        .nonencrypted_ports
577        .iter()
578        .map(|p| (*p, false))
579        .chain(tls_configs.keys().map(|p| (p.1, true)))
580      {
581        let socket_address = SocketAddr::new(listen_ip_addr, tcp_port);
582        listened_socket_addresses.push((socket_address, encrypted));
583      }
584      let mut quic_tls_configs_processed: HashMap<(Option<IpAddr>, u16), Arc<quinn::ServerConfig>> =
585        HashMap::with_capacity(quic_tls_configs.len());
586      let mut had_quic_ports = HashSet::new();
587      for ((quic_ip, quic_port), quic_tls_config) in quic_tls_configs.into_iter() {
588        let quic_tls_config2_option: Option<quinn::crypto::rustls::QuicServerConfig> =
589          quic_tls_config.clone().try_into().ok();
590        if let Some(quic_tls_config2) = quic_tls_config2_option {
591          quic_tls_configs_processed.insert(
592            (quic_ip, quic_port),
593            Arc::new(quinn::ServerConfig::with_crypto(Arc::new(quic_tls_config2))),
594          );
595        }
596        let socket_address = SocketAddr::new(listen_ip_addr, quic_port);
597        if quic_ip.is_none() {
598          if had_quic_ports.contains(&quic_port) {
599            quic_listened_socket_addresses.retain(|(sa, _)| sa != &socket_address);
600          }
601          quic_listened_socket_addresses.push((socket_address, quic_tls_config));
602          had_quic_ports.insert(quic_port);
603        } else if !had_quic_ports.contains(&quic_port) {
604          // Empty TLS server configuration
605          let tls_config2_option = rustls::ServerConfig::builder_with_provider(crypto_provider.clone())
606            .with_safe_default_protocol_versions()
607            .ok()
608            .map(|b| {
609              b.with_no_client_auth()
610                .with_cert_resolver(Arc::new(crate::util::CustomSniResolver::new()))
611            });
612          if let Some(quic_tls_config) = tls_config2_option {
613            quic_listened_socket_addresses.push((socket_address, Arc::new(quic_tls_config)));
614            had_quic_ports.insert(quic_port);
615          }
616        }
617      }
618
619      let enable_uring = global_configuration
620        .as_deref()
621        .and_then(|c| get_value!("io_uring", c))
622        .and_then(|v| v.as_bool());
623      let mut uring_enabled_locked = URING_ENABLED
624        .lock()
625        .map_err(|_| anyhow::anyhow!("Can't access the enabled `io_uring` option"))?;
626      let shutdown_handlers = enable_uring != *uring_enabled_locked;
627      let mut tcp_listener_socketaddrs_to_remove = Vec::new();
628      let mut quic_listener_socketaddrs_to_remove = Vec::new();
629      for (key, value) in &*tcp_listeners {
630        if enable_uring != *uring_enabled_locked
631          || (!listened_socket_addresses.contains(&(*key, true)) && !listened_socket_addresses.contains(&(*key, false)))
632        {
633          // Shut down the TCP listener
634          value.cancel();
635
636          // Push the the TCP listener address to remove
637          tcp_listener_socketaddrs_to_remove.push(*key);
638        }
639      }
640      for (key, value) in &*quic_listeners {
641        let mut contains = false;
642        for key2 in &quic_listened_socket_addresses {
643          if key2.0 == *key {
644            contains = true;
645            break;
646          }
647        }
648        if !contains {
649          // Shut down the QUIC listener
650          value.0.cancel();
651
652          // Push the the QUIC listener address to remove
653          quic_listener_socketaddrs_to_remove.push(*key);
654        }
655      }
656      *uring_enabled_locked = enable_uring;
657      drop(uring_enabled_locked);
658
659      for key_to_remove in tcp_listener_socketaddrs_to_remove {
660        // Remove the TCP listener
661        tcp_listeners.remove(&key_to_remove);
662      }
663
664      for key_to_remove in quic_listener_socketaddrs_to_remove {
665        // Remove the QUIC listener
666        quic_listeners.remove(&key_to_remove);
667      }
668
669      // Get a global logger for listeners
670      let (global_logging_tx, global_logging_rx) = &**LISTENER_LOGGING_CHANNEL;
671      let global_logger = if global_configuration
672        .as_ref()
673        .is_none_or(|c| c.observability.log_channels.is_empty())
674      {
675        None
676      } else {
677        let global_configuration_clone = global_configuration.clone();
678        secondary_runtime_ref.spawn(async move {
679          while let Ok(log_message) = global_logging_rx.recv().await {
680            for logging_tx in global_configuration_clone
681              .as_ref()
682              .map_or(&vec![], |c| &c.observability.log_channels)
683            {
684              logging_tx.send(log_message.clone()).await.unwrap_or_default();
685            }
686          }
687        });
688        Some(global_logging_tx.clone())
689      };
690
691      let (io_uring_disabled_tx, io_uring_disabled_rx) = async_channel::unbounded();
692      if let Some(global_logger) = &global_logger {
693        let global_logger = global_logger.clone();
694        secondary_runtime_ref.spawn(async move {
695          while let Ok(err) = io_uring_disabled_rx.recv().await {
696            if let Some(err) = err {
697              global_logger
698                .send(LogMessage::new(
699                  format!("Can't configure io_uring: {err}. Ferron may run with io_uring disabled."),
700                  true,
701                ))
702                .await
703                .unwrap_or_default();
704              break;
705            }
706          }
707
708          io_uring_disabled_rx.close();
709        });
710      } else {
711        io_uring_disabled_rx.close();
712      }
713
714      let mut acme_configs = tls_build_ctx.acme_configs;
715      let mut acme_on_demand_configs = tls_build_ctx.acme_on_demand_configs;
716      let memory_acme_account_cache_data_clone = memory_acme_account_cache_data.clone();
717
718      // Preload the cached certificates before spawning the background ACME task
719      let (acme_configs, acme_on_demand_configs, existing_combinations) = secondary_runtime_ref.block_on(async move {
720        let mut existing_combinations = HashSet::new();
721
722        for acme_config in &mut acme_configs {
723          // Install the certificates from the cache if they're valid
724          check_certificate_validity_or_install_cached(acme_config, None)
725            .await
726            .unwrap_or_default();
727        }
728
729        for acme_on_demand_config in &mut acme_on_demand_configs {
730          for cached_domain in get_cached_domains(acme_on_demand_config).await {
731            let mut acme_config = convert_on_demand_config(
732              acme_on_demand_config,
733              cached_domain.clone(),
734              memory_acme_account_cache_data_clone.clone(),
735            )
736            .await;
737
738            existing_combinations.insert((cached_domain, acme_on_demand_config.port));
739
740            // Install the certificates from the cache if they're valid
741            check_certificate_validity_or_install_cached(&mut acme_config, None)
742              .await
743              .unwrap_or_default();
744
745            acme_configs.push(acme_config);
746          }
747        }
748
749        (acme_configs, acme_on_demand_configs, existing_combinations)
750      });
751
752      let inner_handler_data = ReloadableHandlerData {
753        configurations: server_configurations,
754        tls_configs: Arc::new(tls_configs),
755        http3_enabled: !quic_listened_socket_addresses.is_empty(),
756        acme_tls_alpn_01_configs: Arc::new(acme_tls_alpn_01_configs),
757        acme_http_01_resolvers: tls_build_ctx.acme_http_01_resolvers,
758        quic_tls_configs: Arc::new(quic_tls_configs_processed),
759        enable_proxy_protocol,
760      };
761      let reloadable_handler_data = if let Some(data) = SERVER_CONFIG_ARCSWAP.get().cloned() {
762        data.swap(Arc::new(inner_handler_data));
763        data
764      } else {
765        let reloadable_handler_data = Arc::new(ArcSwap::from_pointee(inner_handler_data));
766        let _ = SERVER_CONFIG_ARCSWAP.set(reloadable_handler_data.clone());
767        reloadable_handler_data
768      };
769
770      let mut start_new_handlers = true;
771      if let Ok(mut handlers_locked) = HANDLERS.lock() {
772        if shutdown_handlers {
773          while let Some((cancel_token, _)) = handlers_locked.pop() {
774            cancel_token.cancel();
775          }
776        } else {
777          for (_, graceful_shutdown) in handlers_locked.iter() {
778            start_new_handlers = false;
779            let _ = graceful_shutdown.send_blocking(());
780          }
781        }
782      }
783
784      let acme_on_demand_rx = tls_build_ctx.acme_on_demand_rx;
785      let on_demand_tls_ask_endpoint = match global_configuration
786        .as_ref()
787        .and_then(|c| get_value!("auto_tls_on_demand_ask", c))
788        .and_then(|v| v.as_str())
789        .map(|u| u.parse::<hyper::Uri>())
790      {
791        Some(Ok(uri)) => Some(uri),
792        Some(Err(err)) => Err(anyhow::anyhow!(
793          "Failed to parse automatic TLS on demand asking endpoint URI: {}",
794          err
795        ))?,
796        None => None,
797      };
798      let on_demand_tls_ask_endpoint_verify = !global_configuration
799        .as_ref()
800        .and_then(|c| get_value!("auto_tls_on_demand_ask_no_verification", c))
801        .and_then(|v| v.as_bool())
802        .unwrap_or(false);
803
804      // Cancel some background tasks
805      background_cancel_token_ref.cancel();
806      *background_cancel_token_ref = CancellationToken::new();
807
808      if !acme_configs.is_empty() || !acme_on_demand_configs.is_empty() {
809        // Spawn a task to handle ACME certificate provisioning, one certificate at time
810        let acme_logger = ErrorLogger::new_multiple(
811          global_configuration
812            .as_ref()
813            .map_or(vec![], |c| c.observability.log_channels.clone()),
814        );
815        secondary_runtime_ref.spawn(background_acme_task(
816          acme_configs,
817          acme_on_demand_configs,
818          memory_acme_account_cache_data,
819          acme_on_demand_rx,
820          on_demand_tls_ask_endpoint,
821          on_demand_tls_ask_endpoint_verify,
822          acme_logger,
823          crypto_provider,
824          existing_combinations,
825          Some(background_cancel_token_ref.clone()),
826        ));
827      }
828
829      // Process metrics initialization
830      #[cfg(any(target_os = "linux", target_os = "android"))]
831      if let Some(metrics_channels) = global_configuration
832        .as_ref()
833        .map(|c| &c.observability.metric_channels)
834        .cloned()
835      {
836        let background_cancel_token = background_cancel_token_ref.clone();
837        secondary_runtime_ref.spawn(async move {
838          tokio::select! {
839            biased;
840
841            _ = background_cancel_token.cancelled() => {}
842            _ = crate::setup::metrics::background_metrics(
843              metrics_channels,
844              available_parallelism,
845            ) => {}
846          }
847        });
848      }
849
850      // Spawn request handler threads
851      if start_new_handlers {
852        let mut handler_shutdown_channels = HANDLERS.lock().expect("Can't access the handler threads");
853
854        // The number of handler threads, minus one for the multi-cancel, because without "minus one",
855        // there would be a "deadlock" when shutting down handler threads, and they won't be able to shut down
856        let multi_cancel = Arc::new(MultiCancel::new(available_parallelism.saturating_sub(1)));
857
858        #[cfg(feature = "runtime-vibeio")]
859        if let Some(core_ids) = core_affinity::get_core_ids() {
860          for core_id in core_ids {
861            handler_shutdown_channels.push(create_http_handler(
862              reloadable_handler_data.clone(),
863              listener_handler_rx.clone(),
864              enable_uring,
865              io_uring_disabled_tx.clone(),
866              multi_cancel.clone(),
867              Some(core_id),
868            )?);
869          }
870        } else {
871          for _ in 0..available_parallelism {
872            handler_shutdown_channels.push(create_http_handler(
873              reloadable_handler_data.clone(),
874              listener_handler_rx.clone(),
875              enable_uring,
876              io_uring_disabled_tx.clone(),
877              multi_cancel.clone(),
878              None,
879            )?);
880          }
881        }
882        #[cfg(not(feature = "runtime-vibeio"))]
883        for _ in 0..available_parallelism {
884          handler_shutdown_channels.push(create_http_handler(
885            reloadable_handler_data.clone(),
886            listener_handler_rx.clone(),
887            enable_uring,
888            io_uring_disabled_tx.clone(),
889            multi_cancel.clone(),
890          )?);
891        }
892      }
893
894      // Error out, if server is configured to listen to no port
895      if listened_socket_addresses.is_empty() && quic_listened_socket_addresses.is_empty() {
896        Err(anyhow::anyhow!("The server is configured to listen to no port"))?
897      }
898
899      let tcp_send_buffer_size = global_configuration
900        .as_deref()
901        .and_then(|c| get_value!("tcp_send_buffer", c))
902        .and_then(|v| v.as_i128())
903        .map(|v| v as usize);
904      let tcp_recv_buffer_size = global_configuration
905        .as_deref()
906        .and_then(|c| get_value!("tcp_recv_buffer", c))
907        .and_then(|v| v.as_i128())
908        .map(|v| v as usize);
909      for (socket_address, encrypted) in listened_socket_addresses {
910        if let std::collections::hash_map::Entry::Vacant(e) = tcp_listeners.entry(socket_address) {
911          // Create a TCP listener
912          e.insert(create_tcp_listener(
913            socket_address,
914            encrypted,
915            listener_handler_tx.clone(),
916            enable_uring,
917            global_logger.clone(),
918            first_startup,
919            (tcp_send_buffer_size, tcp_recv_buffer_size),
920            io_uring_disabled_tx.clone(),
921          )?);
922        }
923      }
924
925      // Drop TCP listener mutex guard
926      drop(tcp_listeners);
927
928      for (socket_address, tls_config) in quic_listened_socket_addresses {
929        if let Some(quic_listener_entry) = quic_listeners.get(&socket_address) {
930          // Replace the TLS configuration in the QUIC listener
931          let (_, tls_quic_listener) = quic_listener_entry;
932          tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
933        } else {
934          // Create a QUIC listener
935          quic_listeners.insert(
936            socket_address,
937            create_quic_listener(
938              socket_address,
939              tls_config,
940              listener_handler_tx.clone(),
941              global_logger.clone(),
942              first_startup,
943            )?,
944          );
945        }
946      }
947
948      // Drop QUIC listener mutex guard
949      drop(quic_listeners);
950
951      let shutdown_result = handle_shutdown_signals(secondary_runtime_ref);
952
953      Ok::<_, Box<dyn Error + Send + Sync>>(shutdown_result)
954    };
955
956    match execute_rest() {
957      Ok(to_restart) => {
958        if to_restart {
959          first_startup = false;
960          println!("Reloading the server configuration...");
961        } else {
962          if let Ok(mut handlers_locked) = HANDLERS.lock() {
963            while let Some((cancel_token, _)) = handlers_locked.pop() {
964              cancel_token.cancel();
965            }
966          }
967          drop(secondary_runtime);
968          break;
969        }
970      }
971      Err(err) => {
972        for logging_tx in global_configuration_clone
973          .as_ref()
974          .map_or(&vec![], |c| &c.observability.log_channels)
975        {
976          logging_tx
977            .send_blocking(LogMessage::new(err.to_string(), true))
978            .unwrap_or_default();
979        }
980        std::thread::sleep(Duration::from_millis(100));
981        Err(err)?
982      }
983    }
984
985    drop(observability_backend_loaders);
986    drop(module_loaders);
987  }
988
989  Ok(())
990}
991
992fn obtain_configuration_adapters() -> (
993  HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
994  Vec<&'static str>,
995) {
996  // Configuration adapters
997  let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
998  let mut all_adapters = Vec::new();
999
1000  // Configuration adapter registration macro
1001  macro_rules! register_configuration_adapter {
1002    ($name:literal, $adapter:expr) => {
1003      configuration_adapters.insert($name.to_string(), Box::new($adapter));
1004      all_adapters.push($name);
1005    };
1006  }
1007
1008  // Register configuration adapters
1009  register_configuration_adapter!("kdl", config::adapters::kdl::KdlConfigurationAdapter::new());
1010  #[cfg(feature = "config-yaml-legacy")]
1011  register_configuration_adapter!(
1012    "yaml-legacy",
1013    config::adapters::yaml_legacy::YamlLegacyConfigurationAdapter::new()
1014  );
1015  #[cfg(feature = "config-docker-auto")]
1016  register_configuration_adapter!(
1017    "docker-auto",
1018    config::adapters::docker_auto::DockerAutoConfigurationAdapter::new()
1019  );
1020
1021  (configuration_adapters, all_adapters)
1022}
1023
1024/// Determines the default configuration adapter
1025#[cfg(feature = "config-yaml-legacy")]
1026fn determine_default_configuration_adapter(path: &Path) -> &'static str {
1027  match path
1028    .extension()
1029    .and_then(|s| s.to_str())
1030    .map(|s| s.to_lowercase())
1031    .as_deref()
1032  {
1033    Some("yaml") | Some("yml") => "yaml-legacy",
1034    _ => "kdl",
1035  }
1036}
1037
1038/// Determines the default configuration adapter
1039#[cfg(not(feature = "config-yaml-legacy"))]
1040fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
1041  "kdl"
1042}
1043
1044fn print_version() {
1045  // Print the server version and build information
1046  println!("Ferron {}", build::PKG_VERSION);
1047  println!("  Compiled on: {}", build::BUILD_TIME);
1048  println!("  Git commit: {}", build::COMMIT_HASH);
1049  println!("  Build target: {}", build::BUILD_TARGET);
1050  println!("  Rust version: {}", build::RUST_VERSION);
1051  println!("  Build host: {}", build::BUILD_OS);
1052  if shadow_rs::is_debug() {
1053    println!("WARNING: This is a debug build. It is not recommended for production use.");
1054  }
1055}
1056
1057/// The main entry point of the application
1058fn main() {
1059  #[cfg(feature = "runtime-vibeio")]
1060  BEMalloc::init();
1061
1062  // Set the panic handler
1063  install_panic_hook();
1064
1065  // Obtain the configuration adapters
1066  let (configuration_adapters, _all_adapters) = obtain_configuration_adapters();
1067
1068  // Parse command-line arguments
1069  let args = FerronArgs::parse();
1070
1071  if args.module_config {
1072    // Dump the used compile-time module configuration and exit
1073    println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
1074    return;
1075  } else if args.version {
1076    print_version();
1077    return;
1078  }
1079
1080  // Start the server!
1081  if let Err(err) = before_starting_server(args, configuration_adapters) {
1082    eprintln!("Error while running a server: {err}");
1083    std::process::exit(1);
1084  }
1085}