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
85fn 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
117fn before_starting_server(
119 args: FerronArgs,
120 configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
121) -> Result<(), Box<dyn Error + Send + Sync>> {
122 let temp_config_file: NamedTempFile;
125 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 "kdl"
223 } else {
224 determine_default_configuration_adapter(configuration_path)
225 };
226
227 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 let available_parallelism = thread::available_parallelism()?.get();
237
238 let mut first_startup = true;
240
241 let mut background_cancel_token: CancellationToken = CancellationToken::new();
243
244 let mut ocsp_cancel_token: CancellationToken = CancellationToken::new();
246
247 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 let mut module_loaders = obtain_module_loaders();
260
261 let mut observability_backend_loaders = obtain_observability_backend_loaders();
263
264 let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
266
267 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 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 let background_cancel_token_ref = &mut background_cancel_token;
288 let ocsp_cancel_token_ref = &mut ocsp_cancel_token;
289
290 let execute_rest = move || {
292 if let Some(first_module_error) = first_module_error {
293 Err(first_module_error)?;
295 }
296
297 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 let crypto_provider = init_crypto_provider(global_configuration.as_deref())?;
314
315 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 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 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 !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 ocsp_cancel_token_ref.cancel();
481 *ocsp_cancel_token_ref = CancellationToken::new();
482
483 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 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 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 value.cancel();
621
622 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 value.0.cancel();
637
638 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 tcp_listeners.remove(&key_to_remove);
648 }
649
650 for key_to_remove in quic_listener_socketaddrs_to_remove {
651 quic_listeners.remove(&key_to_remove);
653 }
654
655 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 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 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 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 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 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 #[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 if start_new_handlers {
838 let mut handler_shutdown_channels = HANDLERS.lock().expect("Can't access the handler threads");
839
840 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 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 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_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 let (_, tls_quic_listener) = quic_listener_entry;
918 tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
919 } else {
920 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_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 let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
984 let mut all_adapters = Vec::new();
985
986 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_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#[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#[cfg(not(feature = "config-yaml-legacy"))]
1026fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
1027 "kdl"
1028}
1029
1030fn print_version() {
1031 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
1043fn main() {
1045 #[cfg(feature = "runtime-vibeio")]
1046 BEMalloc::init();
1047
1048 install_panic_hook();
1050
1051 let (configuration_adapters, _all_adapters) = obtain_configuration_adapters();
1053
1054 let args = FerronArgs::parse();
1056
1057 if args.module_config {
1058 println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
1060 return;
1061 } else if args.version {
1062 print_version();
1063 return;
1064 }
1065
1066 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}