A client that completes TCP but vanishes mid-TLS-handshake (e.g. a
phone losing its network/VPN while traveling) blocked
ssl.SSLSocket.accept() inside serve_forever forever: the gateway
stopped accepting any new device connections (the app could not
reconnect), and on the next restart httpd.shutdown() froze the whole
event loop until the shutdown watchdog killed the process (ARIA
journal 2026-09-11 / 2026-09-23).
- Move the TLS handshake out of the accept loop: it now runs in the
per-connection thread under a hard timeout (HANDSHAKE_TIMEOUT_S,
10 s); a failed/timed-out handshake just closes the socket.
- stop() no longer blocks the event loop: shutdown()/server_close()/
join run in an executor under asyncio.wait_for(10 s); if the bound
expires the daemon threads are abandoned.
- Regression test: a silent half-open TCP connection must not stop
fresh TLS connections from being served, and stop() must stay
bounded.