diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2017-06-27 00:22:33 +0200 |
|---|---|---|
| committer | Carbenium <carbenium@outlook.com> | 2020-07-16 22:00:30 +0200 |
| commit | 2c3fc47a96baa8a47130befda647bf29d8eacce1 (patch) | |
| tree | d2b003d52361193409965d7e914eceed6071efd0 /src | |
| parent | 37c3259de8a53f6e790707f4f105dda7a297c28d (diff) | |
Proper client timeout detection (#19906)
- Properly detect client timeout when logged into a character after a configurable time (default 60s) has passed without the client sending any packets.
- Fixes issues with crashed clients leaving characters in the world for a very long time (default 15 minutes), as well as edge case exploits involving intentionally pausing client execution for some amount of time.
(cherry picked from commit 7dfd472f8dff6ce067572e2887c2beb56d9ba9de)
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 14 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.h | 2 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 8 | ||||
| -rw-r--r-- | src/server/game/World/World.cpp | 3 | ||||
| -rw-r--r-- | src/server/game/World/World.h | 1 | ||||
| -rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 9 |
6 files changed, 27 insertions, 10 deletions
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index ef257e71c9f..0e3817bb509 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -142,7 +142,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun if (sock) { m_Address = sock->GetRemoteIpAddress().to_string(); - ResetTimeOutTime(); + ResetTimeOutTime(false); LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query } @@ -327,7 +327,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) UpdateTimeOutTime(diff); ///- Before we process anything: - /// If necessary, kick the player from the character select screen + /// If necessary, kick the player because the client didn't send anything for too long + /// (or they've been idling in character select) if (IsConnectionIdle()) m_Socket[CONNECTION_TYPE_REALM]->CloseSocket(); @@ -697,9 +698,12 @@ char const* WorldSession::GetTrinityString(uint32 entry) const return sObjectMgr->GetTrinityString(entry, GetSessionDbLocaleIndex()); } -void WorldSession::ResetTimeOutTime() +void WorldSession::ResetTimeOutTime(bool onlyActive) { - m_timeOutTime = int32(sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME)); + if (GetPlayer()) + m_timeOutTime = int32(sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME_ACTIVE)); + else if (!onlyActive) + m_timeOutTime = int32(sWorld->getIntConfig(CONFIG_SOCKET_TIMEOUTTIME)); } void WorldSession::Handle_NULL(WorldPackets::Null& null) @@ -1069,7 +1073,7 @@ void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder* realmHold SendAuthWaitQue(0); SetInQueue(false); - ResetTimeOutTime(); + ResetTimeOutTime(false); SendSetTimeZoneInformation(); SendFeatureSystemStatusGlueScreen(); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 0f2a577d260..fdbac1a465e 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1095,7 +1095,7 @@ class TC_GAME_API WorldSession m_timeOutTime -= int32(diff); } - void ResetTimeOutTime(); + void ResetTimeOutTime(bool onlyActive); bool IsConnectionIdle() const { diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 022e1c289a2..0ea17e4143d 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -424,7 +424,10 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() return ReadDataHandlerResult::WaitingForQuery; } case CMSG_KEEP_ALIVE: + sessionGuard.lock(); LogOpcodeText(opcode, sessionGuard); + if (_worldSession) + _worldSession->ResetTimeOutTime(true); break; case CMSG_LOG_DISCONNECT: LogOpcodeText(opcode, sessionGuard); @@ -471,9 +474,8 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() break; } - // Our Idle timer will reset on any non PING opcodes. - // Catches people idling on the login screen and any lingering ingame connections. - _worldSession->ResetTimeOutTime(); + // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling. + _worldSession->ResetTimeOutTime(false); // Copy the packet to the heap before enqueuing _worldSession->QueuePacket(new WorldPacket(std::move(packet))); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 828db2cd210..8d5f8ca66ac 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -410,7 +410,7 @@ bool World::RemoveQueuedPlayer(WorldSession* sess) if (*iter == sess) { sess->SetInQueue(false); - sess->ResetTimeOutTime(); + sess->ResetTimeOutTime(false); iter = m_QueuedPlayer.erase(iter); found = true; // removing queued session break; @@ -753,6 +753,7 @@ void World::LoadConfigSettings(bool reload) } m_int_configs[CONFIG_SOCKET_TIMEOUTTIME] = sConfigMgr->GetIntDefault("SocketTimeOutTime", 900000); + m_int_configs[CONFIG_SOCKET_TIMEOUTTIME_ACTIVE] = sConfigMgr->GetIntDefault("SocketTimeOutTimeActive", 60000); m_int_configs[CONFIG_SESSION_ADD_DELAY] = sConfigMgr->GetIntDefault("SessionAddDelay", 10000); m_float_configs[CONFIG_GROUP_XP_DISTANCE] = sConfigMgr->GetFloatDefault("MaxGroupXPDistance", 74.0f); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 86cc55cc057..ee3158dc119 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -414,6 +414,7 @@ enum WorldIntConfigs CONFIG_RESPAWN_DYNAMICMINIMUM_CREATURE, CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT, CONFIG_RESPAWN_GUIDWARNING_FREQUENCY, + CONFIG_SOCKET_TIMEOUTTIME_ACTIVE, CONFIG_BLACKMARKET_MAXAUCTIONS, CONFIG_BLACKMARKET_UPDATE_PERIOD, INT_CONFIG_VALUE_COUNT diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index c673c143b42..194d06aeb8f 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -341,6 +341,15 @@ InstanceMapLoadAllGrids = 0 SocketTimeOutTime = 900000 # +# SocketTimeOutTimeActive +# Description: Time (in milliseconds) after which an idle connection is dropped while +# logged into the world. +# The client sends keepalive packets every 30 seconds. Values <= 30s are not recommended. +# Default: 60000 - (1 minute) + +SocketTimeOutTimeActive = 60000 + +# # SessionAddDelay # Description: Time (in microseconds) that a network thread will sleep after authentication # protocol handling before adding a connection to the world session map. |
