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 ()
 
boost::asio::ip::address GetRemoteIpAddress () const
 
uint16 GetRemotePort () const
 
void AsyncRead ()
 
void AsyncReadProxyHeader ()
 
void AsyncReadWithCallback (void(T::*callback)(boost::system::error_code, std::size_t))
 
void QueuePacket (MessageBuffer &&buffer)
 
ProxyHeaderReadingState GetProxyHeaderReadingState () const
 
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 >
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< EncryptableAndCompressiblePacket, &EncryptableAndCompressiblePacket::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)
120 : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
121{
124}
void Resize(size_type bytes)
Definition MessageBuffer.h:52
Definition Socket.h:52
MessageBuffer _headerBuffer
Definition WorldSocket.h:129
bool _authed
Definition WorldSocket.h:127
std::size_t _sendBufferSize
Definition WorldSocket.h:132
uint32 _OverSpeedPings
Definition WorldSocket.h:123
WorldSession * _worldSession
Definition WorldSocket.h:126
std::array< uint8, 4 > _authSeed
Definition WorldSocket.h:119
std::array< uint8, S > GetRandomBytes()
Definition CryptoRandom.h:35
Definition WorldSocket.h:59

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
139{
140 if (result)
141 {
142 bool banned = false;
143 do
144 {
145 Field* fields = result->Fetch();
146 if (fields[0].Get<uint64>() != 0)
147 banned = true;
148
149 } while (result->NextRow());
150
151 if (banned)
152 {
154 LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP {} banned).", GetRemoteIpAddress().to_string());
156 return;
157 }
158 }
159
160 AsyncRead();
162}
#define LOG_ERROR(filterType__,...)
Definition Log.h:157
@ AUTH_REJECT
Definition SharedDefines.h:3337
Class used to access individual fields of database query result.
Definition Field.h:98
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:171
boost::asio::ip::address GetRemoteIpAddress() const
Definition Socket.h:90
void AsyncRead()
Definition Socket.h:100
void HandleSendAuthSession()
Definition WorldSocket.cpp:222
void SendAuthResponseError(uint8 code)
Definition WorldSocket.cpp:722

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
528{
529 std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();
530
531 // Read the content of the packet
532 recvPacket >> authSession->Build;
533 recvPacket >> authSession->LoginServerID;
534 recvPacket >> authSession->Account;
535 recvPacket >> authSession->LoginServerType;
536 recvPacket.read(authSession->LocalChallenge);
537 recvPacket >> authSession->RegionID;
538 recvPacket >> authSession->BattlegroupID;
539 recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table
540 recvPacket >> authSession->DosResponse;
541 recvPacket.read(authSession->Digest);
542 authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos());
543 recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want
544
545 // Get the account information from the auth database
547 stmt->SetData(0, int32(realm.Id.Realm));
548 stmt->SetData(1, authSession->Account);
549
550 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)));
551}
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition DatabaseEnv.cpp:22
std::int32_t int32
Definition Define.h:103
@ LOGIN_SEL_ACCOUNT_INFO_BY_NAME
Definition LoginDatabase.h:50
T & AddCallback(T &&query)
Definition AsyncCallbackProcessor.h:34
std::size_t size() const
Definition ByteBuffer.h:444
std::size_t rpos() const
Definition ByteBuffer.h:317
T read()
Definition ByteBuffer.h:351
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition PreparedStatement.h:77
Definition PreparedStatement.h:157
QueryCallbackProcessor _queryProcessor
Definition WorldSocket.h:134
void HandleAuthSessionCallback(std::shared_ptr< AuthSession > authSession, PreparedQueryResult result)
Definition WorldSocket.cpp:553
Realm realm
Definition World.cpp:111
uint32 Realm
Definition Realm.h:43
RealmHandle Id
Definition Realm.h:69

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.

554{
555 // Stop if the account is not found
556 if (!result)
557 {
558 // We can not log here, as we do not know the account. Thus, no accountId.
560 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
562 return;
563 }
564
565 AccountInfo account(result->Fetch());
566
567 // For hook purposes, we get Remoteaddress at this point.
568 std::string address = sConfigMgr->GetOption<bool>("AllowLoggingIPAddressesInDatabase", true, true) ? GetRemoteIpAddress().to_string() : "0.0.0.0";
569
570 LoginDatabasePreparedStatement* stmt = nullptr;
571
572 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
573 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
574 stmt->SetData(0, address);
575 stmt->SetData(1, authSession->Account);
576 LoginDatabase.Execute(stmt);
577 // This also allows to check for possible "hack" attempts on account
578
579 // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
580 _authCrypt.Init(account.SessionKey);
581
582 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
583 if (sWorld->IsClosed())
584 {
586 LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", GetRemoteIpAddress().to_string());
588 return;
589 }
590
591 if (authSession->RealmID != realm.Id.Realm)
592 {
594 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
595 GetRemoteIpAddress().to_string(), authSession->RealmID, realm.Id.Realm);
597 return;
598 }
599
600 // Must be done before WorldSession is created
601 bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
602 if (wardenActive && account.OS != "Win" && account.OS != "OSX")
603 {
605 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
607 return;
608 }
609
610 // Check that Key and account name are the same on client and server
611 uint8 t[4] = { 0x00,0x00,0x00,0x00 };
612
614 sha.UpdateData(authSession->Account);
615 sha.UpdateData(t);
616 sha.UpdateData(authSession->LocalChallenge);
618 sha.UpdateData(account.SessionKey);
619 sha.Finalize();
620
621 if (sha.GetDigest() != authSession->Digest)
622 {
624 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Id, authSession->Account, address);
626 return;
627 }
628
629 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
630 _ipCountry = location->CountryCode;
631
633 if (account.IsLockedToIP)
634 {
635 if (account.LastIP != address)
636 {
638 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.LastIP, address);
639 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
640 sScriptMgr->OnFailedAccountLogin(account.Id);
642 return;
643 }
644 }
645 else if (!account.LockCountry.empty() && account.LockCountry != "00" && !_ipCountry.empty())
646 {
647 if (account.LockCountry != _ipCountry)
648 {
650 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.LockCountry, _ipCountry);
651 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
652 sScriptMgr->OnFailedAccountLogin(account.Id);
654 return;
655 }
656 }
657
659 if (account.MuteTime < 0)
660 {
661 account.MuteTime = GameTime::GetGameTime().count() + std::llabs(account.MuteTime);
662
663 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
664 stmt->SetData(0, account.MuteTime);
665 stmt->SetData(1, account.Id);
666 LoginDatabase.Execute(stmt);
667 }
668
669 if (account.IsBanned)
670 {
672 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
673 sScriptMgr->OnFailedAccountLogin(account.Id);
675 return;
676 }
677
678 // Check locked state for server
679 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
680 LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Security);
681 if (allowedAccountType > SEC_PLAYER && account.Security < allowedAccountType)
682 {
684 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
685 sScriptMgr->OnFailedAccountLogin(account.Id);
687 return;
688 }
689
690 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->Account, address);
691
692 // Update the last_ip in the database as it was successful for login
693 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
694 stmt->SetData(0, address);
695 stmt->SetData(1, authSession->Account);
696
697 LoginDatabase.Execute(stmt);
698
699 // At this point, we can safely hook a successful login
700 sScriptMgr->OnAccountLogin(account.Id);
701
702 _authed = true;
703
704 sScriptMgr->OnLastIpUpdate(account.Id, address);
705
706 _worldSession = new WorldSession(account.Id, std::move(authSession->Account), shared_from_this(), account.Security,
707 account.Expansion, account.MuteTime, account.Locale, account.Recruiter, account.IsRectuiter, account.Security ? true : false, account.TotalTime);
708
709 _worldSession->ReadAddonsInfo(authSession->AddonInfo);
710
711 // Initialize Warden system only if it is enabled by config
712 if (wardenActive)
713 {
714 _worldSession->InitWarden(account.SessionKey, account.OS);
715 }
716
717 sWorldSessionMgr->AddSession(_worldSession);
718
719 AsyncRead();
720}
AccountTypes
Definition Common.h:56
@ SEC_PLAYER
Definition Common.h:57
#define sConfigMgr
Definition Config.h:74
std::uint8_t uint8
Definition Define.h:109
#define sIPLocation
Definition IPLocation.h:49
@ CONFIG_WARDEN_ENABLED
Definition IWorld.h:145
#define LOG_DEBUG(filterType__,...)
Definition Log.h:169
@ LOGIN_UPD_MUTE_TIME_LOGIN
Definition LoginDatabase.h:73
@ LOGIN_UPD_LAST_ATTEMPT_IP
Definition LoginDatabase.h:75
@ LOGIN_UPD_LAST_IP
Definition LoginDatabase.h:74
#define sScriptMgr
Definition ScriptMgr.h:727
@ REALM_LIST_REALM_NOT_FOUND
Definition SharedDefines.h:3363
@ AUTH_FAILED
Definition SharedDefines.h:3336
@ AUTH_UNKNOWN_ACCOUNT
Definition SharedDefines.h:3344
@ AUTH_BANNED
Definition SharedDefines.h:3351
@ AUTH_UNAVAILABLE
Definition SharedDefines.h:3339
#define sWorldSessionMgr
Definition WorldSessionMgr.h:110
Definition CryptoHash.h:43
void Finalize()
Definition CryptoHash.h:123
void UpdateData(uint8 const *data, std::size_t len)
Definition CryptoHash.h:110
Digest const & GetDigest() const
Definition CryptoHash.h:131
void Init(SessionKey const &K)
Definition AuthCrypt.cpp:22
Player session in the World.
Definition WorldSession.h:330
void ReadAddonsInfo(ByteBuffer &data)
Definition WorldSession.cpp:1125
void InitWarden(SessionKey const &, std::string const &os)
Definition WorldSession.cpp:1308
std::string _ipCountry
Definition WorldSocket.h:135
AuthCrypt _authCrypt
Definition WorldSocket.h:120
#define sWorld
Definition World.h:363
Seconds GetGameTime()
Definition GameTime.cpp:38
Definition AuthSession.h:49
Definition IPLocation.h:23

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, 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, sWorldSessionMgr, AccountInfo::TotalTime, and Acore::Impl::GenericHash< HashCreator, DigestLength >::UpdateData().

Referenced by HandleAuthSession().

◆ HandlePing()

bool WorldSocket::HandlePing ( WorldPacket recvPacket)
private
731{
732 using namespace std::chrono;
733
734 uint32 ping;
735 uint32 latency;
736
737 // Get the ping packet content
738 recvPacket >> ping;
739 recvPacket >> latency;
740
741 if (_LastPingTime == steady_clock::time_point())
742 {
743 _LastPingTime = steady_clock::now();
744 }
745 else
746 {
747 steady_clock::time_point now = steady_clock::now();
748 steady_clock::duration diff = now - _LastPingTime;
749
750 _LastPingTime = now;
751
752 if (diff < seconds(27))
753 {
755
756 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
757
758 if (maxAllowed && _OverSpeedPings > maxAllowed)
759 {
760 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
761
763 {
764 LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
766
767 return false;
768 }
769 }
770 }
771 else
772 {
773 _OverSpeedPings = 0;
774 }
775 }
776
777 {
778 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
779
780 if (_worldSession)
781 _worldSession->SetLatency(latency);
782 else
783 {
784 LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress().to_string());
785 return false;
786 }
787 }
788
789 WorldPacket packet(SMSG_PONG, 4);
790 packet << ping;
792
793 return true;
794}
std::uint32_t uint32
Definition Define.h:107
@ CONFIG_MAX_OVERSPEED_PINGS
Definition IWorld.h:274
Definition WorldPacket.h:26
AccountTypes GetSecurity() const
Definition WorldSession.h:373
std::string GetPlayerInfo() const
Definition WorldSession.cpp:190
void SetLatency(uint32 latency)
Definition WorldSession.h:517
TimePoint _LastPingTime
Definition WorldSocket.h:122
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition WorldSocket.cpp:510
std::mutex _worldSessionLock
Definition WorldSocket.h:125
@ SMSG_PONG
Definition Opcodes.h:507
bool IsPlayerAccount(uint32 gmlevel)
Definition AccountMgr.cpp:305

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
223{
225 packet << uint32(1); // 1...31
226 packet.append(_authSeed);
227
228 packet.append(Acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
229
231}
@ 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

498{
499 if (!guard)
500 {
501 LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(opcode));
502 }
503 else
504 {
505 LOG_TRACE("network.opcode", "C->S: {} {}", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()),
507 }
508}
#define LOG_TRACE(filterType__,...)
Definition Log.h:173
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 >.

234{
235 {
236 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
237 _worldSession = nullptr;
238 }
239}

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
400{
401 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
402 OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
403
404 WorldPacket packet(opcode, std::move(_packetBuffer));
405 WorldPacket* packetToQueue;
406
407 if (sPacketLog->CanLogPacket())
409
410 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
411
412 switch (opcode)
413 {
414 case CMSG_PING:
415 {
416 LogOpcodeText(opcode, sessionGuard);
417 try
418 {
420 }
421 catch (ByteBufferException const&)
422 {
423 }
424 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
426 }
428 {
429 LogOpcodeText(opcode, sessionGuard);
430 if (_authed)
431 {
432 // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
433 if (sessionGuard.try_lock())
434 LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
436 }
437
438 try
439 {
440 HandleAuthSession(packet);
442 }
443 catch (ByteBufferException const&) { }
444
445 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string());
447 }
448 case CMSG_KEEP_ALIVE:
449 sessionGuard.lock();
450 LogOpcodeText(opcode, sessionGuard);
451 if (_worldSession)
452 {
455 }
456 LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress().to_string());
459 packetToQueue = new WorldPacket(std::move(packet), GameTime::Now());
460 break;
461 default:
462 packetToQueue = new WorldPacket(std::move(packet));
463 break;
464 }
465
466 sessionGuard.lock();
467
468 LogOpcodeText(opcode, sessionGuard);
469
470 if (!_worldSession)
471 {
472 LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = {}", uint32(opcode));
473 delete packetToQueue;
475 }
476
477 OpcodeHandler const* handler = opcodeTable[opcode];
478 if (!handler)
479 {
480 LOG_ERROR("network.opcode", "No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packetToQueue->GetOpcode())), _worldSession->GetPlayerInfo());
481 delete packetToQueue;
483 }
484
485 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
486 if (packetToQueue->GetOpcode() != CMSG_WARDEN_DATA)
487 {
489 }
490
491 // Copy the packet to the heap before enqueuing
492 _worldSession->QueuePacket(packetToQueue);
493
495}
#define sPacketLog
Definition PacketLog.h:52
@ CLIENT_TO_SERVER
Definition PacketLog.h:27
Definition ByteBuffer.h:32
uint8 * GetReadPointer()
Definition MessageBuffer.h:58
Definition Opcodes.h:1375
uint16 GetRemotePort() const
Definition Socket.h:95
uint16 GetOpcode() const
Definition WorldPacket.h:75
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
Definition WorldSession.cpp:276
void ResetTimeOutTime(bool onlyActive)
Definition WorldSession.h:527
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
Definition WorldSocket.cpp:497
void HandleAuthSession(WorldPacket &recvPacket)
Definition WorldSocket.cpp:527
bool HandlePing(WorldPacket &recvPacket)
Definition WorldSocket.cpp:730
MessageBuffer _packetBuffer
Definition WorldSocket.h:130
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
uint32 cmd
Definition WorldSocket.h:61

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 >.

242{
243 if (!IsOpen())
244 return;
245
246 MessageBuffer& packet = GetReadBuffer();
247 while (packet.GetActiveSize() > 0)
248 {
250 {
251 // need to receive the header
252 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
253 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
254 packet.ReadCompleted(readHeaderSize);
255
257 {
258 // Couldn't receive the whole header this time.
259 ASSERT(packet.GetActiveSize() == 0);
260 break;
261 }
262
263 // We just received nice new header
264 if (!ReadHeaderHandler())
265 {
266 CloseSocket();
267 return;
268 }
269 }
270
271 // We have full read header, now check the data payload
273 {
274 // need more data in the payload
275 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
276 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
277 packet.ReadCompleted(readDataSize);
278
280 {
281 // Couldn't receive the whole data this time.
282 ASSERT(packet.GetActiveSize() == 0);
283 break;
284 }
285 }
286
287 // just received fresh new payload
290
291 if (result != ReadDataHandlerResult::Ok)
292 {
294 {
295 CloseSocket();
296 }
297
298 return;
299 }
300 }
301
302 AsyncRead();
303}
#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
MessageBuffer & GetReadBuffer()
Definition Socket.h:173
bool IsOpen() const
Definition Socket.h:153
void CloseSocket()
Definition Socket.h:155
bool ReadHeaderHandler()
Definition WorldSocket.cpp:305
ReadDataHandlerResult
Definition WorldSocket.h:94
ReadDataHandlerResult ReadDataHandler()
Definition WorldSocket.cpp:399

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
306{
308
310 {
312 }
313
314 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
315 EndianConvertReverse(header->size);
316 EndianConvert(header->cmd);
317
318 if (!header->IsValidSize() || !header->IsValidOpcode())
319 {
320 LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
321 GetRemoteIpAddress().to_string(), header->size, header->cmd);
322
323 return false;
324 }
325
326 header->size -= sizeof(header->cmd);
327 _packetBuffer.Resize(header->size);
328
329 return true;
330}
void EndianConvertReverse(T &)
Definition ByteConverter.h:48
void EndianConvert(T &val)
Definition ByteConverter.h:47
void DecryptRecv(uint8 *data, std::size_t len)
Definition AuthCrypt.cpp:38
bool IsInitialized() const
Definition AuthCrypt.h:33
uint16 size
Definition WorldSocket.h:60
bool IsValidSize() const
Definition WorldSocket.h:63
bool IsValidOpcode() const
Definition WorldSocket.h:64

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
723{
725 packet << uint8(code);
726
728}
@ 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)
517{
518 if (!IsOpen())
519 return;
520
521 if (sPacketLog->CanLogPacket())
523
525}
@ SERVER_TO_CLIENT
Definition PacketLog.h:28
Definition WorldSocket.h:33
MPSCQueue< EncryptableAndCompressiblePacket, &EncryptableAndCompressiblePacket::SocketQueueLink > _bufferQueue
Definition WorldSocket.h:131

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

511{
512 LOG_TRACE("network.opcode", "S->C: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())));
513 SendPacket(packet);
514}
void SendPacket(WorldPacket const &packet)
Definition WorldSocket.cpp:516

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
86{ _sendBufferSize = sendBufferSize; }

◆ Start()

void WorldSocket::Start ( )
overridevirtual

Implements Socket< WorldSocket >.

129{
130 std::string ip_address = GetRemoteIpAddress().to_string();
131
133 stmt->SetData(0, ip_address);
134
135 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1)));
136}
@ LOGIN_SEL_IP_INFO
Definition LoginDatabase.h:34
void CheckIpCallback(PreparedQueryResult result)
Definition WorldSocket.cpp:138

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 >.

165{
167 if (_bufferQueue.Dequeue(queued))
168 {
169 // Allocate buffer only when it's needed but not on every Update() call.
171 std::size_t currentPacketSize;
172 do
173 {
174 queued->CompressIfNeeded();
175 ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
176 if (queued->NeedsEncryption())
177 _authCrypt.EncryptSend(header.header, header.getHeaderLength());
178
179 currentPacketSize = queued->size() + header.getHeaderLength();
180
181 if (buffer.GetRemainingSpace() < currentPacketSize)
182 {
183 QueuePacket(std::move(buffer));
184 buffer.Resize(_sendBufferSize);
185 }
186
187 if (buffer.GetRemainingSpace() >= currentPacketSize)
188 {
189 buffer.Write(header.header, header.getHeaderLength());
190 if (!queued->empty())
191 buffer.Write(queued->contents(), queued->size());
192 }
193 else // Single packet larger than current buffer size
194 {
195 // Resize buffer to fit current packet
196 buffer.Resize(currentPacketSize);
197
198 // Grow future buffers to current packet size if still below limit
199 if (currentPacketSize <= 65536)
200 _sendBufferSize = currentPacketSize;
201
202 buffer.Write(header.header, header.getHeaderLength());
203 if (!queued->empty())
204 buffer.Write(queued->contents(), queued->size());
205 }
206
207 delete queued;
208 } while (_bufferQueue.Dequeue(queued));
209
210 if (buffer.GetActiveSize() > 0)
211 QueuePacket(std::move(buffer));
212 }
213
214 if (!BaseSocket::Update())
215 return false;
216
218
219 return true;
220}
void ProcessReadyCallbacks()
Definition AsyncCallbackProcessor.h:40
void EncryptSend(uint8 *data, std::size_t len)
Definition AuthCrypt.cpp:44
bool empty() const
Definition ByteBuffer.h:445
uint8 * contents()
Definition ByteBuffer.h:424
void CompressIfNeeded()
Definition WorldSocket.cpp:97
bool NeedsEncryption() const
Definition WorldSocket.h:40
virtual bool Update()
Definition Socket.h:70
void QueuePacket(MessageBuffer &&buffer)
Definition Socket.h:142
Definition ServerPktHeader.h:26

References _authCrypt, _bufferQueue, _queryProcessor, _sendBufferSize, EncryptableAndCompressiblePacket::CompressIfNeeded(), ByteBuffer::contents(), ByteBuffer::empty(), AuthCrypt::EncryptSend(), MessageBuffer::GetActiveSize(), ServerPktHeader::getHeaderLength(), WorldPacket::GetOpcode(), MessageBuffer::GetRemainingSpace(), ServerPktHeader::header, EncryptableAndCompressiblePacket::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

◆ _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

The documentation for this class was generated from the following files: