mirror of
https://git.mentality.rip/numas13/xash3d-master.git
synced 2025-01-22 04:44:31 +00:00
master: reload config with SIGUSR1
This commit is contained in:
parent
e30d1c2a65
commit
4039b9fc43
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -262,6 +262,25 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.37"
|
version = "2.0.37"
|
||||||
@ -491,6 +510,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
|
"signal-hook",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"toml",
|
"toml",
|
||||||
"xash3d-protocol",
|
"xash3d-protocol",
|
||||||
|
@ -19,6 +19,7 @@ fastrand = "2.0.1"
|
|||||||
serde = { version = "1.0.188", features = ["derive"] }
|
serde = { version = "1.0.188", features = ["derive"] }
|
||||||
toml = "0.5.11"
|
toml = "0.5.11"
|
||||||
blake2b_simd = "<0.6"
|
blake2b_simd = "<0.6"
|
||||||
|
signal-hook = { version = "0.3.17", default-features = false }
|
||||||
xash3d-protocol = { path = "../protocol", version = "0.1.0" }
|
xash3d-protocol = { path = "../protocol", version = "0.1.0" }
|
||||||
|
|
||||||
[dependencies.chrono]
|
[dependencies.chrono]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[log]
|
[log]
|
||||||
# Possible values: 0-5, off, error, warn, info, debug, trace
|
# Possible values: 0-5, off, error, warn, info, debug, trace
|
||||||
level = "warn"
|
level = "info"
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
ip = "0.0.0.0"
|
ip = "0.0.0.0"
|
||||||
@ -21,7 +21,7 @@ admin = 10
|
|||||||
version = "0.19"
|
version = "0.19"
|
||||||
update_title = "https://github.com/FWGS/xash3d-fwgs"
|
update_title = "https://github.com/FWGS/xash3d-fwgs"
|
||||||
update_map = "Update please"
|
update_map = "Update please"
|
||||||
update_addr = "mentality.rip:27010"
|
update_addr = "mentality.rip"
|
||||||
|
|
||||||
[hash]
|
[hash]
|
||||||
len = 64
|
len = 64
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
// SPDX-FileCopyrightText: 2023 Denis Drakhnia <numas13@gmail.com>
|
// SPDX-FileCopyrightText: 2023 Denis Drakhnia <numas13@gmail.com>
|
||||||
|
|
||||||
use log::{LevelFilter, Metadata, Record};
|
use log::{Metadata, Record};
|
||||||
|
|
||||||
struct Logger;
|
struct Logger;
|
||||||
|
|
||||||
@ -30,9 +30,8 @@ impl log::Log for Logger {
|
|||||||
|
|
||||||
static LOGGER: Logger = Logger;
|
static LOGGER: Logger = Logger;
|
||||||
|
|
||||||
pub fn init(level_filter: LevelFilter) {
|
pub fn init() {
|
||||||
if let Err(e) = log::set_logger(&LOGGER) {
|
if let Err(e) = log::set_logger(&LOGGER) {
|
||||||
eprintln!("Failed to initialize logger: {}", e);
|
eprintln!("Failed to initialize logger: {}", e);
|
||||||
}
|
}
|
||||||
log::set_max_level(level_filter);
|
|
||||||
}
|
}
|
||||||
|
@ -6,35 +6,74 @@ mod config;
|
|||||||
mod logger;
|
mod logger;
|
||||||
mod master_server;
|
mod master_server;
|
||||||
|
|
||||||
use log::error;
|
use std::process;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
fn main() {
|
use log::{error, info};
|
||||||
|
use signal_hook::consts::signal::*;
|
||||||
|
use signal_hook::flag as signal_flag;
|
||||||
|
|
||||||
|
use crate::cli::Cli;
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::master_server::{Error, MasterServer};
|
||||||
|
|
||||||
|
fn load_config(cli: &Cli) -> Result<Config, config::Error> {
|
||||||
|
let mut cfg = config::load(cli.config_path.as_ref())?;
|
||||||
|
|
||||||
|
if let Some(level) = cli.log_level {
|
||||||
|
cfg.log.level = level;
|
||||||
|
}
|
||||||
|
if let Some(ip) = cli.listen_ip {
|
||||||
|
cfg.server.ip = ip;
|
||||||
|
}
|
||||||
|
if let Some(port) = cli.listen_port {
|
||||||
|
cfg.server.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::set_max_level(cfg.log.level);
|
||||||
|
|
||||||
|
Ok(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() -> Result<(), Error> {
|
||||||
let cli = cli::parse().unwrap_or_else(|e| {
|
let cli = cli::parse().unwrap_or_else(|e| {
|
||||||
eprintln!("{}", e);
|
eprintln!("{}", e);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut cfg = config::load(cli.config_path.as_ref()).unwrap_or_else(|e| {
|
logger::init();
|
||||||
|
|
||||||
|
let cfg = load_config(&cli).unwrap_or_else(|e| {
|
||||||
eprintln!("Failed to load config \"{}\": {}", cli.config_path, e);
|
eprintln!("Failed to load config \"{}\": {}", cli.config_path, e);
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(level) = cli.log_level {
|
let mut master = MasterServer::new(cfg)?;
|
||||||
cfg.log.level = level;
|
let sig_flag = Arc::new(AtomicBool::new(false));
|
||||||
}
|
signal_flag::register(SIGUSR1, sig_flag.clone())?;
|
||||||
|
|
||||||
if let Some(ip) = cli.listen_ip {
|
loop {
|
||||||
cfg.server.ip = ip;
|
master.run(&sig_flag)?;
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(port) = cli.listen_port {
|
if sig_flag.swap(false, Ordering::Relaxed) {
|
||||||
cfg.server.port = port;
|
info!("Reloading config from {}", cli.config_path);
|
||||||
}
|
|
||||||
|
|
||||||
logger::init(cfg.log.level);
|
match load_config(&cli) {
|
||||||
|
Ok(cfg) => {
|
||||||
if let Err(e) = master_server::run(cfg) {
|
if let Err(e) = master.update_config(cfg) {
|
||||||
error!("{}", e);
|
error!("{}", e);
|
||||||
std::process::exit(1);
|
}
|
||||||
|
}
|
||||||
|
Err(e) => error!("failed to load config: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if let Err(e) = run() {
|
||||||
|
error!("{}", e);
|
||||||
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
|
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::time::Instant;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use blake2b_simd::Params;
|
use blake2b_simd::Params;
|
||||||
use fastrand::Rng;
|
use fastrand::Rng;
|
||||||
@ -97,7 +98,7 @@ impl Counter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MasterServer {
|
pub struct MasterServer {
|
||||||
sock: UdpSocket,
|
sock: UdpSocket,
|
||||||
challenges: HashMap<SocketAddrV4, Entry<u32>>,
|
challenges: HashMap<SocketAddrV4, Entry<u32>>,
|
||||||
challenges_counter: Counter,
|
challenges_counter: Counter,
|
||||||
@ -137,38 +138,36 @@ where
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_update_addr(cfg: &Config, local_addr: SocketAddr) -> SocketAddrV4 {
|
||||||
|
if let Some(s) = cfg.client.update_addr.as_deref() {
|
||||||
|
let addr = if !s.contains(':') {
|
||||||
|
format!("{}:{}", s, local_addr.port())
|
||||||
|
} else {
|
||||||
|
s.to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
match resolve_socket_addr(&addr) {
|
||||||
|
Ok(Some(x)) => return x,
|
||||||
|
Ok(None) => error!("Update address: failed to resolve IPv4 for \"{}\"", addr),
|
||||||
|
Err(e) => error!("Update address: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match local_addr {
|
||||||
|
SocketAddr::V4(x) => x,
|
||||||
|
SocketAddr::V6(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl MasterServer {
|
impl MasterServer {
|
||||||
fn new(cfg: Config) -> Result<Self, Error> {
|
pub fn new(cfg: Config) -> Result<Self, Error> {
|
||||||
let addr = SocketAddr::new(cfg.server.ip, cfg.server.port);
|
let addr = SocketAddr::new(cfg.server.ip, cfg.server.port);
|
||||||
info!("Listen address: {}", addr);
|
info!("Listen address: {}", addr);
|
||||||
let sock = UdpSocket::bind(addr).map_err(Error::BindSocket)?;
|
let sock = UdpSocket::bind(addr).map_err(Error::BindSocket)?;
|
||||||
|
// make socket interruptable by singals
|
||||||
|
sock.set_read_timeout(Some(Duration::from_secs(u32::MAX as u64)))?;
|
||||||
|
|
||||||
let update_addr = {
|
let update_addr = resolve_update_addr(&cfg, addr);
|
||||||
let mut addr = None;
|
|
||||||
|
|
||||||
if let Some(update_addr) = cfg.client.update_addr {
|
|
||||||
addr = match resolve_socket_addr(&*update_addr) {
|
|
||||||
Ok(None) => {
|
|
||||||
error!(
|
|
||||||
"update address: failed to resolve IPv4 for \"{}\"",
|
|
||||||
update_addr
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("update address: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Ok(addr) => addr,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// fallback to local address
|
|
||||||
addr.unwrap_or_else(|| match sock.local_addr().unwrap() {
|
|
||||||
SocketAddr::V4(a) => a,
|
|
||||||
_ => todo!(),
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sock,
|
sock,
|
||||||
@ -193,10 +192,40 @@ impl MasterServer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&mut self) -> Result<(), Error> {
|
pub fn update_config(&mut self, cfg: Config) -> Result<(), Error> {
|
||||||
|
let local_addr = self.sock.local_addr()?;
|
||||||
|
let addr = SocketAddr::new(cfg.server.ip, cfg.server.port);
|
||||||
|
if local_addr != addr {
|
||||||
|
info!("Listen address: {}", addr);
|
||||||
|
self.sock = UdpSocket::bind(addr).map_err(Error::BindSocket)?;
|
||||||
|
// make socket interruptable by singals
|
||||||
|
self.sock
|
||||||
|
.set_read_timeout(Some(Duration::from_secs(u32::MAX as u64)))?;
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_addr = resolve_update_addr(&cfg, addr);
|
||||||
|
self.timeout = cfg.server.timeout;
|
||||||
|
self.clver = cfg.client.version;
|
||||||
|
self.update_title = cfg.client.update_title;
|
||||||
|
self.update_map = cfg.client.update_map;
|
||||||
|
self.admin_list = cfg.admin_list;
|
||||||
|
self.hash = cfg.hash;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self, sig_flag: &AtomicBool) -> Result<(), Error> {
|
||||||
let mut buf = [0; MAX_PACKET_SIZE];
|
let mut buf = [0; MAX_PACKET_SIZE];
|
||||||
loop {
|
while !sig_flag.load(Ordering::Relaxed) {
|
||||||
let (n, from) = self.sock.recv_from(&mut buf)?;
|
let (n, from) = match self.sock.recv_from(&mut buf) {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
io::ErrorKind::Interrupted => break,
|
||||||
|
io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock => continue,
|
||||||
|
_ => Err(e)?,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let from = match from {
|
let from = match from {
|
||||||
SocketAddr::V4(a) => a,
|
SocketAddr::V4(a) => a,
|
||||||
@ -210,6 +239,14 @@ impl MasterServer {
|
|||||||
error!("{}: {}", from, e);
|
error!("{}: {}", from, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
info!("Clear all servers and challenges");
|
||||||
|
self.challenges.clear();
|
||||||
|
self.servers.clear();
|
||||||
|
self.admin_challenges.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_packet(&mut self, from: SocketAddrV4, src: &[u8]) -> Result<(), Error> {
|
fn handle_packet(&mut self, from: SocketAddrV4, src: &[u8]) -> Result<(), Error> {
|
||||||
@ -505,7 +542,3 @@ impl MasterServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(cfg: Config) -> Result<(), Error> {
|
|
||||||
MasterServer::new(cfg)?.run()
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user