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 #[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
131fn before_starting_server(
133 args: FerronArgs,
134 configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
135) -> Result<(), Box<dyn Error + Send + Sync>> {
136 let temp_config_file: NamedTempFile;
139 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 "kdl"
237 } else {
238 determine_default_configuration_adapter(configuration_path)
239 };
240
241 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 let available_parallelism = thread::available_parallelism()?.get();
251
252 let mut first_startup = true;
254
255 let mut background_cancel_token: CancellationToken = CancellationToken::new();
257
258 let mut ocsp_cancel_token: CancellationToken = CancellationToken::new();
260
261 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 let mut module_loaders = obtain_module_loaders();
274
275 let mut observability_backend_loaders = obtain_observability_backend_loaders();
277
278 let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
280
281 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 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 let background_cancel_token_ref = &mut background_cancel_token;
302 let ocsp_cancel_token_ref = &mut ocsp_cancel_token;
303
304 let execute_rest = move || {
306 if let Some(first_module_error) = first_module_error {
307 Err(first_module_error)?;
309 }
310
311 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 let crypto_provider = init_crypto_provider(global_configuration.as_deref())?;
328
329 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 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 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 !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 ocsp_cancel_token_ref.cancel();
495 *ocsp_cancel_token_ref = CancellationToken::new();
496
497 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 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 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 value.cancel();
635
636 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 value.0.cancel();
651
652 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 tcp_listeners.remove(&key_to_remove);
662 }
663
664 for key_to_remove in quic_listener_socketaddrs_to_remove {
665 quic_listeners.remove(&key_to_remove);
667 }
668
669 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 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 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 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 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 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 #[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 if start_new_handlers {
852 let mut handler_shutdown_channels = HANDLERS.lock().expect("Can't access the handler threads");
853
854 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 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 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_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 let (_, tls_quic_listener) = quic_listener_entry;
932 tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
933 } else {
934 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_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 let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
998 let mut all_adapters = Vec::new();
999
1000 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_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#[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#[cfg(not(feature = "config-yaml-legacy"))]
1040fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
1041 "kdl"
1042}
1043
1044fn print_version() {
1045 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
1057fn main() {
1059 #[cfg(feature = "runtime-vibeio")]
1060 BEMalloc::init();
1061
1062 install_panic_hook();
1064
1065 let (configuration_adapters, _all_adapters) = obtain_configuration_adapters();
1067
1068 let args = FerronArgs::parse();
1070
1071 if args.module_config {
1072 println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
1074 return;
1075 } else if args.version {
1076 print_version();
1077 return;
1078 }
1079
1080 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}