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