diff options
author | Treeston <treeston.mmoc@gmail.com> | 2017-06-27 00:22:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-27 00:22:33 +0200 |
commit | 7dfd472f8dff6ce067572e2887c2beb56d9ba9de (patch) | |
tree | db9a92f5e30f5f6783a8c5a43d56f5953070a35d /src | |
parent | 19fefbb72b0a4a413e86d57a13fb0fd040c2a78a (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.
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 a7a959bd0ea..05f69568507 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -137,7 +137,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS 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 } @@ -271,7 +271,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->CloseSocket(); @@ -633,9 +634,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(WorldPacket& null) @@ -1198,7 +1202,7 @@ void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder) SendAuthWaitQue(0); SetInQueue(false); - ResetTimeOutTime(); + ResetTimeOutTime(false); SendAddonsInfo(); SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 9271fb06e06..237fa991456 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -439,7 +439,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 699c5a38a92..f759e2d27dd 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -357,7 +357,10 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() return ReadDataHandlerResult::Error; } case CMSG_KEEP_ALIVE: + sessionGuard.lock(); LogOpcodeText(opcode, sessionGuard); + if (_worldSession) + _worldSession->ResetTimeOutTime(true); break; default: { @@ -378,9 +381,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 6f5f987e9aa..ae5cc87d097 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -353,7 +353,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; @@ -664,6 +664,7 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_PORT_WORLD] = sConfigMgr->GetIntDefault("WorldServerPort", 8085); 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 6b9e21dcf69..5254b32bbdf 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -389,6 +389,7 @@ enum WorldIntConfigs CONFIG_RESPAWN_DYNAMICMINIMUM_CREATURE, CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT, CONFIG_RESPAWN_GUIDWARNING_FREQUENCY, + CONFIG_SOCKET_TIMEOUTTIME_ACTIVE, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 83dd87a487e..ba8a10c759d 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -305,6 +305,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. |