io: bound the blocking TLS handshake write side + the wss TLS handshake
The thread-per-connection TLS path bounded only the handshake read, so a peer advertising a zero TCP receive window could stall our certificate write and pin the thread forever; add a write deadline (cleared once the handshake completes). The wss listener ran backend.accept() with no deadline at all — bound its TLS handshake both ways too. Both reset via the same-socket shutdown handle.
This commit is contained in:
parent
2d42fbd2ca
commit
369e06ec2b
2 changed files with 25 additions and 9 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue