diff --git a/src/server.rs b/src/server.rs index b644062..47c70de 100644 --- a/src/server.rs +++ b/src/server.rs @@ -479,8 +479,14 @@ impl Server { let tx = self.event_tx.clone(); std::thread::spawn(move || { let _guard = Guard; // decrements even on panic - let ev = f(); - let _ = tx.send(ev); + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { + Ok(ev) => { + let _ = tx.send(ev); + } + // a panic here can't reach the core (we don't know which Event to send); + // log it so a stuck request is diagnosable instead of silent. + Err(_) => eprintln!("[worker] a background crypto/http task panicked; its request was dropped"), + } }); true } diff --git a/src/socketengine.rs b/src/socketengine.rs index 20b80c8..d1b455f 100644 --- a/src/socketengine.rs +++ b/src/socketengine.rs @@ -351,11 +351,25 @@ pub fn run_reactor( } } Token(t) => { + // isolate per-connection I/O: a panic framing one client's bytes + // drops that client, never the reactor that serves all the others. if event.is_readable() { - read_conn(&mut poll, &mut conns, t, &core); + let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + read_conn(&mut poll, &mut conns, t, &core) + })); + if r.is_err() { + eprintln!("[reactor] recovered from a panic reading a socket; dropping that connection"); + close_conn(&mut poll, &mut conns, t, &core); + } } if event.is_writable() && conns.contains_key(&t) { - flush_conn(&mut poll, &mut conns, t, &core); + let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + flush_conn(&mut poll, &mut conns, t, &core) + })); + if r.is_err() { + eprintln!("[reactor] recovered from a panic writing a socket; dropping that connection"); + close_conn(&mut poll, &mut conns, t, &core); + } } } }