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:158
@ AUTH_REJECT
Definition SharedDefines.h:3592
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:726

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
530{
531 std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();
532
533 // Read the content of the packet
534 recvPacket >> authSession->Build;
535 recvPacket >> authSession->LoginServerID;
536 recvPacket >> authSession->Account;
537 recvPacket >> authSession->LoginServerType;
538 recvPacket.read(authSession->LocalChallenge);
539 recvPacket >> authSession->RegionID;
540 recvPacket >> authSession->BattlegroupID;
541 recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table
542 recvPacket >> authSession->DosResponse;
543 recvPacket.read(authSession->Digest);
544 authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos());
545 recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want
546
547 // Get the account information from the auth database
549 stmt->SetData(0, int32(realm.Id.Realm));
550 stmt->SetData(1, authSession->Account);
551
552 _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)));
553}
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:555
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.

556{
557 // Stop if the account is not found
558 if (!result)
559 {
560 // We can not log here, as we do not know the account. Thus, no accountId.
562 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
564 return;
565 }
566
567 AccountInfo account(result->Fetch());
568
569 // For hook purposes, we get Remoteaddress at this point.
570 std::string address = sConfigMgr->GetOption<bool>("AllowLoggingIPAddressesInDatabase", true, true) ? GetRemoteIpAddress().to_string() : "0.0.0.0";
571
572 LoginDatabasePreparedStatement* stmt = nullptr;
573
574 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
575 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
576 stmt->SetData(0, address);
577 stmt->SetData(1, authSession->Account);
578 LoginDatabase.Execute(stmt);
579 // This also allows to check for possible "hack" attempts on account
580
581 // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
582 _authCrypt.Init(account.SessionKey);
583
584 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
585 if (sWorld->IsClosed())
586 {
588 LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", GetRemoteIpAddress().to_string());
590 return;
591 }
592
593 if (authSession->RealmID != realm.Id.Realm)
594 {
596 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
597 GetRemoteIpAddress().to_string(), authSession->RealmID, realm.Id.Realm);
599 return;
600 }
601
602 // Must be done before WorldSession is created
603 bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
604 if (wardenActive && account.OS != "Win" && account.OS != "OSX")
605 {
607 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
609 return;
610 }
611
612 // Check that Key and account name are the same on client and server
613 uint8 t[4] = { 0x00,0x00,0x00,0x00 };
614
616 sha.UpdateData(authSession->Account);
617 sha.UpdateData(t);
618 sha.UpdateData(authSession->LocalChallenge);
620 sha.UpdateData(account.SessionKey);
621 sha.Finalize();
622
623 if (sha.GetDigest() != authSession->Digest)
624 {
626 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Id, authSession->Account, address);
628 return;
629 }
630
631 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
632 _ipCountry = location->CountryCode;
633
635 if (account.IsLockedToIP)
636 {
637 if (account.LastIP != address)
638 {
640 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.LastIP, address);
641 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
642 sScriptMgr->OnFailedAccountLogin(account.Id);
644 return;
645 }
646 }
647 else if (!account.LockCountry.empty() && account.LockCountry != "00" && !_ipCountry.empty())
648 {
649 if (account.LockCountry != _ipCountry)
650 {
652 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.LockCountry, _ipCountry);
653 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
654 sScriptMgr->OnFailedAccountLogin(account.Id);
656 return;
657 }
658 }
659
661 if (account.MuteTime < 0)
662 {
663 account.MuteTime = GameTime::GetGameTime().count() + std::llabs(account.MuteTime);
664
665 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
666 stmt->SetData(0, account.MuteTime);
667 stmt->SetData(1, account.Id);
668 LoginDatabase.Execute(stmt);
669 }
670
671 if (account.IsBanned)
672 {
674 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
675 sScriptMgr->OnFailedAccountLogin(account.Id);
677 return;
678 }
679
680 // Check locked state for server
681 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
682 LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Security);
683 if (allowedAccountType > SEC_PLAYER && account.Security < allowedAccountType)
684 {
686 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
687 sScriptMgr->OnFailedAccountLogin(account.Id);
689 return;
690 }
691
692 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->Account, address);
693
694 // Update the last_ip in the database as it was successful for login
695 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
696 stmt->SetData(0, address);
697 stmt->SetData(1, authSession->Account);
698
699 LoginDatabase.Execute(stmt);
700
701 // At this point, we can safely hook a successful login
702 sScriptMgr->OnAccountLogin(account.Id);
703
704 _authed = true;
705
706 sScriptMgr->OnLastIpUpdate(account.Id, address);
707
708 _worldSession = new WorldSession(account.Id, std::move(authSession->Account), account.Flags, shared_from_this(), account.Security,
709 account.Expansion, account.MuteTime, account.Locale, account.Recruiter, account.IsRectuiter, account.Security ? true : false, account.TotalTime);
710
711 _worldSession->ReadAddonsInfo(authSession->AddonInfo);
712
713 // Initialize Warden system only if it is enabled by config
714 if (wardenActive)
715 {
716 _worldSession->InitWarden(account.SessionKey, account.OS);
717 }
718
720
721 sWorldSessionMgr->AddSession(_worldSession);
722
723 AsyncRead();
724}
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
#define LOG_DEBUG(filterType__,...)
Definition Log.h:170
@ 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:3618
@ AUTH_FAILED
Definition SharedDefines.h:3591
@ AUTH_UNKNOWN_ACCOUNT
Definition SharedDefines.h:3599
@ AUTH_BANNED
Definition SharedDefines.h:3606
@ AUTH_UNAVAILABLE
Definition SharedDefines.h:3594
@ CONFIG_WARDEN_ENABLED
Definition WorldConfig.h:106
#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:1150
void ValidateAccountFlags()
Definition WorldSession.cpp:195
void InitWarden(SessionKey const &, std::string const &os)
Definition WorldSession.cpp:1333
std::string _ipCountry
Definition WorldSocket.h:135
AuthCrypt _authCrypt
Definition WorldSocket.h:120
#define sWorld
Definition World.h:320
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(), AccountInfo::Flags, 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, Acore::Impl::GenericHash< HashCreator, DigestLength >::UpdateData(), and WorldSession::ValidateAccountFlags().

Referenced by HandleAuthSession().

◆ HandlePing()

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

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

500{
501 if (!guard)
502 {
503 LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(opcode));
504 }
505 else
506 {
507 LOG_TRACE("network.opcode", "C->S: {} {}", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()),
509 }
510}
#define LOG_TRACE(filterType__,...)
Definition Log.h:174
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
402{
403 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
404 OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
405
406 WorldPacket packet(opcode, std::move(_packetBuffer));
407 WorldPacket* packetToQueue;
408
409 if (sPacketLog->CanLogPacket())
411
412 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
413
414 switch (opcode)
415 {
416 case CMSG_PING:
417 {
418 LogOpcodeText(opcode, sessionGuard);
419 try
420 {
422 }
423 catch (ByteBufferException const&)
424 {
425 }
426 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
428 }
430 {
431 LogOpcodeText(opcode, sessionGuard);
432 if (_authed)
433 {
434 // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
435 if (sessionGuard.try_lock())
436 LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
438 }
439
440 try
441 {
442 HandleAuthSession(packet);
444 }
445 catch (ByteBufferException const&) { }
446
447 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string());
449 }
450 case CMSG_KEEP_ALIVE:
451 sessionGuard.lock();
452 LogOpcodeText(opcode, sessionGuard);
453 if (_worldSession)
454 {
457 }
458 LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress().to_string());
461 packetToQueue = new WorldPacket(std::move(packet), GameTime::Now());
462 break;
463 default:
464 packetToQueue = new WorldPacket(std::move(packet));
465 break;
466 }
467
468 sessionGuard.lock();
469
470 LogOpcodeText(opcode, sessionGuard);
471
472 if (!_worldSession)
473 {
474 LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = {}", uint32(opcode));
475 delete packetToQueue;
477 }
478
479 OpcodeHandler const* handler = opcodeTable[opcode];
480 if (!handler)
481 {
482 LOG_ERROR("network.opcode", "No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packetToQueue->GetOpcode())), _worldSession->GetPlayerInfo());
483 delete packetToQueue;
485 }
486
487 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
488 if (packetToQueue->GetOpcode() != CMSG_WARDEN_DATA)
489 {
491 }
492
493 // Copy the packet to the heap before enqueuing
494 _worldSession->QueuePacket(packetToQueue);
495
497}
#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:301
void ResetTimeOutTime(bool onlyActive)
Definition WorldSession.h:532
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
Definition WorldSocket.cpp:499
void HandleAuthSession(WorldPacket &recvPacket)
Definition WorldSocket.cpp:529
bool HandlePing(WorldPacket &recvPacket)
Definition WorldSocket.cpp:734
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:401

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
727{
729 packet << uint8(code);
730
732}
@ 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)
519{
520 if (!IsOpen())
521 return;
522
523 if (sPacketLog->CanLogPacket())
525
527}
@ 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

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

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: