diff --git a/Cargo.lock b/Cargo.lock index 1334bc0..7d22102 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -168,9 +168,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "bitflags" @@ -203,9 +203,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byteorder" @@ -260,9 +260,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2" dependencies = [ "bitflags", "clap_lex", @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" dependencies = [ "os_str_bytes", ] @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e" dependencies = [ "cc", "cxxbridge-flags", @@ -380,9 +380,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" +checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200" dependencies = [ "cc", "codespan-reporting", @@ -395,15 +395,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" +checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea" [[package]] name = "cxxbridge-macro" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e" dependencies = [ "proc-macro2", "quote", @@ -412,9 +412,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.12.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ "darling_core", "darling_macro", @@ -422,9 +422,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.12.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ "fnv", "ident_case", @@ -436,9 +436,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.12.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", @@ -447,18 +447,18 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.10.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.10.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling", "proc-macro2", @@ -468,9 +468,9 @@ dependencies = [ [[package]] name = "derive_builder_macro" -version = "0.10.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" dependencies = [ "derive_builder_core", "syn", @@ -745,9 +745,9 @@ dependencies = [ [[package]] name = "gloo-timers" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" dependencies = [ "futures-channel", "futures-core", @@ -843,9 +843,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" dependencies = [ "libc", "windows-sys", @@ -938,6 +938,7 @@ dependencies = [ "md-5", "minecraft-protocol", "named-binary-tag", + "nix", "notify", "pretty_env_logger", "proxy-protocol", @@ -1013,6 +1014,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg 1.1.0", +] + [[package]] name = "minecraft-protocol" version = "0.1.0" @@ -1122,6 +1132,20 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "libc", + "memoffset", + "pin-utils", + "static_assertions", +] + [[package]] name = "notify" version = "4.0.17" @@ -1255,9 +1279,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -1495,9 +1519,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ "bitflags", "errno", @@ -1620,6 +1644,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -1651,9 +1681,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -1691,9 +1721,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.24.1" +version = "1.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" +checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" dependencies = [ "autocfg 1.1.0", "bytes", @@ -1721,9 +1751,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -1968,45 +1998,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "ws2_32-sys" diff --git a/Cargo.toml b/Cargo.toml index 5912be7..809b674 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,16 +8,15 @@ homepage = "https://timvisee.com/projects/lazymc" repository = "https://gitlab.com/timvisee/lazymc" description = "Put your Minecraft server to rest when idle." keywords = ["minecraft", "server", "idle", "cli"] -categories = [ - "command-line-interface", - "games", -] -exclude = [ - "/.github", - "/contrib", -] +categories = ["command-line-interface", "games"] +exclude = ["/.github", "/contrib"] edition = "2021" +[profile.release] +codegen-units = 1 +lto = true +strip = true + [features] default = ["rcon", "lobby"] @@ -32,18 +31,28 @@ lobby = ["md-5", "uuid"] [dependencies] anyhow = "1.0" -base64 = "0.13" +base64 = "0.21" bytes = "1.1" chrono = "0.4" -clap = { version = "4.0.32", default-features = false, features = [ "std", "help", "suggestions", "color", "usage", "cargo", "env", "unicode" ]} +clap = { version = "4.0.32", default-features = false, features = [ + "std", + "help", + "suggestions", + "color", + "usage", + "cargo", + "env", + "unicode", +] } colored = "2.0" -derive_builder = "0.10" +derive_builder = "0.12" dotenv = "0.15" flate2 = { version = "1.0", default-features = false, features = ["default"] } futures = { version = "0.3", default-features = false, features = ["executor"] } log = "0.4" minecraft-protocol = { git = "https://github.com/timvisee/rust-minecraft-protocol", rev = "edfdf87" } named-binary-tag = "0.6" +nix = "0.26" notify = "4.0" pretty_env_logger = "0.4" proxy-protocol = "0.5" @@ -53,7 +62,17 @@ serde = "1.0" serde_json = "1.0" shlex = "1.1" thiserror = "1.0" -tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "io-util", "net", "macros", "time", "process", "signal", "sync", "fs"] } +tokio = { version = "1", default-features = false, features = [ + "rt-multi-thread", + "io-util", + "net", + "macros", + "time", + "process", + "signal", + "sync", + "fs", +] } toml = "0.5" version-compare = "0.1" @@ -69,4 +88,10 @@ uuid = { version = "0.7", optional = true, features = ["v3"] } libc = "0.2" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["winuser", "processthreadsapi", "handleapi", "ntdef", "minwindef"] } +winapi = { version = "0.3", features = [ + "winuser", + "processthreadsapi", + "handleapi", + "ntdef", + "minwindef", +] } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..ec12475 --- /dev/null +++ b/build.rs @@ -0,0 +1,7 @@ +fn main() { + // rcon is required on Windows + #[cfg(all(windows, not(feature = "rcon")))] + { + compile_error!("required feature missing on Windows: rcon"); + } +} diff --git a/docs/protocol-version.md b/docs/protocol-version.md index 524b88e..070c19b 100644 --- a/docs/protocol-version.md +++ b/docs/protocol-version.md @@ -21,8 +21,8 @@ In lazymc you may configure what protocol version to use: # Server version & protocol hint. # Sent to clients until actual server version is known. # See: https://git.io/J1Fvx -version = "1.18.1" -protocol = 757 +version = "1.19.3" +protocol = 761 # -- snip -- ``` diff --git a/res/lazymc.toml b/res/lazymc.toml index 38fe8e2..aa670f4 100644 --- a/res/lazymc.toml +++ b/res/lazymc.toml @@ -18,8 +18,8 @@ # Server version & protocol hint. # Sent to clients until actual server version is known. # See: https://git.io/J1Fvx -#version = "1.18.1" -#protocol = 757 +#version = "1.19.3" +#protocol = 761 [server] # Server address. Internal IP and port of server started by lazymc to proxy to. @@ -33,6 +33,10 @@ directory = "." # Warning: if using a bash script read: https://git.io/JMIKH command = "java -Xmx1G -Xms1G -jar server.jar --nogui" +# Freeze the server process instead of restarting it when no players online, making it resume faster. +# Only works on Unix (Linux or MacOS), ignored on Windows +#freeze_process = true + # Immediately wake server when starting lazymc. #wake_on_start = false diff --git a/src/config.rs b/src/config.rs index eff00f7..3ab1949 100644 --- a/src/config.rs +++ b/src/config.rs @@ -174,6 +174,11 @@ pub struct Server { )] pub address: SocketAddr, + /// Freeze the server process instead of restarting it when no players online, making it start up faster. + /// Only works on Unix (Linux or MacOS) + #[serde(default = "bool_true")] + pub freeze_process: bool, + /// Immediately wake server when starting lazymc. #[serde(default)] pub wake_on_start: bool, @@ -478,19 +483,13 @@ impl Default for Advanced { } /// Config configuration. -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] #[serde(default)] pub struct ConfigConfig { /// Configuration for lazymc version. pub version: Option, } -impl Default for ConfigConfig { - fn default() -> Self { - Self { version: None } - } -} - fn option_pathbuf_dot() -> Option { Some(".".into()) } diff --git a/src/lobby.rs b/src/lobby.rs index e79ef2f..fc8fab4 100644 --- a/src/lobby.rs +++ b/src/lobby.rs @@ -42,7 +42,7 @@ const SERVER_JOIN_GAME_TIMEOUT: Duration = Duration::from_secs(20); /// /// Notchian servers are slow, we must wait a little before sending play packets, because the /// server needs time to transition the client into this state. -/// See warning at: https://wiki.vg/Protocol#Login_Success +/// See warning at: const SERVER_WARMUP: Duration = Duration::from_secs(1); /// Serve lobby service for given client connection. diff --git a/src/mc/favicon.rs b/src/mc/favicon.rs index 2a54e8f..7580c87 100644 --- a/src/mc/favicon.rs +++ b/src/mc/favicon.rs @@ -1,3 +1,5 @@ +use base64::Engine; + use crate::proto::client::ClientInfo; /// Protocol version since when favicons are supported. @@ -12,7 +14,11 @@ pub fn default_favicon() -> String { /// /// This assumes the favicon data to be a valid PNG image. pub fn encode_favicon(data: &[u8]) -> String { - format!("{}{}", "data:image/png;base64,", base64::encode(data)) + format!( + "{}{}", + "data:image/png;base64,", + base64::engine::general_purpose::STANDARD.encode(data) + ) } /// Check whether the status response favicon is supported based on the given client info. diff --git a/src/mc/server_properties.rs b/src/mc/server_properties.rs index 2fcd8f7..85e1098 100644 --- a/src/mc/server_properties.rs +++ b/src/mc/server_properties.rs @@ -114,7 +114,7 @@ fn rewrite_contents(contents: String, mut changes: HashMap<&str, String>) -> Opt } // Try to split property - let (key, value) = match line.split_once("=") { + let (key, value) = match line.split_once('=') { Some(result) => result, None => return line, }; diff --git a/src/mc/uuid.rs b/src/mc/uuid.rs index 0aee292..c54540a 100644 --- a/src/mc/uuid.rs +++ b/src/mc/uuid.rs @@ -18,7 +18,7 @@ pub fn offline_player_uuid(username: &str) -> Uuid { /// /// Static factory to retrieve a type 3 (name based) `Uuid` based on the specified byte array. /// -/// Ported from: https://git.io/J1b6A +/// Ported from: fn java_name_uuid_from_bytes(data: &[u8]) -> Uuid { let mut hasher = Md5::new(); hasher.update(data); diff --git a/src/os/mod.rs b/src/os/mod.rs index 614a646..348f56f 100644 --- a/src/os/mod.rs +++ b/src/os/mod.rs @@ -1,17 +1,15 @@ -#[cfg(unix)] -pub mod unix; #[cfg(windows)] pub mod windows; +use nix::{sys::signal, unistd::Pid}; + /// Force kill process. /// /// Results in undefined behavior if PID is invalid. #[allow(unreachable_code)] pub fn force_kill(pid: u32) -> bool { #[cfg(unix)] - unsafe { - return unix::force_kill(pid); - } + return unix_signal(pid, signal::SIGKILL); #[cfg(windows)] unsafe { @@ -22,20 +20,57 @@ pub fn force_kill(pid: u32) -> bool { } /// Gracefully kill process. -/// /// Results in undefined behavior if PID is invalid. /// /// # Panics -/// /// Panics on platforms other than Unix. #[allow(unreachable_code, dead_code, unused_variables)] pub fn kill_gracefully(pid: u32) -> bool { #[cfg(unix)] - unsafe { - return unix::kill_gracefully(pid); - } + return unix_signal(pid, signal::SIGTERM); unimplemented!( "gracefully killing Minecraft server process not implemented on non-Unix platforms" ); } + +/// Freeze process. +/// Results in undefined behavior if PID is invaild. +/// +/// # Panics +/// Panics on platforms other than Unix. +#[allow(unreachable_code)] +pub fn freeze(pid: u32) -> bool { + #[cfg(unix)] + return unix_signal(pid, signal::SIGSTOP); + + unimplemented!( + "freezing the Minecraft server process is not implemented on non-Unix platforms" + ); +} + +/// Unfreeze process. +/// Results in undefined behavior if PID is invaild. +/// +/// # Panics +/// Panics on platforms other than Unix. +#[allow(unreachable_code)] +pub fn unfreeze(pid: u32) -> bool { + #[cfg(unix)] + return unix_signal(pid, signal::SIGCONT); + + unimplemented!( + "unfreezing the Minecraft server process is not implemented on non-Unix platforms" + ); +} + +#[cfg(unix)] +pub fn unix_signal(pid: u32, signal: signal::Signal) -> bool { + return match signal::kill(Pid::from_raw(pid as i32), signal) { + Ok(()) => true, + Err(err) => { + warn!(target: "lazymc", "Sending {signal} signal to server failed: {err}"); + false + } + }; +} diff --git a/src/os/unix.rs b/src/os/unix.rs deleted file mode 100644 index 753b3ff..0000000 --- a/src/os/unix.rs +++ /dev/null @@ -1,27 +0,0 @@ -/// Force kill process on Unix by sending SIGKILL. -/// -/// This is unsafe because the PID isn't checked. -pub unsafe fn force_kill(pid: u32) -> bool { - debug!(target: "lazymc", "Sending SIGKILL signal to {} to kill server", pid); - let result = libc::kill(pid as i32, libc::SIGKILL); - - if result != 0 { - trace!(target: "lazymc", "SIGKILL failed: {}", result); - } - - result == 0 -} - -/// Gracefully kill process on Unix by sending SIGTERM. -/// -/// This is unsafe because the PID isn't checked. -pub unsafe fn kill_gracefully(pid: u32) -> bool { - debug!(target: "lazymc", "Sending SIGTERM signal to {} to kill server", pid); - let result = libc::kill(pid as i32, libc::SIGTERM); - - if result != 0 { - warn!(target: "lazymc", "Sending SIGTERM signal to server failed: {}", result); - } - - result == 0 -} diff --git a/src/probe.rs b/src/probe.rs index d200d64..8ba6462 100644 --- a/src/probe.rs +++ b/src/probe.rs @@ -157,11 +157,7 @@ async fn connect_to_server_no_timeout( // Select server address to use, add magic if Forge let server_addr = if config.server.forge { - format!( - "{}{}", - config.server.address.ip().to_string(), - forge::STATUS_MAGIC, - ) + format!("{}{}", config.server.address.ip(), forge::STATUS_MAGIC) } else { config.server.address.ip().to_string() }; diff --git a/src/proto/mod.rs b/src/proto/mod.rs index e917060..9e00ea1 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -9,7 +9,7 @@ pub mod packets; /// in the configuration. /// /// Should be kept up-to-date with latest supported Minecraft version by lazymc. -pub const PROTO_DEFAULT_VERSION: &str = "1.18.1"; +pub const PROTO_DEFAULT_VERSION: &str = "1.19.3"; /// Default minecraft protocol version. /// @@ -17,7 +17,7 @@ pub const PROTO_DEFAULT_VERSION: &str = "1.18.1"; /// in the configuration. /// /// Should be kept up-to-date with latest supported Minecraft version by lazymc. -pub const PROTO_DEFAULT_PROTOCOL: u32 = 757; +pub const PROTO_DEFAULT_PROTOCOL: u32 = 761; /// Compression threshold to use. // TODO: read this from server.properties instead diff --git a/src/server.rs b/src/server.rs index 7d852c1..8bc259d 100644 --- a/src/server.rs +++ b/src/server.rs @@ -217,9 +217,14 @@ impl Server { None => info!(target: "lazymc", "Starting server..."), } + // Unfreeze server if it is frozen + #[cfg(unix)] + if config.server.freeze_process && unfreeze_server_signal(&config, &server).await { + return true; + } + // Spawn server in new task Self::spawn_server_task(config, server); - true } @@ -235,6 +240,12 @@ impl Server { /// This will attempt to stop the server with all available methods. #[allow(unused_variables)] pub async fn stop(&self, config: &Config) -> bool { + // Try to freeze through signal + #[cfg(unix)] + if config.server.freeze_process && freeze_server_signal(config, self).await { + return true; + } + // Try to stop through RCON if started #[cfg(feature = "rcon")] if self.state() == State::Started && stop_server_rcon(config, self).await { @@ -586,13 +597,11 @@ async fn stop_server_signal(config: &Config, server: &Server) -> bool { } }; - // Send kill signal if !crate::os::kill_gracefully(pid) { error!(target: "lazymc", "Failed to send stop signal to server process"); return false; } - // Update from starting/started to stopping server .update_state_from(Some(State::Starting), State::Stopping, config) .await; @@ -602,3 +611,59 @@ async fn stop_server_signal(config: &Config, server: &Server) -> bool { true } + +/// Freeze server by sending SIGSTOP signal. +/// +/// Only available on Unix. +#[cfg(unix)] +async fn freeze_server_signal(config: &Config, server: &Server) -> bool { + // Grab PID + let pid = match *server.pid.lock().await { + Some(pid) => pid, + None => { + debug!(target: "lazymc", "Could not send freeze signal to server process, PID unknown"); + return false; + } + }; + + if !os::freeze(pid) { + error!(target: "lazymc", "Failed to send freeze signal to server process."); + } + + server + .update_state_from(Some(State::Starting), State::Stopped, config) + .await; + server + .update_state_from(Some(State::Started), State::Stopped, config) + .await; + + true +} + +/// Unfreeze server by sending SIGCONT signal. +/// +/// Only available on Unix. +#[cfg(unix)] +async fn unfreeze_server_signal(config: &Config, server: &Server) -> bool { + // Grab PID + let pid = match *server.pid.lock().await { + Some(pid) => pid, + None => { + debug!(target: "lazymc", "Could not send unfreeze signal to server process, PID unknown"); + return false; + } + }; + + if !os::unfreeze(pid) { + error!(target: "lazymc", "Failed to send unfreeze signal to server process."); + } + + server + .update_state_from(Some(State::Stopping), State::Starting, config) + .await; + server + .update_state_from(Some(State::Stopped), State::Starting, config) + .await; + + true +} diff --git a/src/service/file_watcher.rs b/src/service/file_watcher.rs index 284061a..fa0ecb9 100644 --- a/src/service/file_watcher.rs +++ b/src/service/file_watcher.rs @@ -151,10 +151,9 @@ fn reload_whitelist(config: &Config, server: &Server, dir: &Path) { } // Must be enabled in server.properties - let enabled = - server_properties::read_property(&dir.join(server_properties::FILE), "white-list") - .map(|v| v.trim() == "true") - .unwrap_or(false); + let enabled = server_properties::read_property(dir.join(server_properties::FILE), "white-list") + .map(|v| v.trim() == "true") + .unwrap_or(false); if !enabled { server.set_whitelist_blocking(None); debug!(target: "lazymc", "Not using whitelist, not enabled in {}", server_properties::FILE);