[Server] Clarify pingClockTimeout rate limits and idle timeout (#7881)

This commit is contained in:
AI-scor 2026-11-10 18:51:54 +01:00 • committed by GitHub
parent 12884c94dc
commit 223ab844a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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<int> &counts, int bucketCount)
{
counts.prepend(0);
if (counts.size() > bucketCount) {
counts.removeLast();
}
}
} // namespace
void Server_ProtocolHandler::pingClockTimeout() void Server_ProtocolHandler::pingClockTimeout()
{ {
const int keepAliveInterval = server->getClientKeepAlive();
int cmdcountinterval = server->getCommandCountingInterval(); if (keepAliveInterval > 0) {
int msgcountinterval = server->getMessageCountingInterval(); const int messageCountingInterval = server->getMessageCountingInterval();
int pingclockinterval = server->getClientKeepAlive(); if (messageCountingInterval > 0) {
const int messageBucketCount = messageCountingInterval / keepAliveInterval;
int interval = server->getMessageCountingInterval(); advanceCountingWindow(messageSizeOverTime, messageBucketCount);
if (interval > 0) { advanceCountingWindow(messageCountOverTime, messageBucketCount);
if (pingclockinterval > 0) {
messageSizeOverTime.prepend(0);
if (messageSizeOverTime.size() > (msgcountinterval / pingclockinterval)) {
messageSizeOverTime.removeLast();
}
messageCountOverTime.prepend(0);
if (messageCountOverTime.size() > (msgcountinterval / pingclockinterval)) {
messageCountOverTime.removeLast();
}
}
} }
interval = server->getCommandCountingInterval(); const int commandCountingInterval = server->getCommandCountingInterval();
if (interval > 0) { if (commandCountingInterval > 0) {
if (pingclockinterval > 0) { advanceCountingWindow(commandCountOverTime, commandCountingInterval / keepAliveInterval);
commandCountOverTime.prepend(0);
if (commandCountOverTime.size() > (cmdcountinterval / pingclockinterval)) {
commandCountOverTime.removeLast();
}
} }
} }
@ -565,20 +564,23 @@ void Server_ProtocolHandler::pingClockTimeout()
prepareDestroy(); 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 hasPrivLevel = userInfo && QString::fromStdString(userInfo->privlevel()).toLower() != "none";
const bool isStaff = const bool isStaff =
userInfo && (userInfo->user_level() & userInfo && (userInfo->user_level() &
(ServerInfo_User::IsModerator | ServerInfo_User::IsAdmin | ServerInfo_User::IsDeveloper)); (ServerInfo_User::IsModerator | ServerInfo_User::IsAdmin | ServerInfo_User::IsDeveloper));
if (!hasPrivLevel && !isStaff) { const bool isExemptFromIdleTimeout = hasPrivLevel || isStaff;
if ((server->getIdleClientTimeout() > 0) && (idleClientWarningSent)) { if (!isExemptFromIdleTimeout) {
if (timeRunning - lastActionReceived > server->getIdleClientTimeout()) { const int idleTimeout = server->getIdleClientTimeout();
const int idleDuration = timeRunning - lastActionReceived;
if (idleTimeout > 0 && idleClientWarningSent && idleDuration > idleTimeout) {
prepareDestroy(); prepareDestroy();
} }
}
if (((timeRunning - lastActionReceived) >= qCeil(server->getIdleClientTimeout() * .9)) && const bool shouldWarnBeforeIdleTimeout =
(!idleClientWarningSent) && (server->getIdleClientTimeout() > 0)) { idleTimeout > 0 && !idleClientWarningSent && idleDuration >= qCeil(idleTimeout * .9);
if (shouldWarnBeforeIdleTimeout) {
Event_NotifyUser event; Event_NotifyUser event;
event.set_type(Event_NotifyUser::IDLEWARNING); event.set_type(Event_NotifyUser::IDLEWARNING);
SessionEvent *se = prepareSessionEvent(event); SessionEvent *se = prepareSessionEvent(event);