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

#include "WorldSocket.h"

Inheritance diagram for WorldSocket:
Socket< WorldSocket >

Public Member Functions

 WorldSocket (IoContextTcpSocket &&socket)
 
 ~WorldSocket ()
 
 WorldSocket (WorldSocket const &right)=delete
 
WorldSocket & operator= (WorldSocket const &right)=delete
 
void Start () override
 
bool Update () final
 
void SendPacket (WorldPacket const &packet)
 
void SetSendBufferSize (std::size_t sendBufferSize)
 
bool IsLoggingPackets () const
 
void SetPacketLogging (bool state)
 
- Public Member Functions inherited from Socket< WorldSocket >
 Socket (IoContextTcpSocket &&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.
 
MessageBuffer & GetReadBuffer ()
 

Protected Types

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

Protected Member Functions

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

Private Types

typedef Socket< WorldSocket > BaseSocket
 

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< ClientAuthSession > 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
 
bool _loggingPackets
 

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 ( IoContextTcpSocket &&  socket)
122 : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096), _loggingPackets(false)
123{
126}
void Resize(size_type bytes)
Definition MessageBuffer.h:52
Definition Socket.h:68
MessageBuffer _headerBuffer
Definition WorldSocket.h:132
bool _authed
Definition WorldSocket.h:130
std::size_t _sendBufferSize
Definition WorldSocket.h:135
uint32 _OverSpeedPings
Definition WorldSocket.h:126
WorldSession * _worldSession
Definition WorldSocket.h:129
std::array< uint8, 4 > _authSeed
Definition WorldSocket.h:122
bool _loggingPackets
Definition WorldSocket.h:140
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
141{
142 if (result)
143 {
144 bool banned = false;
145 do
146 {
147 Field* fields = result->Fetch();
148 if (fields[0].Get<uint64>() != 0)
149 banned = true;
150
151 } while (result->NextRow());
152
153 if (banned)
154 {
156 LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP {} banned).", GetRemoteIpAddress().to_string());
158 return;
159 }
160 }
161
162 AsyncRead();
164}
#define LOG_ERROR(filterType__,...)
Definition Log.h:145
@ AUTH_REJECT
Definition SharedDefines.h:3586
Class used to access individual fields of database query result.
Definition Field.h:99
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:194
boost::asio::ip::address GetRemoteIpAddress() const
Definition Socket.h:107
void AsyncRead()
Definition Socket.h:117
void HandleSendAuthSession()
Definition WorldSocket.cpp:224
void SendAuthResponseError(uint8 code)
Definition WorldSocket.cpp:732

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

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

Referenced by HandleAuthSession().

◆ HandlePing()

bool WorldSocket::HandlePing ( WorldPacket &  recvPacket)
private
741{
742 using namespace std::chrono;
743
744 uint32 ping;
745 uint32 latency;
746
747 // Get the ping packet content
748 recvPacket >> ping;
749 recvPacket >> latency;
750
751 if (_LastPingTime == steady_clock::time_point())
752 {
753 _LastPingTime = steady_clock::now();
754 }
755 else
756 {
757 steady_clock::time_point now = steady_clock::now();
758 steady_clock::duration diff = now - _LastPingTime;
759
760 _LastPingTime = now;
761
762 if (diff < seconds(27))
763 {
765
766 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
767
768 if (maxAllowed && _OverSpeedPings > maxAllowed)
769 {
770 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
771
773 {
774 LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
776
777 return false;
778 }
779 }
780 }
781 else
782 {
783 _OverSpeedPings = 0;
784 }
785 }
786
787 {
788 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
789
790 if (_worldSession)
791 _worldSession->SetLatency(latency);
792 else
793 {
794 LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress().to_string());
795 return false;
796 }
797 }
798
799 WorldPacket packet(SMSG_PONG, 4);
800 packet << ping;
802
803 return true;
804}
std::uint32_t uint32
Definition Define.h:107
@ CONFIG_MAX_OVERSPEED_PINGS
Definition WorldConfig.h:233
Definition WorldPacket.h:26
std::string GetPlayerInfo() const
Definition WorldSession.cpp:272
bool HasPermission(uint32 permissionId)
Definition WorldSession.cpp:1691
void SetLatency(uint32 latency)
Definition WorldSession.h:652
TimePoint _LastPingTime
Definition WorldSocket.h:125
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition WorldSocket.cpp:514
std::mutex _worldSessionLock
Definition WorldSocket.h:128
@ SMSG_PONG
Definition Opcodes.h:507
@ RBAC_PERM_SKIP_CHECK_OVERSPEED_PING
Definition RBAC.h:74

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

Referenced by ReadDataHandler().

◆ HandleSendAuthSession()

void WorldSocket::HandleSendAuthSession ( )
private
225{
227 packet << uint32(1); // 1...31
228 packet.append(_authSeed);
229
230 packet.append(Acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
231
233}
@ SMSG_AUTH_CHALLENGE
Definition Opcodes.h:522

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

Referenced by CheckIpCallback().

◆ IsLoggingPackets()

bool WorldSocket::IsLoggingPackets ( ) const
inline
88{ return _loggingPackets; }

Referenced by ReadDataHandler(), and SendPacket().

◆ 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

502{
503 if (!guard)
504 {
505 LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(opcode));
506 }
507 else
508 {
509 LOG_TRACE("network.opcode", "C->S: {} {}", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()),
511 }
512}
#define LOG_TRACE(filterType__,...)
Definition Log.h:161
std::string GetOpcodeNameForLogging(Opcodes opcode)
Lookup opcode name for human understandable logging.
Definition Opcodes.cpp:1470

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

Referenced by ReadDataHandler().

◆ OnClose()

void WorldSocket::OnClose ( )
overrideprotectedvirtual

Reimplemented from Socket< WorldSocket >.

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

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
404{
405 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
406 OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
407
408 WorldPacket packet(opcode, std::move(_packetBuffer));
409 WorldPacket* packetToQueue;
410
411 if (sPacketLog->CanLogPacket() && IsLoggingPackets())
413
414 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
415
416 switch (opcode)
417 {
418 case CMSG_PING:
419 {
420 LogOpcodeText(opcode, sessionGuard);
421 try
422 {
424 }
425 catch (ByteBufferException const&)
426 {
427 }
428 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
430 }
432 {
433 LogOpcodeText(opcode, sessionGuard);
434 if (_authed)
435 {
436 // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
437 if (sessionGuard.try_lock())
438 LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
440 }
441
442 try
443 {
444 HandleAuthSession(packet);
446 }
447 catch (ByteBufferException const&) { }
448
449 LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string());
451 }
452 case CMSG_KEEP_ALIVE:
453 sessionGuard.lock();
454 LogOpcodeText(opcode, sessionGuard);
455 if (_worldSession)
456 {
459 }
460 LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress().to_string());
463 packetToQueue = new WorldPacket(std::move(packet), GameTime::Now());
464 break;
465 default:
466 packetToQueue = new WorldPacket(std::move(packet));
467 break;
468 }
469
470 sessionGuard.lock();
471
472 LogOpcodeText(opcode, sessionGuard);
473
474 if (!_worldSession)
475 {
476 LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = {}", uint32(opcode));
477 delete packetToQueue;
479 }
480
481 OpcodeHandler const* handler = opcodeTable[opcode];
482 if (!handler)
483 {
484 LOG_ERROR("network.opcode", "No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packetToQueue->GetOpcode())), _worldSession->GetPlayerInfo());
485 delete packetToQueue;
487 }
488
489 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
490 if (packetToQueue->GetOpcode() != CMSG_WARDEN_DATA)
491 {
493 }
494
495 // Copy the packet to the heap before enqueuing
496 _worldSession->QueuePacket(packetToQueue);
497
499}
#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:1377
uint16 GetRemotePort() const
Definition Socket.h:112
uint16 GetOpcode() const
Definition WorldPacket.h:75
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
Definition WorldSession.cpp:360
void ResetTimeOutTime(bool onlyActive)
Definition WorldSession.h:662
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
Definition WorldSocket.cpp:501
void HandleAuthSession(WorldPacket &recvPacket)
Definition WorldSocket.cpp:531
bool HandlePing(WorldPacket &recvPacket)
Definition WorldSocket.cpp:740
MessageBuffer _packetBuffer
Definition WorldSocket.h:133
bool IsLoggingPackets() const
Definition WorldSocket.h:88
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(), IsLoggingPackets(), LOG_ERROR, LogOpcodeText(), GameTime::Now(), Ok, opcodeTable, WorldSession::QueuePacket(), WorldSession::ResetTimeOutTime(), sPacketLog, and WaitingForQuery.

Referenced by ReadHandler().

◆ ReadHandler()

SocketReadCallbackResult WorldSocket::ReadHandler ( )
finalprotectedvirtual

Implements Socket< WorldSocket >.

244{
245 if (!IsOpen())
247
248 MessageBuffer& packet = GetReadBuffer();
249 while (packet.GetActiveSize() > 0)
250 {
252 {
253 // need to receive the header
254 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
255 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
256 packet.ReadCompleted(readHeaderSize);
257
259 {
260 // Couldn't receive the whole header this time.
261 ASSERT(packet.GetActiveSize() == 0);
262 break;
263 }
264
265 // We just received nice new header
266 if (!ReadHeaderHandler())
267 {
268 CloseSocket();
270 }
271 }
272
273 // We have full read header, now check the data payload
275 {
276 // need more data in the payload
277 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
278 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
279 packet.ReadCompleted(readDataSize);
280
282 {
283 // Couldn't receive the whole data this time.
284 ASSERT(packet.GetActiveSize() == 0);
285 break;
286 }
287 }
288
289 // just received fresh new payload
292
293 if (result != ReadDataHandlerResult::Ok)
294 {
296 {
297 CloseSocket();
298 }
299
301 }
302 }
303
305}
#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:200
bool IsOpen() const
Definition Socket.h:170
void CloseSocket()
Definition Socket.h:172
bool ReadHeaderHandler()
Definition WorldSocket.cpp:307
ReadDataHandlerResult
Definition WorldSocket.h:97
ReadDataHandlerResult ReadDataHandler()
Definition WorldSocket.cpp:403

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

◆ ReadHeaderHandler()

bool WorldSocket::ReadHeaderHandler ( )
protected
308{
310
312 {
314 }
315
316 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
317 EndianConvertReverse(header->size);
318 EndianConvert(header->cmd);
319
320 if (!header->IsValidSize() || !header->IsValidOpcode())
321 {
322 LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
323 GetRemoteIpAddress().to_string(), header->size, header->cmd);
324
325 return false;
326 }
327
328 header->size -= sizeof(header->cmd);
329 _packetBuffer.Resize(header->size);
330
331 return true;
332}
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
733{
735 packet << uint8(code);
736
738}
@ 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)
521{
522 if (!IsOpen())
523 return;
524
525 if (sPacketLog->CanLogPacket() && IsLoggingPackets())
527
529}
@ SERVER_TO_CLIENT
Definition PacketLog.h:28
Definition WorldSocket.h:33
MPSCQueue< EncryptableAndCompressiblePacket, &EncryptableAndCompressiblePacket::SocketQueueLink > _bufferQueue
Definition WorldSocket.h:134

References _authCrypt, _bufferQueue, Socket< WorldSocket >::GetRemoteIpAddress(), Socket< WorldSocket >::GetRemotePort(), AuthCrypt::IsInitialized(), IsLoggingPackets(), 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

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

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

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

◆ SetPacketLogging()

void WorldSocket::SetPacketLogging ( bool  state)
inline
89{ _loggingPackets = state; }

◆ SetSendBufferSize()

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

◆ Start()

void WorldSocket::Start ( )
overridevirtual

Implements Socket< WorldSocket >.

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

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

◆ Update()

bool WorldSocket::Update ( )
finalvirtual

Reimplemented from Socket< WorldSocket >.

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

◆ _loggingPackets

bool WorldSocket::_loggingPackets
private

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