From 223ab844a019a422c3db084a68ea6fb4991aad30 Mon Sep 17 00:00:00 2001 From: AI-scor <354880559+AI-scor@users.noreply.github.com> Date: Tue, 10 Nov 2026 18:51:54 +0100 Subject: [PATCH] [Server] Clarify pingClockTimeout rate limits and idle timeout (#7881) --- .../server/remote/server_protocolhandler.cpp | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp index fccec85ef..7e976bd59 100644 --- a/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp +++ b/libcockatrice_network/libcockatrice/network/server/remote/server_protocolhandler.cpp @@ -530,34 +530,33 @@ void Server_ProtocolHandler::processCommandContainer(const CommandContainer &con } } +namespace +{ +/// Advances a rate-limit window by one keep-alive tick: add a fresh bucket at the front and +/// drop the oldest bucket once the window holds more than `bucketCount` of them. +void advanceCountingWindow(QList &counts, int bucketCount) +{ + counts.prepend(0); + if (counts.size() > bucketCount) { + counts.removeLast(); + } +} +} // namespace + void Server_ProtocolHandler::pingClockTimeout() { - - int cmdcountinterval = server->getCommandCountingInterval(); - int msgcountinterval = server->getMessageCountingInterval(); - int pingclockinterval = server->getClientKeepAlive(); - - int interval = server->getMessageCountingInterval(); - if (interval > 0) { - if (pingclockinterval > 0) { - messageSizeOverTime.prepend(0); - if (messageSizeOverTime.size() > (msgcountinterval / pingclockinterval)) { - messageSizeOverTime.removeLast(); - } - messageCountOverTime.prepend(0); - if (messageCountOverTime.size() > (msgcountinterval / pingclockinterval)) { - messageCountOverTime.removeLast(); - } + const int keepAliveInterval = server->getClientKeepAlive(); + if (keepAliveInterval > 0) { + const int messageCountingInterval = server->getMessageCountingInterval(); + if (messageCountingInterval > 0) { + const int messageBucketCount = messageCountingInterval / keepAliveInterval; + advanceCountingWindow(messageSizeOverTime, messageBucketCount); + advanceCountingWindow(messageCountOverTime, messageBucketCount); } - } - interval = server->getCommandCountingInterval(); - if (interval > 0) { - if (pingclockinterval > 0) { - commandCountOverTime.prepend(0); - if (commandCountOverTime.size() > (cmdcountinterval / pingclockinterval)) { - commandCountOverTime.removeLast(); - } + const int commandCountingInterval = server->getCommandCountingInterval(); + if (commandCountingInterval > 0) { + advanceCountingWindow(commandCountOverTime, commandCountingInterval / keepAliveInterval); } } @@ -565,20 +564,23 @@ void Server_ProtocolHandler::pingClockTimeout() prepareDestroy(); } - // PrivLevel users, Moderators, Admins, and Developers are not subject to the server idle timeout policy + // PrivLevel users, Moderators, Admins, and Developers are not subject to the server idle timeout policy. const bool hasPrivLevel = userInfo && QString::fromStdString(userInfo->privlevel()).toLower() != "none"; const bool isStaff = userInfo && (userInfo->user_level() & (ServerInfo_User::IsModerator | ServerInfo_User::IsAdmin | ServerInfo_User::IsDeveloper)); - if (!hasPrivLevel && !isStaff) { - if ((server->getIdleClientTimeout() > 0) && (idleClientWarningSent)) { - if (timeRunning - lastActionReceived > server->getIdleClientTimeout()) { - prepareDestroy(); - } + const bool isExemptFromIdleTimeout = hasPrivLevel || isStaff; + if (!isExemptFromIdleTimeout) { + const int idleTimeout = server->getIdleClientTimeout(); + const int idleDuration = timeRunning - lastActionReceived; + + if (idleTimeout > 0 && idleClientWarningSent && idleDuration > idleTimeout) { + prepareDestroy(); } - if (((timeRunning - lastActionReceived) >= qCeil(server->getIdleClientTimeout() * .9)) && - (!idleClientWarningSent) && (server->getIdleClientTimeout() > 0)) { + const bool shouldWarnBeforeIdleTimeout = + idleTimeout > 0 && !idleClientWarningSent && idleDuration >= qCeil(idleTimeout * .9); + if (shouldWarnBeforeIdleTimeout) { Event_NotifyUser event; event.set_type(Event_NotifyUser::IDLEWARNING); SessionEvent *se = prepareSessionEvent(event);