Skip to content

Commit 8d9bca2

Browse files
committed
Ported WorldSocket timeout feature to native branch
See ACE implementation: 7f01436
1 parent ea9ae47 commit 8d9bca2

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

src/game/Protocol/WorldSocket.cpp

+33-5
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,26 @@
2020
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2121
*/
2222

23+
#include "WorldSocket.h"
24+
#include "WorldSocketMgr.h"
25+
#include "WorldSession.h"
26+
2327
#include "Auth/AuthCrypt.h"
2428
#include "World.h"
2529
#include "AccountMgr.h"
2630
#include "SharedDefines.h"
27-
#include "WorldSession.h"
28-
#include "WorldSocket.h"
29-
30-
#include <memory>
3131
#include "AddonHandler.h"
3232
#include "Opcodes.h"
3333
#include "Crypto/Hash/SHA1.h"
3434
#include "Database/SqlPreparedStatement.h"
3535
#include "Database/DatabaseEnv.h"
3636
#include "DBCStores.h"
37+
#include "Config/Config.h"
38+
3739
#include "IO/Networking/DNS.h"
38-
#include "WorldSocketMgr.h"
40+
#include "IO/Timer/AsyncSystemTimer.h"
41+
42+
#include <memory>
3943

4044
#if defined( __GNUC__ )
4145
#pragma pack(1)
@@ -78,6 +82,11 @@ WorldSocket::~WorldSocket()
7882
{
7983
CloseSocket();
8084
sLog.Out(LOG_NETWORK, LOG_LVL_BASIC, "[%s] Connection closed", GetRemoteIpString().c_str());
85+
86+
if (m_sessionNoAuthTimeout)
87+
{
88+
m_sessionNoAuthTimeout->Cancel();
89+
}
8190
}
8291

8392
void WorldSocket::DoRecvIncomingData()
@@ -412,6 +421,14 @@ WorldSocket::HandlerResult WorldSocket::_HandleAuthSession(WorldPacket& recvPack
412421
return HandlerResult::Fail;
413422
}
414423

424+
425+
// ===== Auth was successful =====
426+
if (this->m_sessionNoAuthTimeout)
427+
{
428+
this->m_sessionNoAuthTimeout->Cancel();
429+
this->m_sessionNoAuthTimeout = nullptr;
430+
}
431+
415432
m_Session = new WorldSession(accountId, this->shared_from_this(), security, mutetime, locale);
416433

417434
m_Crypt.SetKey(K.AsByteArray());
@@ -595,6 +612,17 @@ void WorldSocket::HandleResultOfAsyncWrite(IO::NetworkError const& error, std::s
595612

596613
void WorldSocket::Start()
597614
{
615+
// Start auto timeout loop
616+
if (int secs = sConfig.GetIntDefault("Network.TimeoutSecsIfNoAuth", 10))
617+
{
618+
m_sessionNoAuthTimeout = sAsyncSystemTimer.ScheduleFunctionOnce(std::chrono::seconds(secs), [this]()
619+
{
620+
sLog.Out(LOG_NETWORK, LOG_LVL_DETAIL, "[%s] Connection has reached TimeoutSecsIfNoAuth. Closing socket...", this->GetRemoteIpString().c_str());
621+
// It's correct that we capture _this_ and not a shared_ptr, since the timer will be canceled in destructor
622+
this->CloseSocket();
623+
});
624+
}
625+
598626
SendInitialPacketAndStartRecvLoop();
599627
}
600628

src/game/Protocol/WorldSocket.h

+3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "Auth/AuthCrypt.h"
2828
#include "WorldPacket.h"
2929
#include "WorldSession.h"
30+
#include "IO/Timer/TimerHandle.h"
3031

3132
class WorldSocketMgr;
3233

@@ -95,6 +96,8 @@ class WorldSocket final : public std::enable_shared_from_this<WorldSocket>
9596
/// Called by ProcessIncoming() on CMSG_PING.
9697
HandlerResult _HandlePing(WorldPacket& recvPacket);
9798

99+
std::shared_ptr<IO::Timer::TimerHandle> m_sessionNoAuthTimeout; // nullptr after auth, or if feature is disabled
100+
98101
std::mutex m_sendQueueLock;
99102
std::queue<WorldPacket> m_sendQueue;
100103
std::atomic_flag m_sendQueueIsRunning;

src/mangosd/mangosd.conf.dist.in

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#####################################
44

55
[MangosdConf]
6-
ConfVersion=2024091701
6+
ConfVersion=2025040601
77

88
###################################################################################################################
99
# CONNECTIONS AND DIRECTORIES
@@ -2804,6 +2804,12 @@ LFG.MatchmakingTimer = 600
28042804
# Default: "" - (Disabled, no proxy)
28052805
# Example "10.13.37.1,10.13.37.2" - (to allow multiple proxy servers)
28062806
#
2807+
# Network.TimeoutSecsIfNoAuth
2808+
# Description: Kicks a player if they dont auth within a certain amount of time.
2809+
# (in seconds)
2810+
# Default: 10
2811+
# 0 - to disable
2812+
#
28072813
###################################################################################################################
28082814

28092815
Network.Threads = 1
@@ -2814,6 +2820,7 @@ Network.PacketBroadcast.Threads = 0
28142820
Network.PacketBroadcast.Frequency = 50
28152821
Network.PacketBroadcast.ReduceVisDistance.DiffAbove = 0
28162822
Network.TrustedProxyServers = ""
2823+
Network.TimeoutSecsIfNoAuth = 10
28172824

28182825
###################################################################################################################
28192826
# CONSOLE, REMOTE ACCESS AND SOAP

src/shared/IO/Networking/AsyncSocket.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ namespace IO { namespace Networking {
9494
// We are doing all this atomic stuff, just so we don't have to std::mutex everything
9595
enum SocketStateFlags : int
9696
{
97-
SHUTDOWN_PENDING = (1 << 0), // stop all new transaction requests. There should never be a new _INUSE when this is present
97+
SHUTDOWN_PENDING = (1 << 0), // stop all new transaction requests. There should never be a new `*_PENDING_*` when this is present
9898
IGNORE_TRANSFERS = (1 << 1), // Like SHUTDOWN_PENDING but the event receivers `PerformNonBlockingRead` and `PerformNonBlockingWrite` will ignore the event
9999

100100
// PRESENT: Stuff that is present and set
@@ -127,10 +127,12 @@ namespace IO { namespace Networking {
127127
IO::ReadableBuffer m_writeSrc{};
128128

129129
#if defined(WIN32)
130+
// Windows IOCP stuff:
130131
IocpOperationTask m_currentContextTask; // <-- Internal tasks / callback to internal networking code
131132
IocpOperationTask m_currentWriteTask; // <-- Internal tasks / callback to internal networking code
132133
IocpOperationTask m_currentReadTask; // <-- Internal tasks / callback to internal networking code
133134
#elif defined(__linux__) || defined(__APPLE__)
135+
// Unix epoll stuff:
134136
void PerformNonBlockingRead();
135137
void PerformNonBlockingWrite();
136138
void PerformContextSwitch();

src/shared/IO/Networking/AsyncSocket_windows.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,10 @@ void IO::Networking::AsyncSocket::CloseSocket()
321321
if (m_atomicState.fetch_or(SocketStateFlags::SHUTDOWN_PENDING) & SocketStateFlags::SHUTDOWN_PENDING)
322322
return; // there was already a ::shutdown()
323323

324-
::shutdown(m_descriptor.GetNativeSocket(), SD_BOTH); // will interrupt and fail all pending IOCP events and post them to the queue
324+
// shutdown the native socket to prevent new operations
325+
::shutdown(m_descriptor.GetNativeSocket(), SD_BOTH);
326+
// interrupt and fail all pending IOCP events and post them to the completion queue
327+
::CancelIoEx(reinterpret_cast<HANDLE>(m_descriptor.GetNativeSocket()), nullptr);
325328
}
326329

327330
/// The callback is invoked in the IO thread

src/shared/SystemConfig.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
// Format is YYYYMMDDRR where RR is the change in the conf file
2929
// for that day.
3030
#ifndef _MANGOSDCONFVERSION
31-
# define _MANGOSDCONFVERSION 2024091701
31+
# define _MANGOSDCONFVERSION 2025040601
3232
#endif
3333
#ifndef _REALMDCONFVERSION
3434
# define _REALMDCONFVERSION 2024091701

0 commit comments

Comments
 (0)