fix WebSocket deadlock on slow client + mobile TX controls visibility

Deadlock: BroadcastBinary held FClientLock during blocking SockSend;
slow/stalled client caused Stop() to wait forever. Fix: set SO_SNDTIMEO=1s
on each accepted socket so SockSend returns error instead of hanging,
mark client wsClosed on send failure so subsequent ticks skip it.

Mobile: move TONE/TX-slider/MOX to front of toolbar via CSS order so
they are immediately visible without horizontal scroll on phones.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 16:39:43 +03:00
co-authored by Claude Sonnet 4.6
parent 9662d3d090
commit 3d25f837af
4 changed files with 65 additions and 2 deletions
+20
View File
@@ -54,6 +54,11 @@ function SockRecv(S: TSocket; Buf: Pointer; Len, Flags: Integer): Integer; inli
function SockSend(S: TSocket; Buf: Pointer; Len, Flags: Integer): Integer; inline;
procedure SockSetNonBlock(S: TSocket; NB: Boolean);
{ SockSetSndTimeout — ограничивает время блокирующего SockSend.
Без таймаута SockSend может зависнуть на минуты (TCP retransmit timeout)
если буфер клиента переполнен, держа при этом FClientLock и блокируя Stop(). }
procedure SockSetSndTimeout(S: TSocket; Ms: Integer);
{ ── SHA-1 ─────────────────────────────────────────────────────────────────── }
type
@@ -111,6 +116,13 @@ begin
ioctlsocket(S, FIONBIO, @Mode);
end;
procedure SockSetSndTimeout(S: TSocket; Ms: Integer);
var T: DWORD;
begin
T := Ms;
setsockopt(S, SOL_SOCKET, SO_SNDTIMEO, @T, SizeOf(T));
end;
{$ELSE}
function SockClose(S: TSocket): Integer;
@@ -145,6 +157,14 @@ begin
fpFcntl(S, F_SETFL, Flags);
end;
procedure SockSetSndTimeout(S: TSocket; Ms: Integer);
var TV: TTimeVal;
begin
TV.tv_sec := Ms div 1000;
TV.tv_usec := (Ms mod 1000) * 1000;
fpSetSockOpt(S, SOL_SOCKET, SO_SNDTIMEO, @TV, SizeOf(TV));
end;
{$ENDIF}
{ ═══════════════════════════════════════════════════════════════════════════