<div dir="ltr"><div>Michael,</div><div><br></div><div>Yes, I'm on it. Will send new patch in a day or two.</div><div><br></div><div>Roger</div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Mon, Sep 7, 2026 at 10:39 PM Michael Van Canneyt via fpc-pascal <<a href="mailto:fpc-pascal@lists.freepascal.org">fpc-pascal@lists.freepascal.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
Roger,<br>
<br>
Do you think you can fix the issues raised by Sven ?<br>
The windows stuff, same-thread join, InterruptConnections issue.<br>
<br>
Sven, if you can file an issue for the TWebSocketServer.CertificateData<br>
issue (patch would be nice, but not required) so that can be scratched off<br>
the list...<br>
<br>
Michael.<br>
<br>
On Mon, 7 Sep 2026, Sven Harazim via fpc-pascal wrote:<br>
<br>
> Hi Roger, hi Michael,<br>
><br>
> I built two complete trees from trunk 695611fdb3 differing only by this<br>
> patch and ran them against each other on aarch64-linux (Ubuntu 24.04,<br>
> OpenSSL 3.0.13) and aarch64-win64. The patch applies cleanly to that<br>
> revision; a full `make all install` with it succeeds on linux. Everything<br>
> below is from runs on those two machines, not from reading the code.<br>
><br>
> To answer Michael's question first: the upgrade path is unaffected. The<br>
> test drives FPC's own TWebSocketServer against the client, so the real HTTP<br>
> handshake runs. It passes with and without the patch, over plain TCP and<br>
> over TLS. I did not find any server-side caller of the new<br>
> `TWSTransport.InterruptRead` either — the only call site is<br>
> `TWSThreadMessagePump`.<br>
><br>
> What the patch fixes, measured. Without it, a peer-closed client stays<br>
> `Active=True` and never fires `OnDisconnect`, over both transports and on<br>
> both platforms — the stale connection from the original report. With it,<br>
> both are correct. And where a reader is genuinely stuck mid-frame, on linux<br>
> `Terminate` now returns in ~300 ms and the teardown is clean, against ~2 s<br>
> plus a hanging client destroy without it.<br>
><br>
> Where it does not work: Windows. The wake is a raw<br>
> `fpShutdown(SHUT_RDWR)`, and on win64 that does not release a `recv` that is<br>
> already blocked. Isolated raw-socket test, three rounds, no websocket code<br>
> involved:<br>
><br>
>    linux : released after 0-2 ms, recv returns 0<br>
>    win64 : NOT released within 3000 ms, 3 of 3 rounds<br>
>            (fpShutdown itself returns 0)<br>
><br>
> Because `Terminate` then joins unconditionally, it blocks for as long as the<br>
> read does. The old code gave up after ~2 s — though the old destructor could<br>
> already block on the list lock the reader holds, so this is not a clean<br>
> regression, it moves where the hang happens.<br>
><br>
> Same test, immediately afterwards on the same socket:<br>
><br>
>    win64 : closesocket DID release it after 0 ms (recv=-1, WSAENOTSOCK)<br>
><br>
> So a wake that works on Windows exists, but it is the one the patch<br>
> deliberately avoids — closing the descriptor is exactly what races with TLS<br>
> teardown. That looks like a real trade-off rather than an oversight, so I am<br>
> not proposing a fix; you two know the constraints. I am happy to measure any<br>
> candidate on this machine, including `SO_RCVTIMEO` on the client socket,<br>
> which the OpenSSL handler already anticipates but which interacts with the<br>
> 100-retry loop in `ReadData`.<br>
><br>
> Two more things I ran into, both reproducible on linux with the patch:<br>
><br>
> `InterruptConnections` shuts down every registered transport, not just the<br>
> stuck one. With a healthy echo client and a stalled client on the same pump,<br>
> right after `Terminate` the healthy client still reports `Active=True` with<br>
> zero `OnDisconnect` calls, but sending on it raises<br>
> `EWebSocket: Write operation returned error: (104) Connection reset by peer`.<br>
> The owner is never told its connection is gone.<br>
><br>
> Calling `Terminate` from the `OnDisconnect` handler makes the reader thread<br>
> join itself, because `ReadConnections` invokes the callback on that thread.<br>
> On win64 `Terminate` is entered and never returns; on linux/glibc it raises<br>
> `EThreadDestroyCalled`. Reacting to a disconnect by stopping the pump seems<br>
> a fairly ordinary thing for an application to do, and the patch is what<br>
> makes this path reachable — before it, the pump discarded the `irClose`<br>
> result and never delivered the notification.<br>
><br>
> Unrelated, noticed while writing the TLS tests:<br>
> `TWebSocketServer.CertificateData` is declared but never instantiated, so<br>
> `CreateSSLSocketHandler` dereferences nil as soon as a TLS handler is<br>
> requested. I worked around it in the test with `OnGetSocketHandler`. Happy<br>
> to file that separately if it is not already known.<br>
><br>
> One last note: there are currently no websocket tests in FPC at all —<br>
> `packages/fcl-web/tests/` covers HTTP, HTTP/2, JWT, cookies and routes only.<br>
> So there is no upgrader test to extend, Roger.<br>
><br>
> The two programs I used are attached (18 KB, sources plus a README with the<br>
> build lines and the numbers above). They are standalone: point `-Fu` at the<br>
> websocket sources of whichever tree you want to test, so the same binary can<br>
> be built against a patched and an unpatched one. Each scenario runs in its<br>
> own process with a timeout, so a hang is reported instead of stalling the<br>
> run. If a harness in `fcl-web/tests` would be useful, I am happy to shape<br>
> them into that form — right now they are deliberately standalone so they can<br>
> be pointed at two trees at once.<br>
><br>
> Sven_______________________________________________<br>
fpc-pascal maillist  -  <a href="mailto:fpc-pascal@lists.freepascal.org" target="_blank">fpc-pascal@lists.freepascal.org</a><br>
<a href="https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal" rel="noreferrer" target="_blank">https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal</a><br>
</blockquote></div></div>