AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
WorldSocket Class Reference

#include "WorldSocket.h"

Inheritance diagram for WorldSocket:
Socket< WorldSocket >

Public Member Functions

 WorldSocket (tcp::socket &&socket)
 
 ~WorldSocket ()
 
 WorldSocket (WorldSocket const &right)=delete
 
WorldSocketoperator= (WorldSocket const &right)=delete
 
void Start () override
 
bool Update () override
 
void SendPacket (WorldPacket const &packet)
 
void SetSendBufferSize (std::size_t sendBufferSize)
 
- Public Member Functions inherited from Socket< WorldSocket >
 Socket (tcp::socket &&socket)
 
virtual ~Socket ()
 
virtual void Start ()=0
 
virtual bool Update ()
 
boost::asio::ip::address GetRemoteIpAddress () const
 
uint16 GetRemotePort () const
 
void AsyncRead ()
 
void AsyncReadWithCallback (void(T::*callback)(boost::system::error_code, std::size_t))
 
void QueuePacket (MessageBuffer &&buffer)
 
bool IsOpen () const
 
void CloseSocket ()
 
void DelayedCloseSocket ()
 Marks the socket for closing after write buffer becomes empty.
 
MessageBufferGetReadBuffer ()
 

Protected Types

enum class  ReadDataHandlerResult {
  Ok = 0 ,
  Error = 1 ,
  WaitingForQuery = 2
}
 

Protected Member Functions

void OnClose () override
 
void ReadHandler () override
 
bool ReadHeaderHandler ()
 
ReadDataHandlerResult ReadDataHandler ()
 
- Protected Member Functions inherited from Socket< WorldSocket >
virtual void OnClose ()
 
virtual void ReadHandler ()=0
 
bool AsyncProcessQueue ()
 
void SetNoDelay (bool enable)
 

Private Types

typedef Socket< WorldSocketBaseSocket
 

Private Member Functions

void CheckIpCallback (PreparedQueryResult result)
 
void LogOpcodeText (OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
 
void SendPacketAndLogOpcode (WorldPacket const &packet)
 sends and logs network.opcode without accessing WorldSession
 
void HandleSendAuthSession ()
 
void HandleAuthSession (WorldPacket &recvPacket)
 
void HandleAuthSessionCallback (std::shared_ptr< AuthSession > authSession, PreparedQueryResult result)
 
void LoadSessionPermissionsCallback (PreparedQueryResult result)
 
void SendAuthResponseError (uint8 code)
 
bool HandlePing (WorldPacket &recvPacket)
 

Private Attributes

std::array< uint8, 4 > _authSeed
 
AuthCrypt _authCrypt
 
TimePoint _LastPingTime
 
uint32 _OverSpeedPings
 
std::mutex _worldSessionLock
 
WorldSession_worldSession
 
bool _authed
 
MessageBuffer _headerBuffer
 
MessageBuffer _packetBuffer
 
MPSCQueue< EncryptablePacket, &EncryptablePacket::SocketQueueLink_bufferQueue
 
std::size_t _sendBufferSize
 
QueryCallbackProcessor _queryProcessor
 
std::string _ipCountry
 

Detailed Description

Member Typedef Documentation

◆ BaseSocket

Member Enumeration Documentation

◆ ReadDataHandlerResult

enum class WorldSocket::ReadDataHandlerResult
strongprotected
Enumerator
Ok 
Error 
WaitingForQuery 

Constructor & Destructor Documentation

◆ WorldSocket() [1/2]

WorldSocket::WorldSocket ( tcp::socket &&  socket)
38 : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
39{
42}
std::array< uint8, S > GetRandomBytes()
Definition: CryptoRandom.h:35
void Resize(size_type bytes)
Definition: MessageBuffer.h:52
Definition: WorldSocket.h:56
MessageBuffer _headerBuffer
Definition: WorldSocket.h:126
bool _authed
Definition: WorldSocket.h:124
std::size_t _sendBufferSize
Definition: WorldSocket.h:129
uint32 _OverSpeedPings
Definition: WorldSocket.h:120
WorldSession * _worldSession
Definition: WorldSocket.h:123
std::array< uint8, 4 > _authSeed
Definition: WorldSocket.h:116
Definition: Socket.h:39

References _authSeed, _headerBuffer, Acore::Crypto::GetRandomBytes(), and MessageBuffer::Resize().

◆ ~WorldSocket()

WorldSocket::~WorldSocket ( )
default

◆ WorldSocket() [2/2]

WorldSocket::WorldSocket ( WorldSocket const &  right)
delete

Member Function Documentation

◆ CheckIpCallback()

void WorldSocket::CheckIpCallback ( PreparedQueryResult  result)
private
57{
58 if (result)
59 {
60 bool banned = false;
61 do
62 {
63 Field* fields = result->Fetch();
64 if (fields[0].Get<uint64>() != 0)
65 banned = true;
66
67 } while (result->NextRow());
68
69 if (banned)
70 {
72 LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP {} banned).", GetRemoteIpAddress().to_string());
74 return;
75 }
76 }
77
78 AsyncRead();
80}
#define LOG_ERROR(filterType__,...)
Definition: Log.h:159
@ AUTH_REJECT
Definition: SharedDefines.h:3309
Class used to access individual fields of database query result.
Definition: Field.h:99
void HandleSendAuthSession()
Definition: WorldSocket.cpp:128
void SendAuthResponseError(uint8 code)
Definition: WorldSocket.cpp:624
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition: Socket.h:141
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:76
void AsyncRead()
Definition: Socket.h:86

References Socket< WorldSocket >::AsyncRead(), AUTH_REJECT, Socket< WorldSocket >::DelayedCloseSocket(), Socket< WorldSocket >::GetRemoteIpAddress(), HandleSendAuthSession(), LOG_ERROR, and SendAuthResponseError().

Referenced by Start().

◆ HandleAuthSession()

void WorldSocket::HandleAuthSession ( WorldPacket recvPacket)
private
430{
431 std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();
432
433 // Read the content of the packet
434 recvPacket >> authSession->Build;
435 recvPacket >> authSession->LoginServerID;
436 recvPacket >> authSession->Account;
437 recvPacket >> authSession->LoginServerType;
438 recvPacket.read(authSession->LocalChallenge);
439 recvPacket >> authSession->RegionID;
440 recvPacket >> authSession->BattlegroupID;
441 recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table
442 recvPacket >> authSession->DosResponse;
443 recvPacket.read(authSession->Digest);
444 authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos());
445 recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want
446
447 // Get the account information from the auth database
449 stmt->SetData(0, int32(realm.Id.Realm));
450 stmt->SetData(1, authSession->Account);
451
452 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)));
453}
std::int32_t int32
Definition: Define.h:104
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
@ LOGIN_SEL_ACCOUNT_INFO_BY_NAME
Definition: LoginDatabase.h:50
Realm realm
Definition: World.cpp:113
T & AddCallback(T &&query)
Definition: AsyncCallbackProcessor.h:35
Definition: PreparedStatement.h:158
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition: PreparedStatement.h:78
QueryCallbackProcessor _queryProcessor
Definition: WorldSocket.h:131
void HandleAuthSessionCallback(std::shared_ptr< AuthSession > authSession, PreparedQueryResult result)
Definition: WorldSocket.cpp:455
size_t rpos() const
Definition: ByteBuffer.h:317
size_t size() const
Definition: ByteBuffer.h:444
T read()
Definition: ByteBuffer.h:351
uint32 Realm
Definition: Realm.h:42
RealmHandle Id
Definition: Realm.h:68

References _queryProcessor, AsyncCallbackProcessor< T >::AddCallback(), HandleAuthSessionCallback(), Realm::Id, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, LoginDatabase, ByteBuffer::read(), realm, RealmHandle::Realm, ByteBuffer::rpos(), PreparedStatementBase::SetData(), and ByteBuffer::size().

Referenced by ReadDataHandler().

◆ HandleAuthSessionCallback()

void WorldSocket::HandleAuthSessionCallback ( std::shared_ptr< AuthSession authSession,
PreparedQueryResult  result 
)
private
  • Re-check ip locking (same check as in auth).

Negative mutetime indicates amount of minutes to be muted effective on next login - which is now.

456{
457 // Stop if the account is not found
458 if (!result)
459 {
460 // We can not log here, as we do not know the account. Thus, no accountId.
462 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
464 return;
465 }
466
467 AccountInfo account(result->Fetch());
468
469 // For hook purposes, we get Remoteaddress at this point.
470 std::string address = sConfigMgr->GetOption<bool>("AllowLoggingIPAddressesInDatabase", true, true) ? GetRemoteIpAddress().to_string() : "0.0.0.0";
471
472 LoginDatabasePreparedStatement* stmt = nullptr;
473
474 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
475 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
476 stmt->SetData(0, address);
477 stmt->SetData(1, authSession->Account);
478 LoginDatabase.Execute(stmt);
479 // This also allows to check for possible "hack" attempts on account
480
481 // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
482 _authCrypt.Init(account.SessionKey);
483
484 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
485 if (sWorld->IsClosed())
486 {
488 LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", GetRemoteIpAddress().to_string());
490 return;
491 }
492
493 if (authSession->RealmID != realm.Id.Realm)
494 {
496 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
497 GetRemoteIpAddress().to_string(), authSession->RealmID, realm.Id.Realm);
499 return;
500 }
501
502 // Must be done before WorldSession is created
503 bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
504 if (wardenActive && account.OS != "Win" && account.OS != "OSX")
505 {
507 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
509 return;
510 }
511
512 // Check that Key and account name are the same on client and server
513 uint8 t[4] = { 0x00,0x00,0x00,0x00 };
514
516 sha.UpdateData(authSession->Account);
517 sha.UpdateData(t);
518 sha.UpdateData(authSession->LocalChallenge);
520 sha.UpdateData(account.SessionKey);
521 sha.Finalize();
522
523 if (sha.GetDigest() != authSession->Digest)
524 {
526 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Id, authSession->Account, address);
528 return;
529 }
530
531 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
532 _ipCountry = location->CountryCode;
533
535 if (account.IsLockedToIP)
536 {
537 if (account.LastIP != address)
538 {
540 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.LastIP, address);
541 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
542 sScriptMgr->OnFailedAccountLogin(account.Id);
544 return;
545 }
546 }
547 else if (!account.LockCountry.empty() && account.LockCountry != "00" && !_ipCountry.empty())
548 {
549 if (account.LockCountry != _ipCountry)
550 {
552 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.LockCountry, _ipCountry);
553 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
554 sScriptMgr->OnFailedAccountLogin(account.Id);
556 return;
557 }
558 }
559
561 if (account.MuteTime < 0)
562 {
563 account.MuteTime = GameTime::GetGameTime().count() + llabs(account.MuteTime);
564
565 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
566 stmt->SetData(0, account.MuteTime);
567 stmt->SetData(1, account.Id);
568 LoginDatabase.Execute(stmt);
569 }
570
571 if (account.IsBanned)
572 {
574 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
575 sScriptMgr->OnFailedAccountLogin(account.Id);
577 return;
578 }
579
580 // Check locked state for server
581 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
582 LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Security);
583 if (allowedAccountType > SEC_PLAYER && account.Security < allowedAccountType)
584 {
586 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
587 sScriptMgr->OnFailedAccountLogin(account.Id);
589 return;
590 }
591
592 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->Account, address);
593
594 // Update the last_ip in the database as it was successful for login
595 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
596 stmt->SetData(0, address);
597 stmt->SetData(1, authSession->Account);
598
599 LoginDatabase.Execute(stmt);
600
601 // At this point, we can safely hook a successful login
602 sScriptMgr->OnAccountLogin(account.Id);
603
604 _authed = true;
605
606 sScriptMgr->OnLastIpUpdate(account.Id, address);
607
608 _worldSession = new WorldSession(account.Id, std::move(authSession->Account), shared_from_this(), account.Security,
609 account.Expansion, account.MuteTime, account.Locale, account.Recruiter, account.IsRectuiter, account.Security ? true : false, account.TotalTime);
610
611 _worldSession->ReadAddonsInfo(authSession->AddonInfo);
612
613 // Initialize Warden system only if it is enabled by config
614 if (wardenActive)
615 {
616 _worldSession->InitWarden(account.SessionKey, account.OS);
617 }
618
619 sWorld->AddSession(_worldSession);
620
621 AsyncRead();
622}
#define llabs
Definition: Common.h:46
AccountTypes
Definition: Common.h:65
@ SEC_PLAYER
Definition: Common.h:66
#define sConfigMgr
Definition: Config.h:92
std::uint8_t uint8
Definition: Define.h:110
#define sIPLocation
Definition: IPLocation.h:49
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:171
@ LOGIN_UPD_MUTE_TIME_LOGIN
Definition: LoginDatabase.h:72
@ LOGIN_UPD_LAST_ATTEMPT_IP
Definition: LoginDatabase.h:74
@ LOGIN_UPD_LAST_IP
Definition: LoginDatabase.h:73
#define sScriptMgr
Definition: ScriptMgr.h:2702
@ CONFIG_WARDEN_ENABLED
Definition: IWorld.h:150
@ REALM_LIST_REALM_NOT_FOUND
Definition: SharedDefines.h:3335
@ AUTH_FAILED
Definition: SharedDefines.h:3308
@ AUTH_UNKNOWN_ACCOUNT
Definition: SharedDefines.h:3316
@ AUTH_BANNED
Definition: SharedDefines.h:3323
@ AUTH_UNAVAILABLE
Definition: SharedDefines.h:3311
#define sWorld
Definition: World.h:451
Seconds GetGameTime()
Definition: GameTime.cpp:38
void Init(SessionKey const &K)
Definition: AuthCrypt.cpp:22
Definition: CryptoHash.h:48
void UpdateData(uint8 const *data, size_t len)
Definition: CryptoHash.h:115
void Finalize()
Definition: CryptoHash.h:128
Digest const & GetDigest() const
Definition: CryptoHash.h:136
Definition: IPLocation.h:23
Definition: AuthSession.h:49
Player session in the World.
Definition: WorldSession.h:330
void ReadAddonsInfo(ByteBuffer &data)
Definition: WorldSession.cpp:1139
void InitWarden(SessionKey const &, std::string const &os)
Definition: WorldSession.cpp:1315
std::string _ipCountry
Definition: WorldSocket.h:132
AuthCrypt _authCrypt
Definition: WorldSocket.h:117

References _authCrypt, _authed, _authSeed, _ipCountry, _worldSession, Socket< WorldSocket >::AsyncRead(), AUTH_BANNED, AUTH_FAILED, AUTH_REJECT, AUTH_UNAVAILABLE, AUTH_UNKNOWN_ACCOUNT, CONFIG_WARDEN_ENABLED, Socket< WorldSocket >::DelayedCloseSocket(), AccountInfo::Expansion, Acore::Impl::GenericHash< HashCreator, DigestLength >::Finalize(), Acore::Impl::GenericHash< HashCreator, DigestLength >::GetDigest(), GameTime::GetGameTime(), Socket< WorldSocket >::GetRemoteIpAddress(), AccountInfo::Id, Realm::Id, AuthCrypt::Init(), WorldSession::InitWarden(), AccountInfo::IsBanned, AccountInfo::IsLockedToIP, AccountInfo::IsRectuiter, AccountInfo::LastIP, llabs, AccountInfo::Locale, AccountInfo::LockCountry, LOG_DEBUG, LOG_ERROR, LOGIN_UPD_LAST_ATTEMPT_IP, LOGIN_UPD_LAST_IP, LOGIN_UPD_MUTE_TIME_LOGIN, LoginDatabase, AccountInfo::MuteTime, AccountInfo::OS, WorldSession::ReadAddonsInfo(), realm, RealmHandle::Realm, REALM_LIST_REALM_NOT_FOUND, AccountInfo::Recruiter, sConfigMgr, SEC_PLAYER, AccountInfo::Security, SendAuthResponseError(), AccountInfo::SessionKey, PreparedStatementBase::SetData(), sIPLocation, sScriptMgr, sWorld, AccountInfo::TotalTime, and Acore::Impl::GenericHash< HashCreator, DigestLength >::UpdateData().

Referenced by HandleAuthSession().

◆ HandlePing()

bool WorldSocket::HandlePing ( WorldPacket recvPacket)
private
633{
634 using namespace std::chrono;
635
636 uint32 ping;
637 uint32 latency;
638
639 // Get the ping packet content
640 recvPacket >> ping;
641 recvPacket >> latency;
642
643 if (_LastPingTime == steady_clock::time_point())
644 {
645 _LastPingTime = steady_clock::now();
646 }
647 else
648 {
649 steady_clock::time_point now = steady_clock::now();
650 steady_clock::duration diff = now - _LastPingTime;
651
652 _LastPingTime = now;
653
654 if (diff < seconds(27))
655 {
657
658 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
659
660 if (maxAllowed && _OverSpeedPings > maxAllowed)
661 {
662 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
663
665 {
666 LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
668
669 return false;
670 }
671 }
672 }
673 else
674 {
675 _OverSpeedPings = 0;
676 }
677 }
678
679 {
680 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
681
682 if (_worldSession)
683 _worldSession->SetLatency(latency);
684 else
685 {
686 LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress().to_string());
687 return false;
688 }
689 }
690
691 WorldPacket packet(SMSG_PONG, 4);
692 packet << ping;
694
695 return true;
696}
std::uint32_t uint32
Definition: Define.h:108
@ CONFIG_MAX_OVERSPEED_PINGS
Definition: IWorld.h:273
@ SMSG_PONG
Definition: Opcodes.h:507
bool IsPlayerAccount(uint32 gmlevel)
Definition: AccountMgr.cpp:276
Definition: WorldPacket.h:27
AccountTypes GetSecurity() const
Definition: WorldSession.h:358
std::string GetPlayerInfo() const
Definition: WorldSession.cpp:184
void SetLatency(uint32 latency)
Definition: WorldSession.h:501
TimePoint _LastPingTime
Definition: WorldSocket.h:119
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition: WorldSocket.cpp:412
std::mutex _worldSessionLock
Definition: WorldSocket.h:122

References _LastPingTime, _OverSpeedPings, _worldSession, _worldSessionLock, CONFIG_MAX_OVERSPEED_PINGS, WorldSession::GetPlayerInfo(), Socket< WorldSocket >::GetRemoteIpAddress(), WorldSession::GetSecurity(), AccountMgr::IsPlayerAccount(), LOG_ERROR, SendPacketAndLogOpcode(), WorldSession::SetLatency(), SMSG_PONG, and sWorld.

Referenced by ReadDataHandler().

◆ HandleSendAuthSession()

void WorldSocket::HandleSendAuthSession ( )
private
129{
131 packet << uint32(1); // 1...31
132 packet.append(_authSeed);
133
134 packet.append(Acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
135
137}
@ SMSG_AUTH_CHALLENGE
Definition: Opcodes.h:522

References _authSeed, ByteBuffer::append(), SendPacketAndLogOpcode(), and SMSG_AUTH_CHALLENGE.

Referenced by CheckIpCallback().

◆ LoadSessionPermissionsCallback()

void WorldSocket::LoadSessionPermissionsCallback ( PreparedQueryResult  result)
private

◆ LogOpcodeText()

void WorldSocket::LogOpcodeText ( OpcodeClient  opcode,
std::unique_lock< std::mutex > const &  guard 
) const
private

writes network.opcode log accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock

400{
401 if (!guard)
402 {
403 LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(opcode));
404 }
405 else
406 {
407 LOG_TRACE("network.opcode", "C->S: {} {}", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()),
409 }
410}
#define LOG_TRACE(filterType__,...)
Definition: Log.h:175
std::string GetOpcodeNameForLogging(Opcodes opcode)
Lookup opcode name for human understandable logging.
Definition: Opcodes.cpp:1468

References _worldSession, GetOpcodeNameForLogging(), WorldSession::GetPlayerInfo(), Socket< WorldSocket >::GetRemoteIpAddress(), and LOG_TRACE.

Referenced by ReadDataHandler().

◆ OnClose()

void WorldSocket::OnClose ( )
overrideprotectedvirtual

Reimplemented from Socket< WorldSocket >.

140{
141 {
142 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
143 _worldSession = nullptr;
144 }
145}

References _worldSession, and _worldSessionLock.

◆ operator=()

WorldSocket & WorldSocket::operator= ( WorldSocket const &  right)
delete

◆ ReadDataHandler()

WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler ( )
protected
Todo:
: handle this packet in the same way of CMSG_TIME_SYNC_RESP
306{
307 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
308 OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
309
310 WorldPacket packet(opcode, std::move(_packetBuffer));
311 WorldPacket* packetToQueue;
312
313 if (sPacketLog->CanLogPacket())
315
316 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
317
318 switch (opcode)
319 {
320 case CMSG_PING:
321 {
322 LogOpcodeText(opcode, sessionGuard);
323 try
324 {
326 }
327 catch (ByteBufferException const&)
328 {
329 }
330 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
332 }
334 {
335 LogOpcodeText(opcode, sessionGuard);
336 if (_authed)
337 {
338 // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
339 if (sessionGuard.try_lock())
340 LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
342 }
343
344 try
345 {
346 HandleAuthSession(packet);
348 }
349 catch (ByteBufferException const&) { }
350
351 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string());
353 }
354 case CMSG_KEEP_ALIVE:
355 sessionGuard.lock();
356 LogOpcodeText(opcode, sessionGuard);
357 if (_worldSession)
361 packetToQueue = new WorldPacket(std::move(packet), GameTime::Now());
362 break;
363 default:
364 packetToQueue = new WorldPacket(std::move(packet));
365 break;
366 }
367
368 sessionGuard.lock();
369
370 LogOpcodeText(opcode, sessionGuard);
371
372 if (!_worldSession)
373 {
374 LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = {}", uint32(opcode));
375 delete packetToQueue;
377 }
378
379 OpcodeHandler const* handler = opcodeTable[opcode];
380 if (!handler)
381 {
382 LOG_ERROR("network.opcode", "No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet.GetOpcode())), _worldSession->GetPlayerInfo());
383 delete packetToQueue;
385 }
386
387 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
388 if (packetToQueue->GetOpcode() != CMSG_WARDEN_DATA)
389 {
391 }
392
393 // Copy the packet to the heap before enqueuing
394 _worldSession->QueuePacket(packetToQueue);
395
397}
#define sPacketLog
Definition: PacketLog.h:52
@ CLIENT_TO_SERVER
Definition: PacketLog.h:27
Opcodes
List of Opcodes.
Definition: Opcodes.h:30
OpcodeTable opcodeTable
Definition: Opcodes.cpp:51
@ CMSG_TIME_SYNC_RESP
Definition: Opcodes.h:943
@ CMSG_PING
Definition: Opcodes.h:506
@ CMSG_WARDEN_DATA
Definition: Opcodes.h:773
@ CMSG_KEEP_ALIVE
Definition: Opcodes.h:1061
@ CMSG_AUTH_SESSION
Definition: Opcodes.h:523
TimePoint Now()
Current chrono steady_clock time point.
Definition: GameTime.cpp:53
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
Definition: Opcodes.h:1375
uint16 GetOpcode() const
Definition: WorldPacket.h:76
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
Definition: WorldSession.cpp:264
void ResetTimeOutTime(bool onlyActive)
Definition: WorldSession.h:511
uint32 cmd
Definition: WorldSocket.h:58
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
Definition: WorldSocket.cpp:399
void HandleAuthSession(WorldPacket &recvPacket)
Definition: WorldSocket.cpp:429
bool HandlePing(WorldPacket &recvPacket)
Definition: WorldSocket.cpp:632
MessageBuffer _packetBuffer
Definition: WorldSocket.h:127
uint16 GetRemotePort() const
Definition: Socket.h:81
Definition: ByteBuffer.h:32

References _authed, _headerBuffer, _packetBuffer, _worldSession, _worldSessionLock, CLIENT_TO_SERVER, ClientPktHeader::cmd, CMSG_AUTH_SESSION, CMSG_KEEP_ALIVE, CMSG_PING, CMSG_TIME_SYNC_RESP, CMSG_WARDEN_DATA, Error, WorldPacket::GetOpcode(), GetOpcodeNameForLogging(), WorldSession::GetPlayerInfo(), MessageBuffer::GetReadPointer(), Socket< WorldSocket >::GetRemoteIpAddress(), Socket< WorldSocket >::GetRemotePort(), HandleAuthSession(), HandlePing(), LOG_ERROR, LogOpcodeText(), GameTime::Now(), Ok, opcodeTable, WorldSession::QueuePacket(), WorldSession::ResetTimeOutTime(), sPacketLog, and WaitingForQuery.

Referenced by ReadHandler().

◆ ReadHandler()

void WorldSocket::ReadHandler ( )
overrideprotectedvirtual

Implements Socket< WorldSocket >.

148{
149 if (!IsOpen())
150 return;
151
152 MessageBuffer& packet = GetReadBuffer();
153 while (packet.GetActiveSize() > 0)
154 {
156 {
157 // need to receive the header
158 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
159 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
160 packet.ReadCompleted(readHeaderSize);
161
163 {
164 // Couldn't receive the whole header this time.
165 ASSERT(packet.GetActiveSize() == 0);
166 break;
167 }
168
169 // We just received nice new header
170 if (!ReadHeaderHandler())
171 {
172 CloseSocket();
173 return;
174 }
175 }
176
177 // We have full read header, now check the data payload
179 {
180 // need more data in the payload
181 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
182 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
183 packet.ReadCompleted(readDataSize);
184
186 {
187 // Couldn't receive the whole data this time.
188 ASSERT(packet.GetActiveSize() == 0);
189 break;
190 }
191 }
192
193 // just received fresh new payload
196
197 if (result != ReadDataHandlerResult::Ok)
198 {
200 {
201 CloseSocket();
202 }
203
204 return;
205 }
206 }
207
208 AsyncRead();
209}
#define ASSERT
Definition: Errors.h:68
Definition: MessageBuffer.h:26
size_type GetRemainingSpace() const
Definition: MessageBuffer.h:65
void ReadCompleted(size_type bytes)
Definition: MessageBuffer.h:61
size_type GetActiveSize() const
Definition: MessageBuffer.h:64
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:93
void Reset()
Definition: MessageBuffer.h:46
bool ReadHeaderHandler()
Definition: WorldSocket.cpp:211
ReadDataHandlerResult
Definition: WorldSocket.h:91
ReadDataHandlerResult ReadDataHandler()
Definition: WorldSocket.cpp:305
MessageBuffer & GetReadBuffer()
Definition: Socket.h:143
bool IsOpen() const
Definition: Socket.h:123
void CloseSocket()
Definition: Socket.h:125

References _headerBuffer, _packetBuffer, ASSERT, Socket< WorldSocket >::AsyncRead(), Socket< WorldSocket >::CloseSocket(), MessageBuffer::GetActiveSize(), Socket< WorldSocket >::GetReadBuffer(), MessageBuffer::GetReadPointer(), MessageBuffer::GetRemainingSpace(), Socket< WorldSocket >::IsOpen(), Ok, MessageBuffer::ReadCompleted(), ReadDataHandler(), ReadHeaderHandler(), MessageBuffer::Reset(), WaitingForQuery, and MessageBuffer::Write().

◆ ReadHeaderHandler()

bool WorldSocket::ReadHeaderHandler ( )
protected
212{
214
216 {
218 }
219
220 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
221 EndianConvertReverse(header->size);
222 EndianConvert(header->cmd);
223
224 if (!header->IsValidSize() || !header->IsValidOpcode())
225 {
226 LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
227 GetRemoteIpAddress().to_string(), header->size, header->cmd);
228
229 return false;
230 }
231
232 header->size -= sizeof(header->cmd);
233 _packetBuffer.Resize(header->size);
234
235 return true;
236}
void EndianConvertReverse(T &)
Definition: ByteConverter.h:48
void EndianConvert(T &val)
Definition: ByteConverter.h:47
bool IsInitialized() const
Definition: AuthCrypt.h:33
void DecryptRecv(uint8 *data, size_t len)
Definition: AuthCrypt.cpp:38
uint16 size
Definition: WorldSocket.h:57
bool IsValidSize() const
Definition: WorldSocket.h:60
bool IsValidOpcode() const
Definition: WorldSocket.h:61

References _authCrypt, _headerBuffer, _packetBuffer, ASSERT, ClientPktHeader::cmd, AuthCrypt::DecryptRecv(), EndianConvert(), EndianConvertReverse(), MessageBuffer::GetActiveSize(), MessageBuffer::GetReadPointer(), Socket< WorldSocket >::GetRemoteIpAddress(), AuthCrypt::IsInitialized(), ClientPktHeader::IsValidOpcode(), ClientPktHeader::IsValidSize(), LOG_ERROR, MessageBuffer::Resize(), and ClientPktHeader::size.

Referenced by ReadHandler().

◆ SendAuthResponseError()

void WorldSocket::SendAuthResponseError ( uint8  code)
private
625{
627 packet << uint8(code);
628
630}
@ SMSG_AUTH_RESPONSE
Definition: Opcodes.h:524

References SendPacketAndLogOpcode(), and SMSG_AUTH_RESPONSE.

Referenced by CheckIpCallback(), and HandleAuthSessionCallback().

◆ SendPacket()

void WorldSocket::SendPacket ( WorldPacket const &  packet)
419{
420 if (!IsOpen())
421 return;
422
423 if (sPacketLog->CanLogPacket())
425
427}
@ SERVER_TO_CLIENT
Definition: PacketLog.h:28
Definition: WorldSocket.h:34
MPSCQueue< EncryptablePacket, &EncryptablePacket::SocketQueueLink > _bufferQueue
Definition: WorldSocket.h:128

References _authCrypt, _bufferQueue, Socket< WorldSocket >::GetRemoteIpAddress(), Socket< WorldSocket >::GetRemotePort(), AuthCrypt::IsInitialized(), Socket< WorldSocket >::IsOpen(), SERVER_TO_CLIENT, and sPacketLog.

Referenced by SendPacketAndLogOpcode().

◆ SendPacketAndLogOpcode()

void WorldSocket::SendPacketAndLogOpcode ( WorldPacket const &  packet)
private

sends and logs network.opcode without accessing WorldSession

413{
414 LOG_TRACE("network.opcode", "S->C: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())));
415 SendPacket(packet);
416}
void SendPacket(WorldPacket const &packet)
Definition: WorldSocket.cpp:418

References WorldPacket::GetOpcode(), GetOpcodeNameForLogging(), Socket< WorldSocket >::GetRemoteIpAddress(), LOG_TRACE, and SendPacket().

Referenced by HandlePing(), HandleSendAuthSession(), and SendAuthResponseError().

◆ SetSendBufferSize()

void WorldSocket::SetSendBufferSize ( std::size_t  sendBufferSize)
inline
83{ _sendBufferSize = sendBufferSize; }

◆ Start()

void WorldSocket::Start ( )
overridevirtual

Implements Socket< WorldSocket >.

47{
48 std::string ip_address = GetRemoteIpAddress().to_string();
49
51 stmt->SetData(0, ip_address);
52
53 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1)));
54}
@ LOGIN_SEL_IP_INFO
Definition: LoginDatabase.h:34
void CheckIpCallback(PreparedQueryResult result)
Definition: WorldSocket.cpp:56

References _queryProcessor, AsyncCallbackProcessor< T >::AddCallback(), CheckIpCallback(), Socket< WorldSocket >::GetRemoteIpAddress(), LOGIN_SEL_IP_INFO, LoginDatabase, and PreparedStatementBase::SetData().

◆ Update()

bool WorldSocket::Update ( )
overridevirtual

Reimplemented from Socket< WorldSocket >.

83{
84 EncryptablePacket* queued;
86 while (_bufferQueue.Dequeue(queued))
87 {
88 ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
89 if (queued->NeedsEncryption())
90 _authCrypt.EncryptSend(header.header, header.getHeaderLength());
91
92 if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength())
93 {
94 QueuePacket(std::move(buffer));
95 buffer.Resize(_sendBufferSize);
96 }
97
98 if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength())
99 {
100 buffer.Write(header.header, header.getHeaderLength());
101 if (!queued->empty())
102 buffer.Write(queued->contents(), queued->size());
103 }
104 else // single packet larger than 4096 bytes
105 {
106 MessageBuffer packetBuffer(queued->size() + header.getHeaderLength());
107 packetBuffer.Write(header.header, header.getHeaderLength());
108 if (!queued->empty())
109 packetBuffer.Write(queued->contents(), queued->size());
110
111 QueuePacket(std::move(packetBuffer));
112 }
113
114 delete queued;
115 }
116
117 if (buffer.GetActiveSize() > 0)
118 QueuePacket(std::move(buffer));
119
120 if (!BaseSocket::Update())
121 return false;
122
124
125 return true;
126}
void EncryptSend(uint8 *data, size_t len)
Definition: AuthCrypt.cpp:44
void ProcessReadyCallbacks()
Definition: AsyncCallbackProcessor.h:41
Definition: ServerPktHeader.h:26
bool NeedsEncryption() const
Definition: WorldSocket.h:41
virtual bool Update()
Definition: Socket.h:56
void QueuePacket(MessageBuffer &&buffer)
Definition: Socket.h:114
bool empty() const
Definition: ByteBuffer.h:445
uint8 * contents()
Definition: ByteBuffer.h:424

References _authCrypt, _bufferQueue, _queryProcessor, _sendBufferSize, ByteBuffer::contents(), ByteBuffer::empty(), AuthCrypt::EncryptSend(), MessageBuffer::GetActiveSize(), ServerPktHeader::getHeaderLength(), WorldPacket::GetOpcode(), MessageBuffer::GetRemainingSpace(), ServerPktHeader::header, EncryptablePacket::NeedsEncryption(), AsyncCallbackProcessor< T >::ProcessReadyCallbacks(), Socket< WorldSocket >::QueuePacket(), MessageBuffer::Resize(), ByteBuffer::size(), Socket< WorldSocket >::Update(), and MessageBuffer::Write().

Member Data Documentation

◆ _authCrypt

AuthCrypt WorldSocket::_authCrypt
private

◆ _authed

bool WorldSocket::_authed
private

◆ _authSeed

std::array<uint8, 4> WorldSocket::_authSeed
private

◆ _bufferQueue

MPSCQueue<EncryptablePacket, &EncryptablePacket::SocketQueueLink> WorldSocket::_bufferQueue
private

Referenced by SendPacket(), and Update().

◆ _headerBuffer

MessageBuffer WorldSocket::_headerBuffer
private

◆ _ipCountry

std::string WorldSocket::_ipCountry
private

◆ _LastPingTime

TimePoint WorldSocket::_LastPingTime
private

Referenced by HandlePing().

◆ _OverSpeedPings

uint32 WorldSocket::_OverSpeedPings
private

Referenced by HandlePing().

◆ _packetBuffer

MessageBuffer WorldSocket::_packetBuffer
private

◆ _queryProcessor

QueryCallbackProcessor WorldSocket::_queryProcessor
private

Referenced by HandleAuthSession(), Start(), and Update().

◆ _sendBufferSize

std::size_t WorldSocket::_sendBufferSize
private

Referenced by Update().

◆ _worldSession

WorldSession* WorldSocket::_worldSession
private

◆ _worldSessionLock

std::mutex WorldSocket::_worldSessionLock
private