diff --git a/src/socketengine.rs b/src/socketengine.rs index 6ba356c..d8adc5b 100644 --- a/src/socketengine.rs +++ b/src/socketengine.rs @@ -1295,10 +1295,12 @@ fn tls_conn( } else { addr }; - // Bound the blocking TLS handshake: a peer that stalls it would otherwise pin this - // thread + socket forever (no uid yet, so nothing else reaps it). Reset to TLS_POLL - // once the handshake completes (below), so it doesn't clip a live client's idle reads. + // Bound the blocking TLS handshake both ways: a peer that stalls it — silent, or a + // zero TCP receive window against our certificate write — would otherwise pin this + // thread + socket forever (no uid yet, so nothing else reaps it). The read deadline + // resets to TLS_POLL and the write deadline drops once the handshake completes. let _ = stream.set_read_timeout(handshake_timeout); + let _ = stream.set_write_timeout(handshake_timeout); let mut conn = match backend.accept(stream) { Ok(c) => c, Err(_) => { @@ -1306,6 +1308,9 @@ fn tls_conn( return; // handshake failed } }; + // handshake done — clear the write deadline (same socket via `shutdown`) so it can't + // clip a live client later. + let _ = shutdown.set_write_timeout(None); let certfp = conn.peer_cert_fp(); let tls_info = conn.tls_info(); let sni = conn.sni(); diff --git a/src/websocket.rs b/src/websocket.rs index cdfaf87..a4cd9bb 100644 --- a/src/websocket.rs +++ b/src/websocket.rs @@ -9,7 +9,7 @@ //! bind_ws = 127.0.0.1:8097 plaintext ws:// listener //! bind_wss = 0.0.0.0:7799 wss:// listener (uses tls_cert/tls_key) //! ws_origin = https://x.example (repeatable) allowed Origin globs; empty = any -//! ws_handshake_timeout = 10 seconds to finish the Upgrade +//! ws_handshake_timeout = 10 seconds to finish the TLS + Upgrade handshake //! ws_ping_interval = 60 seconds between server keepalive pings (0 = off) //! ws_timeout = 120 seconds with no traffic before we drop it //! ws_defaultmode = text frame mode with no subprotocol: text|binary|reject @@ -224,12 +224,23 @@ fn ws_conn( return; }; match tls { - Some(backend) => match backend.accept(raw) { - Ok(conn) => ws_session(conn, uid, addr, true, core, shutdown, cfg), - Err(_) => { - let _ = shutdown.shutdown(Shutdown::Both); + Some(backend) => { + // Bound the blocking wss TLS handshake both ways — otherwise a peer that + // stalls it pins this thread + socket forever (no uid yet). Clear the write + // deadline (same socket via `shutdown`) once the handshake completes; the + // HTTP-upgrade read deadline is set in ws_session. + let _ = raw.set_read_timeout(Some(cfg.handshake_timeout)); + let _ = raw.set_write_timeout(Some(cfg.handshake_timeout)); + match backend.accept(raw) { + Ok(conn) => { + let _ = shutdown.set_write_timeout(None); + ws_session(conn, uid, addr, true, core, shutdown, cfg); + } + Err(_) => { + let _ = shutdown.shutdown(Shutdown::Both); + } } - }, + } None => ws_session(raw, uid, addr, false, core, shutdown, cfg), } }