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
 
WorldSocketoperator= (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.
 
MessageBufferGetReadBuffer ()
 

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< 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< 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:98
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:743
@ 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:76
@ CONFIG_WARDEN_ENABLED
Definition WorldConfig.h:108
#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:409
void ReadAddonsInfo(ByteBuffer &data)
Definition WorldSession.cpp:1230
void ValidateAccountFlags()
Definition WorldSession.cpp:205
void InitWarden(SessionKey const &, std::string const &os)
Definition WorldSession.cpp:1413
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:267
bool HasPermission(uint32 permissionId)
Definition WorldSession.cpp:1671
void SetLatency(uint32 latency)
Definition WorldSession.h:628
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:353
void ResetTimeOutTime(bool onlyActive)
Definition WorldSession.h:638
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: