gracefully handle panics in connection_handler

This commit is contained in:
soruh 2023-03-18 15:17:25 +01:00
parent af130cf56e
commit 022f01e532
4 changed files with 74 additions and 17 deletions

42
Cargo.lock generated
View File

@ -101,6 +101,7 @@ dependencies = [
"anyhow",
"bytemuck",
"chrono",
"futures",
"hyper",
"serde",
"serde_json",
@ -194,6 +195,20 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.27"
@ -201,6 +216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
@ -209,6 +225,18 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
[[package]]
name = "futures-io"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
[[package]]
name = "futures-sink"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
[[package]]
name = "futures-task"
version = "0.3.27"
@ -221,10 +249,15 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
@ -512,6 +545,15 @@ dependencies = [
"serde",
]
[[package]]
name = "slab"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
dependencies = [
"autocfg",
]
[[package]]
name = "socket2"
version = "0.4.9"

View File

@ -13,6 +13,7 @@ serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
hyper = { version = "0.14.24", optional = true, features = ["server", "http1", "tcp"] }
chrono = { version = "0.4.23", optional = true }
futures = { version = "0.3.27", default-features = false, features = ["std"] }
[features]
default = ["debug_server", "chrono"]

View File

@ -91,13 +91,6 @@ impl Config {
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// make whole programm exit on worker thread crash
let default_panic = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
default_panic(info);
std::process::exit(1);
}));
let config = Arc::new(Config::load("config.json")?);
if config.allowed_ports.is_empty() {
@ -127,7 +120,9 @@ async fn main() -> anyhow::Result<()> {
if should_store {
last_store = Some(last_update);
port_handler.store(&cache_path).unwrap();
if let Err(err) = port_handler.store(&cache_path) {
println!("failed to store cache: {err:?}");
}
}
}
}
@ -152,17 +147,36 @@ async fn main() -> anyhow::Result<()> {
let mut handler_metadata = HandlerMetadata::default();
tokio::spawn(async move {
let res =
connection_handler(&config, &mut handler_metadata, &port_handler, &mut stream)
.await;
use futures::future::FutureExt;
if let Err(err) = res {
println!("client at {addr} had an error: {err:?}");
let res = std::panic::AssertUnwindSafe(connection_handler(
&config,
&mut handler_metadata,
&port_handler,
&mut stream,
))
.catch_unwind()
.await;
let error = match res {
Err(err) => {
let err = err
.downcast::<String>()
.unwrap_or_else(|_| Box::new("?".to_owned()));
Some(format!("panic at: {err}"))
}
Ok(Err(err)) => Some(err.to_string()),
Ok(Ok(())) => None,
};
if let Some(err) = error {
println!("client at {addr} had an error: {err}");
let mut packet = Packet::default();
packet.data.extend_from_slice(err.to_string().as_bytes());
packet.data.truncate(0xfe);
packet.data.extend_from_slice(err.as_bytes());
packet.data.truncate((u8::MAX - 1) as usize);
packet.data.push(0);
packet.header = Header {
kind: PacketKind::Error.raw(),

View File

@ -198,7 +198,7 @@ impl PortHandler {
}
pub fn store(&self, cache: &Path) -> anyhow::Result<()> {
println!("storing database");
println!("storing cache");
let temp_file = cache.with_extension(".temp");
serde_json::to_writer(BufWriter::new(File::create(&temp_file)?), self)?;
@ -208,7 +208,7 @@ impl PortHandler {
}
pub fn load(cache: &Path) -> std::io::Result<Self> {
println!("loading database");
println!("loading cache");
Ok(serde_json::from_reader(BufReader::new(File::open(cache)?))?)
}