fix(nvhttp): non-blocking TLS shutdown in SunshineHTTPS destructor - #5617
fix(nvhttp): non-blocking TLS shutdown in SunshineHTTPS destructor#5617awerty-noob wants to merge 1 commit into
Conversation
|
Thank you for the PR submission, but it looks like you used AI to create this PR. Please read and follow our Contributing guidelines and specifically our AI Usage policy. Additionally, please update the PR to use the correct template. You can find it at https://github.com/LizardByte/.github/blob/master/.github/pull_request_template.md?plain=1 |
The ~SunshineHTTPS() destructor performs a synchronous ssl::stream::shutdown() on the single io thread of the HTTPS server (port 47984). After the local close_notify has been written, SSL_shutdown() waits for the peer's close_notify using a blocking read_some() -> poll(fd, POLLIN, -1) on the underlying socket. Clients that keep the connection open after receiving a response -- e.g. the Moonlight HTTP connection pool (Android app, Moonlight-Switch, Moonlight-N3DS) -- never send a close_notify, so the io thread blocks forever and the entire HTTPS server stops accepting connections. Symptom: host reachable, but app list authentication fails with an HTTP request timeout, while the listen backlog on port 47984 keeps growing and 47989/RTSP keep working. Set the socket non-blocking before shutdown (via the error_code overload, as the destructor is noexcept) so the attempt returns immediately with would_block instead of hanging; the close_notify is still written best-effort and the socket is closed right after.
db9d77c to
b970a63
Compare
|
Thanks for the review! I've now followed the contributing guidelines and updated the PR:
Summary of change (12 insertions in |
|



Description
The HTTPS server (port 47984) can permanently stop accepting connections after certain Moonlight clients connect.
When a
SunshineHTTPSconnection object is destroyed (right after a response is written withclose_connection_after_response), its destructor performs a synchronous TLS shutdown. After the server writes its own close_notify,SSL_shutdown()waits for the peer's close_notify via a blockingread_some()→poll(fd, POLLIN, -1)on the blocking socket. Clients that keep the connection open after receiving a response — the Moonlight HTTP connection pool (Android app, Moonlight-Switch, Moonlight-N3DS, …) — never send a close_notify, so the single io thread of the HTTPS server blocks forever. Every later connection times out (Moonlight: host reachable, app list authentication unavailable, HTTP timeout), the 47984 listen backlog grows, while 47989/RTSP/streaming keep working and the process appears healthy.I confirmed this by resolving the hung thread's stack from a core dump plus debug symbols:
I also reproduced it locally with a minimal client that sends
GET /serverinfoand then keeps the connection open: the server stops responding within seconds and stays wedged until restart.The fix marks the underlying socket non-blocking before
shutdown()so the attempt returns immediately withwould_blockinstead of blocking indefinitely; the close_notify is still written best-effort and the socket closes right after. Theerror_codeoverload is used because the destructor isnoexceptand the throwing overload could terminate the process (also flagged by the SonarQube quality gate, which should now pass).Screenshot
N/A (no UI changes)
Issues Fixed or Closed
Roadmap Issues
N/A
Type of Change
Checklist
Testing done manually: with the stock binary the reproduction above wedges the server; with this fix the server stays responsive in the same scenario (repeated /serverinfo probes return 200 OK), and normal requests, pairing and streaming are unaffected.
AI Usage
Please see the AI usage policy.
The debugging (core dump analysis, reproduction, fix) was performed with AI assistance; I reviewed and verified every step locally before submitting.