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)
121 : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096), _loggingPackets(false)
122{
125}
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
140{
141 if (result)
142 {
143 bool banned = false;
144 do
145 {
146 Field* fields = result->Fetch();
147 if (fields[0].Get<uint64>() != 0)
148 banned = true;
149
150 } while (result->NextRow());
151
152 if (banned)
153 {
155 LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP {} banned).", GetRemoteIpAddress().to_string());
157 return;
158 }
159 }
160
161 AsyncRead();
163}
#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:223
void SendAuthResponseError(uint8 code)
Definition WorldSocket.cpp:727

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

557{
558 // Stop if the account is not found
559 if (!result)
560 {
561 // We can not log here, as we do not know the account. Thus, no accountId.
563 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
565 return;
566 }
567
568 AccountInfo account(result->Fetch());
569
570 // For hook purposes, we get Remoteaddress at this point.
571 std::string address = sConfigMgr->GetOption<bool>("AllowLoggingIPAddressesInDatabase", true, true) ? GetRemoteIpAddress().to_string() : "0.0.0.0";
572
573 LoginDatabasePreparedStatement* stmt = nullptr;
574
575 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
576 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
577 stmt->SetData(0, address);
578 stmt->SetData(1, authSession->Account);
579 LoginDatabase.Execute(stmt);
580 // This also allows to check for possible "hack" attempts on account
581
582 // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
583 _authCrypt.Init(account.SessionKey);
584
585 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
586 if (sWorld->IsClosed())
587 {
589 LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", GetRemoteIpAddress().to_string());
591 return;
592 }
593
594 if (authSession->RealmID != realm.Id.Realm)
595 {
597 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
598 GetRemoteIpAddress().to_string(), authSession->RealmID, realm.Id.Realm);
600 return;
601 }
602
603 // Must be done before WorldSession is created
604 bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
605 if (wardenActive && account.OS != "Win" && account.OS != "OSX")
606 {
608 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
610 return;
611 }
612
613 // Check that Key and account name are the same on client and server
614 uint8 t[4] = { 0x00,0x00,0x00,0x00 };
615
617 sha.UpdateData(authSession->Account);
618 sha.UpdateData(t);
619 sha.UpdateData(authSession->LocalChallenge);
621 sha.UpdateData(account.SessionKey);
622 sha.Finalize();
623
624 if (sha.GetDigest() != authSession->Digest)
625 {
627 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Id, authSession->Account, address);
629 return;
630 }
631
632 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
633 _ipCountry = location->CountryCode;
634
636 if (account.IsLockedToIP)
637 {
638 if (account.LastIP != address)
639 {
641 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.LastIP, address);
642 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
643 sScriptMgr->OnFailedAccountLogin(account.Id);
645 return;
646 }
647 }
648 else if (!account.LockCountry.empty() && account.LockCountry != "00" && !_ipCountry.empty())
649 {
650 if (account.LockCountry != _ipCountry)
651 {
653 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.LockCountry, _ipCountry);
654 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
655 sScriptMgr->OnFailedAccountLogin(account.Id);
657 return;
658 }
659 }
660
662 if (account.MuteTime < 0)
663 {
664 account.MuteTime = GameTime::GetGameTime().count() + std::llabs(account.MuteTime);
665
666 auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
667 stmt->SetData(0, account.MuteTime);
668 stmt->SetData(1, account.Id);
669 LoginDatabase.Execute(stmt);
670 }
671
672 if (account.IsBanned)
673 {
675 LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
676 sScriptMgr->OnFailedAccountLogin(account.Id);
678 return;
679 }
680
681 // Check locked state for server
682 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
683 LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Security);
684 if (allowedAccountType > SEC_PLAYER && account.Security < allowedAccountType)
685 {
687 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
688 sScriptMgr->OnFailedAccountLogin(account.Id);
690 return;
691 }
692
693 LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->Account, address);
694
695 // Update the last_ip in the database as it was successful for login
696 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
697 stmt->SetData(0, address);
698 stmt->SetData(1, authSession->Account);
699
700 LoginDatabase.Execute(stmt);
701
702 // At this point, we can safely hook a successful login
703 sScriptMgr->OnAccountLogin(account.Id);
704
705 _authed = true;
706
707 sScriptMgr->OnLastIpUpdate(account.Id, address);
708
709 _worldSession = new WorldSession(account.Id, std::move(authSession->Account), account.Flags, shared_from_this(), account.Security,
710 account.Expansion, account.MuteTime, account.Locale, account.Recruiter, account.IsRectuiter, account.Security ? true : false, account.TotalTime);
711
712 _worldSession->ReadAddonsInfo(authSession->AddonInfo);
713
714 // Initialize Warden system only if it is enabled by config
715 if (wardenActive)
716 {
717 _worldSession->InitWarden(account.SessionKey, account.OS);
718 }
719
721
722 sWorldSessionMgr->AddSession(_worldSession);
723
724 AsyncRead();
725}
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:736
@ 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
@ CONFIG_WARDEN_ENABLED
Definition WorldConfig.h:110
#define sWorldSessionMgr
Definition WorldSessionMgr.h:108
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:384
void ReadAddonsInfo(ByteBuffer &data)
Definition WorldSession.cpp:1158
void ValidateAccountFlags()
Definition WorldSession.cpp:200
void InitWarden(SessionKey const &, std::string const &os)
Definition WorldSession.cpp:1341
std::string _ipCountry
Definition WorldSocket.h:138
AuthCrypt _authCrypt
Definition WorldSocket.h:123
#define sConfigMgr
Definition Config.h:93
#define sWorld
Definition World.h:317
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
736{
737 using namespace std::chrono;
738
739 uint32 ping;
740 uint32 latency;
741
742 // Get the ping packet content
743 recvPacket >> ping;
744 recvPacket >> latency;
745
746 if (_LastPingTime == steady_clock::time_point())
747 {
748 _LastPingTime = steady_clock::now();
749 }
750 else
751 {
752 steady_clock::time_point now = steady_clock::now();
753 steady_clock::duration diff = now - _LastPingTime;
754
755 _LastPingTime = now;
756
757 if (diff < seconds(27))
758 {
760
761 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
762
763 if (maxAllowed && _OverSpeedPings > maxAllowed)
764 {
765 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
766
768 {
769 LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
771
772 return false;
773 }
774 }
775 }
776 else
777 {
778 _OverSpeedPings = 0;
779 }
780 }
781
782 {
783 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
784
785 if (_worldSession)
786 _worldSession->SetLatency(latency);
787 else
788 {
789 LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress().to_string());
790 return false;
791 }
792 }
793
794 WorldPacket packet(SMSG_PONG, 4);
795 packet << ping;
797
798 return true;
799}
std::uint32_t uint32
Definition Define.h:107
@ CONFIG_MAX_OVERSPEED_PINGS
Definition WorldConfig.h:232
Definition WorldPacket.h:26
std::string GetPlayerInfo() const
Definition WorldSession.cpp:251
bool HasPermission(uint32 permissionId)
Definition WorldSession.cpp:1551
void SetLatency(uint32 latency)
Definition WorldSession.h:594
TimePoint _LastPingTime
Definition WorldSocket.h:125
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition WorldSocket.cpp:513
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
224{
226 packet << uint32(1); // 1...31
227 packet.append(_authSeed);
228
229 packet.append(Acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
230
232}
@ 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

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

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

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

243{
244 if (!IsOpen())
246
247 MessageBuffer& packet = GetReadBuffer();
248 while (packet.GetActiveSize() > 0)
249 {
251 {
252 // need to receive the header
253 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
254 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
255 packet.ReadCompleted(readHeaderSize);
256
258 {
259 // Couldn't receive the whole header this time.
260 ASSERT(packet.GetActiveSize() == 0);
261 break;
262 }
263
264 // We just received nice new header
265 if (!ReadHeaderHandler())
266 {
267 CloseSocket();
269 }
270 }
271
272 // We have full read header, now check the data payload
274 {
275 // need more data in the payload
276 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
277 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
278 packet.ReadCompleted(readDataSize);
279
281 {
282 // Couldn't receive the whole data this time.
283 ASSERT(packet.GetActiveSize() == 0);
284 break;
285 }
286 }
287
288 // just received fresh new payload
291
292 if (result != ReadDataHandlerResult::Ok)
293 {
295 {
296 CloseSocket();
297 }
298
300 }
301 }
302
304}
#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:306
ReadDataHandlerResult
Definition WorldSocket.h:97
ReadDataHandlerResult ReadDataHandler()
Definition WorldSocket.cpp:402

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
307{
309
311 {
313 }
314
315 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
316 EndianConvertReverse(header->size);
317 EndianConvert(header->cmd);
318
319 if (!header->IsValidSize() || !header->IsValidOpcode())
320 {
321 LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
322 GetRemoteIpAddress().to_string(), header->size, header->cmd);
323
324 return false;
325 }
326
327 header->size -= sizeof(header->cmd);
328 _packetBuffer.Resize(header->size);
329
330 return true;
331}
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
728{
730 packet << uint8(code);
731
733}
@ 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)
520{
521 if (!IsOpen())
522 return;
523
524 if (sPacketLog->CanLogPacket() && IsLoggingPackets())
526
528}
@ 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

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

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

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

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

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