fix(win): stop TLS sockets busy-spinning the socket poll loop

pollSocket() caches a socket's writability and skips waiting once it's
known writable, relying on writeSocket() to clear the cache on
WSAEWOULDBLOCK. SecureSocket writes via SSL_write(), bypassing
writeSocket() entirely, so the cache never clears and the multiplexer
spins at a zero timeout instead of blocking whenever TLS hits
backpressure.

Add IArchNetwork::resetPollWriteOnSocket() and call it from
checkResult()'s SSL_ERROR_WANT_WRITE case, mirroring writeSocket()'s
existing WSAEWOULDBLOCK handling.
This commit is contained in:
ElCruncharino 2026-07-19 00:58:50 -04:00 committed by Chris Rizzitello
parent 0d7414d89a
commit 59d41b906e
4 changed files with 21 additions and 2 deletions

View file

@ -211,6 +211,16 @@ public:
*/
virtual size_t writeSocket(ArchSocket s, const void *buf, size_t len) = 0;
//! Reset the writable poll hint for a socket
/*!
Tells pollSocket() to wait for a fresh writable notification instead of
assuming the socket is still writable. Needed by callers that write to a
socket without going through writeSocket(), e.g. OpenSSL's SSL_write().
*/
virtual void resetPollWriteOnSocket(ArchSocket)
{
}
//! Check error on socket
/*!
If the socket \c s is in an error state then throws an appropriate

View file

@ -1,5 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -557,6 +558,12 @@ size_t ArchNetworkWinsock::writeSocket(ArchSocket s, const void *buf, size_t len
return static_cast<size_t>(n);
}
void ArchNetworkWinsock::resetPollWriteOnSocket(ArchSocket s)
{
assert(s != nullptr);
s->m_pollWrite = true;
}
void ArchNetworkWinsock::throwErrorOnSocket(ArchSocket s)
{
assert(s != nullptr);

View file

@ -1,5 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2012 - 2016 Synergy App Ltd
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
@ -71,6 +72,7 @@ public:
void unblockPollSocket(ArchThread thread) override;
size_t readSocket(ArchSocket s, void *buf, size_t len) override;
size_t writeSocket(ArchSocket s, const void *buf, size_t len) override;
void resetPollWriteOnSocket(ArchSocket s) override;
void throwErrorOnSocket(ArchSocket) override;
bool setNoDelayOnSocket(ArchSocket, bool noDelay) override;
void setKeepAliveOnSocket(ArchSocket, bool keepAlive) override;

View file

@ -556,8 +556,8 @@ void SecureSocket::checkResult(int status, int &retry)
break;
case SSL_ERROR_WANT_WRITE:
// Need to make sure the socket is known to be writable so the impending
// poll action actually triggers on a write.
// SSL_write() bypasses writeSocket(), so reset the poll hint ourselves.
ARCH->resetPollWriteOnSocket(getSocket());
setWritable(true);
retry++;
LOG_VERBOSE("want to write, error=%d, attempt=%d", errorCode, retry);