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

#include "WorldSocket.h"

Inheritance diagram for WorldSocket:
Socket< WorldSocket >

Public Member Functions

 WorldSocket (tcp::socket &&socket)
 
 ~WorldSocket ()
 
 WorldSocket (WorldSocket const &right)=delete
 
WorldSocketoperator= (WorldSocket const &right)=delete
 
void Start () override
 
bool Update () override
 
void SendPacket (WorldPacket const &packet)
 
void SetSendBufferSize (std::size_t sendBufferSize)
 
- Public Member Functions inherited from Socket< WorldSocket >
 Socket (tcp::socket &&socket)
 
virtual ~Socket ()
 
virtual void Start ()=0
 
virtual bool Update ()
 
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. More...
 
MessageBufferGetReadBuffer ()
 

Protected Types

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

Protected Member Functions

void OnClose () override
 
void ReadHandler () override
 
bool ReadHeaderHandler ()
 
ReadDataHandlerResult ReadDataHandler ()
 
- Protected Member Functions inherited from Socket< WorldSocket >
virtual void OnClose ()
 
virtual void ReadHandler ()=0
 
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 More...
 
void HandleSendAuthSession ()
 
void HandleAuthSession (WorldPacket &recvPacket)
 
void HandleAuthSessionCallback (std::shared_ptr< AuthSession > authSession, PreparedQueryResult result)
 
void LoadSessionPermissionsCallback (PreparedQueryResult result)
 
void SendAuthResponseError (uint8 code)
 
bool HandlePing (WorldPacket &recvPacket)
 

Private Attributes

std::array< uint8, 4 > _authSeed
 
AuthCrypt _authCrypt
 
TimePoint _LastPingTime
 
uint32 _OverSpeedPings
 
std::mutex _worldSessionLock
 
WorldSession_worldSession
 
bool _authed
 
MessageBuffer _headerBuffer
 
MessageBuffer _packetBuffer
 
MPSCQueue< EncryptableAndCompressiblePacket, &EncryptableAndCompressiblePacket::SocketQueueLink_bufferQueue
 
std::size_t _sendBufferSize
 
QueryCallbackProcessor _queryProcessor
 
std::string _ipCountry
 

Detailed Description

Member Typedef Documentation

◆ BaseSocket

Member Enumeration Documentation

◆ ReadDataHandlerResult

enum class WorldSocket::ReadDataHandlerResult
strongprotected
Enumerator
Ok 
Error 
WaitingForQuery 

Constructor & Destructor Documentation

◆ WorldSocket() [1/2]

WorldSocket::WorldSocket ( tcp::socket &&  socket)
117 : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
118{
121}
std::array< uint8, S > GetRandomBytes()
Definition: CryptoRandom.h:35
void Resize(size_type bytes)
Definition: MessageBuffer.h:52
Definition: WorldSocket.h:60
MessageBuffer _headerBuffer
Definition: WorldSocket.h:130
bool _authed
Definition: WorldSocket.h:128
std::size_t _sendBufferSize
Definition: WorldSocket.h:133
uint32 _OverSpeedPings
Definition: WorldSocket.h:124
WorldSession * _worldSession
Definition: WorldSocket.h:127
std::array< uint8, 4 > _authSeed
Definition: WorldSocket.h:120
Definition: Socket.h:52

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

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

References _queryProcessor, AsyncCallbackProcessor< T >::AddCallback(), HandleAuthSessionCallback(), Realm::Id, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, LoginDatabase, ByteBuffer::read(), realm, RealmHandle::Realm, ByteBuffer::rpos(), PreparedStatementBase::SetData(), and ByteBuffer::size().

Referenced by ReadDataHandler().

◆ HandleAuthSessionCallback()

void WorldSocket::HandleAuthSessionCallback ( std::shared_ptr< AuthSession authSession,
PreparedQueryResult  result 
)
private
  • Re-check ip locking (same check as in auth).

Negative mutetime indicates amount of minutes to be muted effective on next login - which is now.

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

References _authCrypt, _authed, _authSeed, _ipCountry, _worldSession, Socket< WorldSocket >::AsyncRead(), AUTH_BANNED, AUTH_FAILED, AUTH_REJECT, AUTH_UNAVAILABLE, AUTH_UNKNOWN_ACCOUNT, CONFIG_WARDEN_ENABLED, Socket< WorldSocket >::DelayedCloseSocket(), AccountInfo::Expansion, Acore::Impl::GenericHash< HashCreator, DigestLength >::Finalize(), Acore::Impl::GenericHash< HashCreator, DigestLength >::GetDigest(), GameTime::GetGameTime(), Socket< WorldSocket >::GetRemoteIpAddress(), AccountInfo::Id, Realm::Id, AuthCrypt::Init(), WorldSession::InitWarden(), AccountInfo::IsBanned, AccountInfo::IsLockedToIP, AccountInfo::IsRectuiter, AccountInfo::LastIP, AccountInfo::Locale, AccountInfo::LockCountry, LOG_DEBUG, LOG_ERROR, LOGIN_UPD_LAST_ATTEMPT_IP, LOGIN_UPD_LAST_IP, LOGIN_UPD_MUTE_TIME_LOGIN, LoginDatabase, AccountInfo::MuteTime, AccountInfo::OS, WorldSession::ReadAddonsInfo(), realm, RealmHandle::Realm, REALM_LIST_REALM_NOT_FOUND, AccountInfo::Recruiter, sConfigMgr, SEC_PLAYER, AccountInfo::Security, SendAuthResponseError(), AccountInfo::SessionKey, PreparedStatementBase::SetData(), sIPLocation, sScriptMgr, sWorld, AccountInfo::TotalTime, and Acore::Impl::GenericHash< HashCreator, DigestLength >::UpdateData().

Referenced by HandleAuthSession().

◆ HandlePing()

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

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

Referenced by ReadDataHandler().

◆ HandleSendAuthSession()

void WorldSocket::HandleSendAuthSession ( )
private
220{
222 packet << uint32(1); // 1...31
223 packet.append(_authSeed);
224
225 packet.append(Acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
226
228}
@ SMSG_AUTH_CHALLENGE
Definition: Opcodes.h:522

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

Referenced by CheckIpCallback().

◆ LoadSessionPermissionsCallback()

void WorldSocket::LoadSessionPermissionsCallback ( PreparedQueryResult  result)
private

◆ LogOpcodeText()

void WorldSocket::LogOpcodeText ( OpcodeClient  opcode,
std::unique_lock< std::mutex > const &  guard 
) const
private

writes network.opcode log accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock

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

231{
232 {
233 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
234 _worldSession = nullptr;
235 }
236}

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

References _authed, _headerBuffer, _packetBuffer, _worldSession, _worldSessionLock, CLIENT_TO_SERVER, ClientPktHeader::cmd, CMSG_AUTH_SESSION, CMSG_KEEP_ALIVE, CMSG_PING, CMSG_TIME_SYNC_RESP, CMSG_WARDEN_DATA, Error, WorldPacket::GetOpcode(), GetOpcodeNameForLogging(), WorldSession::GetPlayerInfo(), MessageBuffer::GetReadPointer(), Socket< WorldSocket >::GetRemoteIpAddress(), Socket< WorldSocket >::GetRemotePort(), HandleAuthSession(), HandlePing(), LOG_ERROR, LogOpcodeText(), GameTime::Now(), Ok, opcodeTable, WorldSession::QueuePacket(), WorldSession::ResetTimeOutTime(), sPacketLog, and WaitingForQuery.

Referenced by ReadHandler().

◆ ReadHandler()

void WorldSocket::ReadHandler ( )
overrideprotectedvirtual

Implements Socket< WorldSocket >.

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

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

◆ ReadHeaderHandler()

bool WorldSocket::ReadHeaderHandler ( )
protected
303{
305
307 {
309 }
310
311 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
312 EndianConvertReverse(header->size);
313 EndianConvert(header->cmd);
314
315 if (!header->IsValidSize() || !header->IsValidOpcode())
316 {
317 LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
318 GetRemoteIpAddress().to_string(), header->size, header->cmd);
319
320 return false;
321 }
322
323 header->size -= sizeof(header->cmd);
324 _packetBuffer.Resize(header->size);
325
326 return true;
327}
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:61
bool IsValidSize() const
Definition: WorldSocket.h:64
bool IsValidOpcode() const
Definition: WorldSocket.h:65

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
720{
722 packet << uint8(code);
723
725}
@ 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)
514{
515 if (!IsOpen())
516 return;
517
518 if (sPacketLog->CanLogPacket())
520
522}
@ SERVER_TO_CLIENT
Definition: PacketLog.h:28
Definition: WorldSocket.h:34
MPSCQueue< EncryptableAndCompressiblePacket, &EncryptableAndCompressiblePacket::SocketQueueLink > _bufferQueue
Definition: WorldSocket.h:132

References _authCrypt, _bufferQueue, Socket< WorldSocket >::GetRemoteIpAddress(), Socket< WorldSocket >::GetRemotePort(), AuthCrypt::IsInitialized(), Socket< WorldSocket >::IsOpen(), SERVER_TO_CLIENT, and sPacketLog.

Referenced by SendPacketAndLogOpcode().

◆ SendPacketAndLogOpcode()

void WorldSocket::SendPacketAndLogOpcode ( WorldPacket const &  packet)
private

sends and logs network.opcode without accessing WorldSession

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

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

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

◆ SetSendBufferSize()

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

◆ Start()

void WorldSocket::Start ( )
overridevirtual

Implements Socket< WorldSocket >.

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

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

◆ Update()

bool WorldSocket::Update ( )
overridevirtual

Reimplemented from Socket< WorldSocket >.

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

References _authCrypt, _bufferQueue, _queryProcessor, _sendBufferSize, EncryptableAndCompressiblePacket::CompressIfNeeded(), ByteBuffer::contents(), ByteBuffer::empty(), AuthCrypt::EncryptSend(), MessageBuffer::GetActiveSize(), ServerPktHeader::getHeaderLength(), WorldPacket::GetOpcode(), MessageBuffer::GetRemainingSpace(), ServerPktHeader::header, EncryptableAndCompressiblePacket::NeedsEncryption(), AsyncCallbackProcessor< T >::ProcessReadyCallbacks(), Socket< WorldSocket >::QueuePacket(), MessageBuffer::Resize(), ByteBuffer::size(), Socket< WorldSocket >::Update(), and MessageBuffer::Write().

Member Data Documentation

◆ _authCrypt

AuthCrypt WorldSocket::_authCrypt
private

◆ _authed

bool WorldSocket::_authed
private

◆ _authSeed

std::array<uint8, 4> WorldSocket::_authSeed
private

◆ _bufferQueue

◆ _headerBuffer

MessageBuffer WorldSocket::_headerBuffer
private

◆ _ipCountry

std::string WorldSocket::_ipCountry
private

◆ _LastPingTime

TimePoint WorldSocket::_LastPingTime
private

Referenced by HandlePing().

◆ _OverSpeedPings

uint32 WorldSocket::_OverSpeedPings
private

Referenced by HandlePing().

◆ _packetBuffer

MessageBuffer WorldSocket::_packetBuffer
private

◆ _queryProcessor

QueryCallbackProcessor WorldSocket::_queryProcessor
private

Referenced by HandleAuthSession(), Start(), and Update().

◆ _sendBufferSize

std::size_t WorldSocket::_sendBufferSize
private

Referenced by Update().

◆ _worldSession

WorldSession* WorldSocket::_worldSession
private

◆ _worldSessionLock

std::mutex WorldSocket::_worldSessionLock
private