diff --git a/server-cli/src/main.rs b/server-cli/src/main.rs index c49aebd963..60d540c485 100644 --- a/server-cli/src/main.rs +++ b/server-cli/src/main.rs @@ -154,7 +154,11 @@ fn main() -> io::Result<()> { info!("Starting server..."); - let server_port = &server_settings.gameserver_address.port(); + if no_auth { + server_settings.auth_server_address = None; + } + + let protocols_and_addresses = server_settings.protocols_and_addresses.clone(); let metrics_port = &server_settings.metrics_address.port(); // Create server let mut server = Server::new( @@ -166,11 +170,13 @@ fn main() -> io::Result<()> { ) .expect("Failed to create server instance!"); - info!( - ?server_port, - ?metrics_port, - "Server is ready to accept connections." - ); + for (_, addr) in protocols_and_addresses { + info!( + ?addr, + ?metrics_port, + "Server is ready to accept connections." + ); + } let mut shutdown_coordinator = ShutdownCoordinator::new(Arc::clone(&sigusr1_signal)); diff --git a/server/src/lib.rs b/server/src/lib.rs index c3a083f323..a7649aa9ff 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -115,6 +115,8 @@ use crate::{ use hashbrown::HashMap; use std::sync::RwLock; +use crate::settings::Protocol; + #[cfg(feature = "plugins")] use { common::uid::UidAllocator, @@ -463,9 +465,8 @@ impl Server { ) .await }); - runtime.block_on(network.listen(ListenAddr::Tcp(settings.gameserver_address)))?; - runtime.block_on(network.listen(ListenAddr::Mpsc(14004)))?; - if let Some(quic) = &settings.quic_files { + + let quic_server_config = if let Some(quic) = &settings.quic_files { use rustls_pemfile::Item; use std::fs; match || -> Result<_, Box> { @@ -494,20 +495,42 @@ impl Server { let server_config = quinn::ServerConfig::with_single_cert(cert_chain, key)?; Ok(server_config) }() { - Ok(server_config) => { - warn!( - "QUIC is enabled. This is experimental and not recommended in production" - ); - runtime.block_on( - network - .listen(ListenAddr::Quic(settings.gameserver_address, server_config)), - )?; - }, + Ok(server_config) => Some(server_config), Err(e) => { - error!(?e, ?settings.quic_files, "Failed to load Quic Certificate, run without Quic") + error!(?e, ?settings.quic_files, "Failed to load the TLS certificate, running without QUIC"); + None + }, + } + } else { + None + }; + + let mut printed_quic_warning = false; + for (protocol, address) in &settings.protocols_and_addresses { + match protocol { + Protocol::Tcp => { + runtime.block_on(network.listen(ListenAddr::Tcp(*address)))?; + }, + Protocol::Quic => { + if let Some(server_config) = &quic_server_config { + runtime.block_on( + network.listen(ListenAddr::Quic(*address, server_config.clone())), + )?; + + if !printed_quic_warning { + warn!( + "QUIC is enabled. This is experimental and not recommended in \ + production" + ); + printed_quic_warning = true; + } + } }, } } + + runtime.block_on(network.listen(ListenAddr::Mpsc(14004)))?; + let connection_handler = ConnectionHandler::new(network, &runtime); // Initiate real-time world simulation diff --git a/server/src/settings.rs b/server/src/settings.rs index d23fd7698d..e50a95d23e 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -23,7 +23,7 @@ use portpicker::pick_unused_port; use serde::{Deserialize, Serialize}; use std::{ fs, - net::SocketAddr, + net::{Ipv4Addr, Ipv6Addr, SocketAddr}, path::{Path, PathBuf}, }; use tracing::{error, warn}; @@ -65,6 +65,12 @@ impl ServerBattleMode { } } +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub enum Protocol { + Quic, + Tcp, +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub enum CalendarMode { None, @@ -91,7 +97,7 @@ impl CalendarMode { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] pub struct Settings { - pub gameserver_address: SocketAddr, + pub protocols_and_addresses: Vec<(Protocol, SocketAddr)>, pub metrics_address: SocketAddr, pub auth_server_address: Option, pub quic_files: Option, @@ -121,8 +127,17 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Self { - gameserver_address: SocketAddr::from(([0; 4], 14004)), - metrics_address: SocketAddr::from(([0; 4], 14005)), + protocols_and_addresses: vec![ + ( + Protocol::Tcp, + SocketAddr::from((Ipv6Addr::UNSPECIFIED, 14004)), + ), + ( + Protocol::Tcp, + SocketAddr::from((Ipv4Addr::UNSPECIFIED, 14004)), + ), + ], + metrics_address: SocketAddr::from((Ipv4Addr::LOCALHOST, 14005)), auth_server_address: Some("https://auth.veloren.net".into()), quic_files: None, world_seed: DEFAULT_WORLD_SEED, @@ -195,14 +210,17 @@ impl Settings { pub fn singleplayer(path: &Path) -> Self { let load = Self::load(path); Self { - //BUG: theoretically another process can grab the port between here and server - // creation, however the timewindow is quite small - gameserver_address: SocketAddr::from(( - [127, 0, 0, 1], - pick_unused_port().expect("Failed to find unused port!"), - )), + // BUG: theoretically another process can grab the port between here and server + // creation, however the time window is quite small. + protocols_and_addresses: vec![( + Protocol::Tcp, + SocketAddr::from(( + Ipv4Addr::LOCALHOST, + pick_unused_port().expect("Failed to find unused port!"), + )), + )], metrics_address: SocketAddr::from(( - [127, 0, 0, 1], + Ipv4Addr::LOCALHOST, pick_unused_port().expect("Failed to find unused port!"), )), auth_server_address: None,