TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
WorldSocket Class Reference

#include <WorldSocket.h>

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)
 
ConnectionType GetConnectionType () const
 
void SendAuthResponseError (uint32 code)
 
void SetWorldSession (WorldSession *session)
 
- Public Member Functions inherited from Socket< WorldSocket >
 Socket (tcp::socket &&socket)
 
virtual ~Socket ()
 
boost::asio::ip::address GetRemoteIpAddress () const
 
uint16 GetRemotePort () const
 
void AsyncRead ()
 
void AsyncReadWithCallback (void(WorldSocket::*callback)(boost::system::error_code, std::size_t))
 
void QueuePacket (MessageBuffer &&buffer)
 
bool IsOpen () const
 
void CloseSocket ()
 
void DelayedCloseSocket ()
 Marks the socket for closing after write buffer becomes empty. More...
 
MessageBufferGetReadBuffer ()
 

Protected Types

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

Protected Member Functions

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

Private Types

typedef Socket< WorldSocketBaseSocket
 

Private Member Functions

void CheckIpCallback (PreparedQueryResult result)
 
void InitializeHandler (boost::system::error_code error, std::size_t transferedBytes)
 
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 WritePacketToBuffer (EncryptablePacket const &packet, MessageBuffer &buffer)
 
uint32 CompressPacket (uint8 *buffer, WorldPacket const &packet)
 
void HandleSendAuthSession ()
 
void HandleAuthSession (std::shared_ptr< WorldPackets::Auth::AuthSession > authSession)
 
void HandleAuthSessionCallback (std::shared_ptr< WorldPackets::Auth::AuthSession > authSession, PreparedQueryResult result)
 
void HandleAuthContinuedSession (std::shared_ptr< WorldPackets::Auth::AuthContinuedSession > authSession)
 
void HandleAuthContinuedSessionCallback (std::shared_ptr< WorldPackets::Auth::AuthContinuedSession > authSession, PreparedQueryResult result)
 
void LoadSessionPermissionsCallback (PreparedQueryResult result)
 
void HandleConnectToFailed (WorldPackets::Auth::ConnectToFailed &connectToFailed)
 
bool HandlePing (WorldPacket &recvPacket)
 
void ExtractOpcodeAndSize (ClientPktHeader const *header, uint32 &opcode, uint32 &size) const
 

Private Attributes

ConnectionType _type
 
BigNumber _serverChallenge
 
WorldPacketCrypt _authCrypt
 
BigNumber _encryptSeed
 
BigNumber _decryptSeed
 
std::chrono::steady_clock::time_point _LastPingTime
 
uint32 _OverSpeedPings
 
std::mutex _worldSessionLock
 
WorldSession_worldSession
 
bool _authed
 
MessageBuffer _headerBuffer
 
MessageBuffer _packetBuffer
 
MPSCQueue< EncryptablePacket_bufferQueue
 
z_stream_s_compressionStream
 
PreparedQueryResultFuture _queryFuture
 
std::function< void(PreparedQueryResult &&)> _queryCallback
 
std::string _ipCountry
 

Static Private Attributes

static uint32 const ConnectionInitializeMagic = 0xF5EB1CE
 
static std::string const ServerConnectionInitialize
 
static std::string const ClientConnectionInitialize
 
static uint32 const MinSizeForCompression = 0x400
 
static uint8 const AuthCheckSeed [16] = { 0xC5, 0xC6, 0x98, 0x95, 0x76, 0x3F, 0x1D, 0xCD, 0xB6, 0xA1, 0x37, 0x28, 0xB3, 0x12, 0xFF, 0x8A }
 
static uint8 const SessionKeySeed [16] = { 0x58, 0xCB, 0xCF, 0x40, 0xFE, 0x2E, 0xCE, 0xA6, 0x5A, 0x90, 0xB8, 0x01, 0x68, 0x6C, 0x28, 0x0B }
 
static uint8 const ContinuedSessionSeed [16] = { 0x16, 0xAD, 0x0C, 0xD4, 0x46, 0xF9, 0x4F, 0xB2, 0xEF, 0x7D, 0xEA, 0x2A, 0x17, 0x66, 0x4D, 0x2F }
 

Member Typedef Documentation

Member Enumeration Documentation

enum WorldSocket::ReadDataHandlerResult
strongprotected
Enumerator
Ok 
Error 
WaitingForQuery 
106  {
107  Ok = 0,
108  Error = 1,
109  WaitingForQuery = 2
110  };
void Error(char const *file, int line, char const *function, char const *message)
Definition: Errors.cpp:77

Constructor & Destructor Documentation

WorldSocket::WorldSocket ( tcp::socket &&  socket)
71  : Socket(std::move(socket)),
73  _worldSession(nullptr), _authed(false), _compressionStream(nullptr)
74 {
75  _serverChallenge.SetRand(8 * 16);
77 }
Socket(tcp::socket &&socket)
Definition: Socket.h:68
uint32 const SizeOfClientHeader[2]
Definition: WorldSocket.cpp:64
BigNumber _serverChallenge
Definition: WorldSocket.h:139
WorldSession * _worldSession
Definition: WorldSocket.h:148
uint32 _OverSpeedPings
Definition: WorldSocket.h:145
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
void SetRand(int32 numbits)
Definition: BigNumber.cpp:74
bool _authed
Definition: WorldSocket.h:149
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
z_stream_s * _compressionStream
Definition: WorldSocket.h:155
Definition: Opcodes.h:31
ConnectionType _type
Definition: WorldSocket.h:137

+ Here is the call graph for this function:

WorldSocket::~WorldSocket ( )
80 {
82  {
83  deflateEnd(_compressionStream);
84  delete _compressionStream;
85  }
86 }
z_stream_s * _compressionStream
Definition: WorldSocket.h:155
WorldSocket::WorldSocket ( WorldSocket const right)
delete

Member Function Documentation

void WorldSocket::CheckIpCallback ( PreparedQueryResult  result)
private
100 {
101  if (result)
102  {
103  bool banned = false;
104  do
105  {
106  Field* fields = result->Fetch();
107  if (fields[0].GetUInt64() != 0)
108  banned = true;
109 
110  if (!fields[1].GetString().empty())
111  _ipCountry = fields[1].GetString();
112 
113  } while (result->NextRow());
114 
115  if (banned)
116  {
117  TC_LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP %s banned).", GetRemoteIpAddress().to_string().c_str());
119  return;
120  }
121  }
122 
124 
126 
127  MessageBuffer initializer;
128  ServerPktHeader header;
129  header.Setup.Size = ServerConnectionInitialize.size();
131  initializer.Write(&header, sizeof(header.Setup.Size));
132  initializer.Write(ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length());
133 
134  // - io_service.run thread, safe.
135  QueuePacket(std::move(initializer));
136 }
void InitializeHandler(boost::system::error_code error, std::size_t transferedBytes)
Definition: WorldSocket.cpp:138
void AsyncReadWithCallback(void(WorldSocket::*callback)(boost::system::error_code, std::size_t))
Definition: Socket.h:120
Class used to access individual fields of database query result.
Definition: Field.h:56
static std::string const ClientConnectionInitialize
Definition: WorldSocket.h:74
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
MessageBuffer _packetBuffer
Definition: WorldSocket.h:152
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition: Socket.h:157
Definition: ServerPktHeader.h:24
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
static std::string const ServerConnectionInitialize
Definition: WorldSocket.h:73
void QueuePacket(MessageBuffer &&buffer)
Definition: Socket.h:131
uint16 Size
Definition: ServerPktHeader.h:28
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
struct ServerPktHeader::@317 Setup
std::string _ipCountry
Definition: WorldSocket.h:159
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
std::string GetString() const
Definition: Field.h:276
Definition: MessageBuffer.h:24
static uint32 const ConnectionInitializeMagic
Definition: WorldSocket.h:72

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

uint32 WorldSocket::CompressPacket ( uint8 buffer,
WorldPacket const packet 
)
private
564 {
565  uint32 opcode = packet.GetOpcode();
566  uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(uint16));
567 
568  _compressionStream->next_out = buffer;
570  _compressionStream->next_in = (Bytef*)&opcode;
572 
573  int32 z_res = deflate(_compressionStream, Z_NO_FLUSH);
574  if (z_res != Z_OK)
575  {
576  TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
577  return 0;
578  }
579 
580  _compressionStream->next_in = (Bytef*)packet.contents();
581  _compressionStream->avail_in = packet.size();
582 
583  z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
584  if (z_res != Z_OK)
585  {
586  TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg);
587  return 0;
588  }
589 
590  return bufferSize - _compressionStream->avail_out;
591 }
const size_t bufferSize
Definition: RASession.h:31
#define Z_NO_FLUSH
Definition: zlib.h:164
uInt avail_in
Definition: zlib.h:87
Byte FAR Bytef
Definition: zconf.h:377
uint16_t uint16
Definition: g3dmath.h:166
z_const char * msg
Definition: zlib.h:94
Bytef * next_out
Definition: zlib.h:90
int32_t int32
Definition: Define.h:146
uint32_t uint32
Definition: Define.h:150
z_stream_s * _compressionStream
Definition: WorldSocket.h:155
uInt avail_out
Definition: zlib.h:91
z_const Bytef * next_in
Definition: zlib.h:86
#define Z_OK
Definition: zlib.h:173
#define Z_SYNC_FLUSH
Definition: zlib.h:166
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::ExtractOpcodeAndSize ( ClientPktHeader const header,
uint32 opcode,
uint32 size 
) const
private
332 {
334  {
335  opcode = header->Normal.Command;
336  size = header->Normal.Size - 2;
337  }
338  else
339  {
340  opcode = header->Setup.Command;
341  size = header->Setup.Size - 2;
342  }
343 }
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
bool IsInitialized() const
Definition: PacketCrypt.h:35

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

ConnectionType WorldSocket::GetConnectionType ( ) const
inline
95 { return _type; }
ConnectionType _type
Definition: WorldSocket.h:137

+ Here is the caller graph for this function:

void WorldSocket::HandleAuthContinuedSession ( std::shared_ptr< WorldPackets::Auth::AuthContinuedSession authSession)
private
849 {
851  key.Raw = authSession->Key;
852 
855  {
858  return;
859  }
860 
861  // Client switches packet headers after sending CMSG_AUTH_CONTINUED_SESSION
863 
864  uint32 accountId = uint32(key.Fields.AccountId);
866  stmt->setUInt32(0, accountId);
867 
868  _queryCallback = std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1);
870 }
void SendAuthResponseError(uint32 code)
Definition: WorldSocket.cpp:948
uint32 const SizeOfClientHeader[2]
Definition: WorldSocket.cpp:64
std::function< void(PreparedQueryResult &&)> _queryCallback
Definition: WorldSocket.h:158
uint64 ConnectionType
Definition: WorldSession.h:1717
QueryResultFuture AsyncQuery(const char *sql)
Definition: DatabaseWorkerPool.cpp:149
uint64 AccountId
Definition: WorldSession.h:1716
Definition: PreparedStatement.h:74
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
void HandleAuthContinuedSessionCallback(std::shared_ptr< WorldPackets::Auth::AuthContinuedSession > authSession, PreparedQueryResult result)
Definition: WorldSocket.cpp:872
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition: Socket.h:157
uint64 Raw
Definition: WorldSession.h:1721
uint32_t uint32
Definition: Define.h:150
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
Definition: Opcodes.h:32
void setUInt32(const uint8 index, const uint32 value)
Definition: PreparedStatement.cpp:115
struct WorldSession::ConnectToKey::@321 Fields
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
Definition: BattlenetRpcErrorCodes.h:28
uint32_t uint32
Definition: g3dmath.h:168
Definition: WorldSession.h:1712
PreparedQueryResultFuture _queryFuture
Definition: WorldSocket.h:157
ConnectionType _type
Definition: WorldSocket.h:137
Definition: LoginDatabase.h:41
ConnectionType
Definition: Opcodes.h:29

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::HandleAuthContinuedSessionCallback ( std::shared_ptr< WorldPackets::Auth::AuthContinuedSession authSession,
PreparedQueryResult  result 
)
private
873 {
874  if (!result)
875  {
878  return;
879  }
880 
882  key.Raw = authSession->Key;
883 
884  uint32 accountId = uint32(key.Fields.AccountId);
885  Field* fields = result->Fetch();
886  std::string login = fields[0].GetString();
887  BigNumber k;
888  k.SetHexStr(fields[1].GetCString());
889 
891 
892  HmacSha256 hmac(40, k.AsByteArray(40).get());
893  hmac.UpdateData(reinterpret_cast<uint8 const*>(&authSession->Key), sizeof(authSession->Key));
894  hmac.UpdateData(authSession->LocalChallenge.data(), authSession->LocalChallenge.size());
895  hmac.UpdateData(_serverChallenge.AsByteArray(16).get(), 16);
896  hmac.UpdateData(ContinuedSessionSeed, 16);
897  hmac.Finalize();
898 
899  if (memcmp(hmac.GetDigest(), authSession->Digest.data(), authSession->Digest.size()))
900  {
901  TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str());
903  return;
904  }
905 
906  sWorld->AddInstanceSocket(shared_from_this(), authSession->Key);
907  AsyncRead();
908 }
Definition: BigNumber.h:28
void SendAuthResponseError(uint32 code)
Definition: WorldSocket.cpp:948
void SetHexStr(char const *str)
Definition: BigNumber.cpp:69
BigNumber _serverChallenge
Definition: WorldSocket.h:139
BigNumber _decryptSeed
Definition: WorldSocket.h:142
Class used to access individual fields of database query result.
Definition: Field.h:56
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void Init(BigNumber *K) override
Definition: WorldPacketCrypt.cpp:29
#define sWorld
Definition: World.h:887
Definition: HmacHash.h:34
uint64 AccountId
Definition: WorldSession.h:1716
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition: Socket.h:157
uint64 Raw
Definition: WorldSession.h:1721
uint32_t uint32
Definition: Define.h:150
void UpdateData(std::string const &str)
Definition: HmacHash.cpp:38
static uint8 const ContinuedSessionSeed[16]
Definition: WorldSocket.h:79
struct WorldSession::ConnectToKey::@321 Fields
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
std::unique_ptr< uint8[]> AsByteArray(int32 minSize=0, bool littleEndian=true)
Definition: BigNumber.cpp:177
Definition: BattlenetRpcErrorCodes.h:28
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
uint32_t uint32
Definition: g3dmath.h:168
void AsyncRead()
Definition: Socket.h:109
Definition: WorldSession.h:1712
std::string GetString() const
Definition: Field.h:276
BigNumber _encryptSeed
Definition: WorldSocket.h:141

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::HandleAuthSession ( std::shared_ptr< WorldPackets::Auth::AuthSession authSession)
private
656 {
657  // Client switches packet headers after sending CMSG_AUTH_SESSION
659 
660  // Get the account information from the auth database
662  stmt->setInt32(0, int32(realm.Id.Realm));
663  stmt->setString(1, authSession->RealmJoinTicket);
664 
665  _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1);
667 }
uint32 Realm
Definition: Realm.h:53
uint32 const SizeOfClientHeader[2]
Definition: WorldSocket.cpp:64
void HandleAuthSessionCallback(std::shared_ptr< WorldPackets::Auth::AuthSession > authSession, PreparedQueryResult result)
Definition: WorldSocket.cpp:669
std::function< void(PreparedQueryResult &&)> _queryCallback
Definition: WorldSocket.h:158
Realm realm
Definition: World.cpp:3485
void setString(const uint8 index, const std::string &value)
Definition: PreparedStatement.cpp:187
Definition: LoginDatabase.h:46
QueryResultFuture AsyncQuery(const char *sql)
Definition: DatabaseWorkerPool.cpp:149
Definition: PreparedStatement.h:74
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
Battlenet::RealmHandle Id
Definition: Realm.h:86
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
void setInt32(const uint8 index, const int32 value)
Definition: PreparedStatement.cpp:151
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
int32_t int32
Definition: g3dmath.h:167
PreparedQueryResultFuture _queryFuture
Definition: WorldSocket.h:157

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

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

670 {
671  // Stop if the account is not found
672  if (!result)
673  {
674  // We can not log here, as we do not know the account. Thus, no accountId.
675  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
677  return;
678  }
679 
680  AccountInfo account(result->Fetch());
681 
682  // For hook purposes, we get Remoteaddress at this point.
683  std::string address = GetRemoteIpAddress().to_string();
684 
685  HmacSha256 hmac(SHA256_DIGEST_LENGTH, account.Game.SessionKey.AsByteArray(SHA256_DIGEST_LENGTH).get());
686  hmac.UpdateData(authSession->LocalChallenge.data(), authSession->LocalChallenge.size());
687  hmac.UpdateData(_serverChallenge.AsByteArray(16).get(), 16);
688  hmac.UpdateData(AuthCheckSeed, 16);
689  hmac.Finalize();
690 
691  // Check that Key and account name are the same on client and server
692  if (memcmp(hmac.GetDigest(), authSession->Digest.data(), authSession->Digest.size()) != 0)
693  {
694  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", account.Game.Id, authSession->RealmJoinTicket.c_str(), address.c_str());
696  return;
697  }
698 
699  HmacSha256 sessionKeyHmac(SHA256_DIGEST_LENGTH, account.Game.SessionKey.AsByteArray(SHA256_DIGEST_LENGTH).get());
700  sessionKeyHmac.UpdateData(_serverChallenge.AsByteArray(16).get(), 16);
701  sessionKeyHmac.UpdateData(authSession->LocalChallenge.data(), authSession->LocalChallenge.size());
702  sessionKeyHmac.UpdateData(SessionKeySeed, 16);
703  sessionKeyHmac.Finalize();
704 
705  uint8 sessionKey[40];
706  SessionKeyGenerator<SHA256Hash> sessionKeyGenerator(sessionKeyHmac.GetDigest(), sessionKeyHmac.GetLength());
707  sessionKeyGenerator.Generate(sessionKey, 40);
708 
709  BigNumber K;
710  K.SetBinary(sessionKey, 40);
711 
712  _authCrypt.Init(&K);
713 
714  // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
716  stmt->setString(0, address);
717  stmt->setString(1, authSession->RealmJoinTicket);
718  LoginDatabase.Execute(stmt);
719  // This also allows to check for possible "hack" attempts on account
720 
722  stmt->setString(0, K.AsHexStr());
723  stmt->setUInt32(1, account.Game.Id);
724  LoginDatabase.Execute(stmt);
725 
726  // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
727  if (sWorld->IsClosed())
728  {
730  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
732  return;
733  }
734 
735  if (authSession->RealmID != realm.Id.Realm)
736  {
738  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s requested connecting with realm id %u but this realm has id %u set in config.",
739  GetRemoteIpAddress().to_string().c_str(), authSession->RealmID, realm.Id.Realm);
741  return;
742  }
743 
744  // Must be done before WorldSession is created
745  bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
746  if (wardenActive && account.Game.OS != "Win" && account.Game.OS != "Wn64" && account.Game.OS != "Mc64")
747  {
749  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), account.Game.OS.c_str());
751  return;
752  }
753 
755  if (account.BattleNet.IsLockedToIP)
756  {
757  if (account.BattleNet.LastIP != address)
758  {
760  TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", account.BattleNet.LastIP.c_str(), address.c_str());
761  // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
762  sScriptMgr->OnFailedAccountLogin(account.Game.Id);
764  return;
765  }
766  }
767  else if (!account.BattleNet.LockCountry.empty() && account.BattleNet.LockCountry != "00" && !_ipCountry.empty())
768  {
769  if (account.BattleNet.LockCountry != _ipCountry)
770  {
772  TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: %s, new country: %s).", account.BattleNet.LockCountry.c_str(), _ipCountry.c_str());
773  // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
774  sScriptMgr->OnFailedAccountLogin(account.Game.Id);
776  return;
777  }
778  }
779 
780  int64 mutetime = account.Game.MuteTime;
782  if (mutetime < 0)
783  {
784  mutetime = time(NULL) + llabs(mutetime);
785 
787  stmt->setInt64(0, mutetime);
788  stmt->setUInt32(1, account.Game.Id);
789  LoginDatabase.Execute(stmt);
790  }
791 
792  if (account.IsBanned())
793  {
795  TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
796  sScriptMgr->OnFailedAccountLogin(account.Game.Id);
798  return;
799  }
800 
801  // Check locked state for server
802  AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
803  TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, account.Game.Security);
804  if (allowedAccountType > SEC_PLAYER && account.Game.Security < allowedAccountType)
805  {
807  TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
808  sScriptMgr->OnFailedAccountLogin(account.Game.Id);
810  return;
811  }
812 
813  TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", authSession->RealmJoinTicket.c_str(), address.c_str());
814 
815  // Update the last_ip in the database as it was successful for login
817 
818  stmt->setString(0, address);
819  stmt->setString(1, authSession->RealmJoinTicket);
820 
821  LoginDatabase.Execute(stmt);
822 
823  // At this point, we can safely hook a successful login
824  sScriptMgr->OnAccountLogin(account.Game.Id);
825 
826  _authed = true;
827  _worldSession = new WorldSession(account.Game.Id, std::move(authSession->RealmJoinTicket), account.BattleNet.Id, shared_from_this(), account.Game.Security,
828  account.Game.Expansion, mutetime, account.Game.OS, account.BattleNet.Locale, account.Game.Recruiter, account.Game.IsRectuiter);
829  _worldSession->ReadAddonsInfo(authSession->AddonInfo);
830 
831  // Initialize Warden system only if it is enabled by config
832  if (wardenActive)
833  _worldSession->InitWarden(&account.Game.SessionKey);
834 
835  _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1);
837  AsyncRead();
838 }
Definition: BigNumber.h:28
uint32 Realm
Definition: Realm.h:53
void Execute(const char *sql)
Definition: DatabaseWorkerPool.h:87
void SendAuthResponseError(uint32 code)
Definition: WorldSocket.cpp:948
Definition: WorldSocket.cpp:593
Definition: World.h:166
void Generate(uint8 *buf, uint32 sz)
Definition: SessionKeyGeneration.h:49
PreparedQueryResultFuture LoadPermissionsAsync()
Definition: WorldSession.cpp:1104
int64_t int64
Definition: Define.h:145
BigNumber _serverChallenge
Definition: WorldSocket.h:139
std::function< void(PreparedQueryResult &&)> _queryCallback
Definition: WorldSocket.h:158
Realm realm
Definition: World.cpp:3485
Definition: LoginDatabase.h:73
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void ReadAddonsInfo(ByteBuffer &data)
Definition: WorldSession.cpp:822
Definition: Common.h:108
void setString(const uint8 index, const std::string &value)
Definition: PreparedStatement.cpp:187
arena_t NULL
Definition: jemalloc_internal.h:624
Definition: SessionKeyGeneration.h:25
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:198
void Init(BigNumber *K) override
Definition: WorldPacketCrypt.cpp:29
void SetBinary(uint8 const *bytes, int32 len)
Definition: BigNumber.cpp:57
#define sWorld
Definition: World.h:887
Definition: HmacHash.h:34
WorldSession * _worldSession
Definition: WorldSocket.h:148
Definition: PreparedStatement.h:74
void LoadSessionPermissionsCallback(PreparedQueryResult result)
Definition: WorldSocket.cpp:840
Definition: LoginDatabase.h:40
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
static uint8 const AuthCheckSeed[16]
Definition: WorldSocket.h:77
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition: Socket.h:157
Battlenet::RealmHandle Id
Definition: Realm.h:86
std::string AsHexStr() const
Definition: BigNumber.cpp:198
AccountTypes
Definition: Common.h:106
void setInt64(const uint8 index, const int64 value)
Definition: PreparedStatement.cpp:160
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
void UpdateData(std::string const &str)
Definition: HmacHash.cpp:38
void setUInt32(const uint8 index, const uint32 value)
Definition: PreparedStatement.cpp:115
static uint8 const SessionKeySeed[16]
Definition: WorldSocket.h:78
Definition: LoginDatabase.h:71
bool _authed
Definition: WorldSocket.h:149
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
std::unique_ptr< uint8[]> AsByteArray(int32 minSize=0, bool littleEndian=true)
Definition: BigNumber.cpp:177
uint8_t uint8
Definition: Define.h:152
std::string _ipCountry
Definition: WorldSocket.h:159
void InitWarden(BigNumber *k)
Definition: WorldSession.cpp:1075
Definition: BattlenetRpcErrorCodes.h:28
#define sScriptMgr
Definition: ScriptMgr.h:837
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
Player session in the World.
Definition: WorldSession.h:882
void AsyncRead()
Definition: Socket.h:109
PreparedQueryResultFuture _queryFuture
Definition: WorldSocket.h:157
Definition: LoginDatabase.h:72
#define llabs
Definition: Common.h:79

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::HandleConnectToFailed ( WorldPackets::Auth::ConnectToFailed connectToFailed)
private
911 {
912  if (_worldSession)
913  {
915  {
916  switch (connectToFailed.Serial)
917  {
920  break;
923  break;
926  break;
929  break;
931  {
932  TC_LOG_ERROR("network", "%s failed to connect 5 times to world socket, aborting login", _worldSession->GetPlayerInfo().c_str());
934  break;
935  }
936  default:
937  return;
938  }
939  }
940  //else
941  //{
942  // transfer_aborted when/if we get map node redirection
943  // SendPacketAndLogOpcode(*WorldPackets::Auth::ResumeComms().Write());
944  //}
945  }
946 }
ConnectToSerial Serial
Definition: AuthenticationPackets.h:210
WorldSession * _worldSession
Definition: WorldSocket.h:148
void SendConnectToInstance(WorldPackets::Auth::ConnectToSerial serial)
Definition: WorldSession.cpp:705
std::string GetPlayerInfo() const
Definition: WorldSession.cpp:195
void AbortLogin(WorldPackets::Character::LoginFailureReason reason)
Definition: CharacterHandler.cpp:876
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
bool PlayerLoading() const
Definition: WorldSession.h:889

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool WorldSocket::HandlePing ( WorldPacket recvPacket)
private
956 {
957  using namespace std::chrono;
958 
959  uint32 ping;
960  uint32 latency;
961 
962  // Get the ping packet content
963  recvPacket >> ping;
964  recvPacket >> latency;
965 
966  if (_LastPingTime == steady_clock::time_point())
967  {
968  _LastPingTime = steady_clock::now();
969  }
970  else
971  {
972  steady_clock::time_point now = steady_clock::now();
973 
974  steady_clock::duration diff = now - _LastPingTime;
975 
976  _LastPingTime = now;
977 
978  if (diff < seconds(27))
979  {
980  ++_OverSpeedPings;
981 
982  uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
983 
984  if (maxAllowed && _OverSpeedPings > maxAllowed)
985  {
986  std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
987 
989  {
990  TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)",
991  _worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().to_string().c_str());
992 
993  return false;
994  }
995  }
996  }
997  else
998  _OverSpeedPings = 0;
999  }
1000 
1001  {
1002  std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
1003 
1004  if (_worldSession)
1005  {
1006  _worldSession->SetLatency(latency);
1008  }
1009  else
1010  {
1011  TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str());
1012  return false;
1013  }
1014  }
1015 
1016  WorldPacket packet(SMSG_PONG, 4);
1017  packet << ping;
1018  SendPacketAndLogOpcode(packet);
1019  return true;
1020 }
Definition: World.h:277
std::chrono::steady_clock::time_point _LastPingTime
Definition: WorldSocket.h:144
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
#define sWorld
Definition: World.h:887
float seconds()
Definition: units.h:97
WorldSession * _worldSession
Definition: WorldSocket.h:148
uint32 _OverSpeedPings
Definition: WorldSocket.h:145
std::mutex _worldSessionLock
Definition: WorldSocket.h:147
uint32_t uint32
Definition: Define.h:150
Definition: Opcodes.h:1381
void SetLatency(uint32 latency)
Definition: WorldSession.h:1064
void ResetClientTimeDelay()
Definition: WorldSession.h:1065
std::string GetPlayerInfo() const
Definition: WorldSession.cpp:195
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
bool HasPermission(uint32 permissionId)
Definition: WorldSession.cpp:1259
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition: WorldSocket.cpp:495
Definition: WorldPacket.h:26

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::HandleSendAuthSession ( )
private
249 {
250  _encryptSeed.SetRand(16 * 8);
251  _decryptSeed.SetRand(16 * 8);
252 
254  memcpy(challenge.Challenge.data(), _serverChallenge.AsByteArray(16).get(), 16);
255  memcpy(&challenge.DosChallenge[0], _encryptSeed.AsByteArray(16).get(), 16);
256  memcpy(&challenge.DosChallenge[4], _decryptSeed.AsByteArray(16).get(), 16);
257  challenge.DosZeroBits = 1;
258 
259  SendPacketAndLogOpcode(*challenge.Write());
260 }
BigNumber _serverChallenge
Definition: WorldSocket.h:139
BigNumber _decryptSeed
Definition: WorldSocket.h:142
uint32 DosChallenge[8]
Encryption seeds.
Definition: AuthenticationPackets.h:42
Definition: AuthenticationPackets.h:34
uint8 DosZeroBits
Definition: AuthenticationPackets.h:43
void SetRand(int32 numbits)
Definition: BigNumber.cpp:74
std::unique_ptr< uint8[]> AsByteArray(int32 minSize=0, bool littleEndian=true)
Definition: BigNumber.cpp:177
WorldPacket const * Write() override
Definition: AuthenticationPackets.cpp:21
std::array< uint8, 16 > Challenge
Definition: AuthenticationPackets.h:41
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition: WorldSocket.cpp:495
BigNumber _encryptSeed
Definition: WorldSocket.h:141

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::InitializeHandler ( boost::system::error_code  error,
std::size_t  transferedBytes 
)
private
139 {
140  if (error)
141  {
142  CloseSocket();
143  return;
144  }
145 
146  GetReadBuffer().WriteCompleted(transferedBytes);
147 
148  MessageBuffer& packet = GetReadBuffer();
149  if (packet.GetActiveSize() > 0)
150  {
152  {
153  // need to receive the header
154  std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
155  _packetBuffer.Write(packet.GetReadPointer(), readHeaderSize);
156  packet.ReadCompleted(readHeaderSize);
157 
159  {
160  // Couldn't receive the whole header this time.
161  ASSERT(packet.GetActiveSize() == 0);
163  return;
164  }
165 
166  uint32 magic;
167  uint16 length;
168  ByteBuffer buffer(std::move(_packetBuffer));
169 
170  buffer >> magic;
171  buffer >> length;
172  std::string initializer = buffer.ReadString(length);
173  if (magic != ConnectionInitializeMagic || initializer != ClientConnectionInitialize)
174  {
175  CloseSocket();
176  return;
177  }
178 
180  _compressionStream->zalloc = (alloc_func)NULL;
181  _compressionStream->zfree = (free_func)NULL;
186  if (z_res != Z_OK)
187  {
188  CloseSocket();
189  TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res));
190  return;
191  }
192 
195  AsyncRead();
196  return;
197  }
198  }
199 
201 }
Byte FAR * voidpf
Definition: zconf.h:390
#define deflateInit2(strm, level, method, windowBits, memLevel, strategy)
Definition: zlib.h:1651
Definition: ByteBuffer.h:70
void InitializeHandler(boost::system::error_code error, std::size_t transferedBytes)
Definition: WorldSocket.cpp:138
void AsyncReadWithCallback(void(WorldSocket::*callback)(boost::system::error_code, std::size_t))
Definition: Socket.h:120
size_type GetRemainingSpace() const
Definition: MessageBuffer.h:68
uInt avail_in
Definition: zlib.h:87
static std::string const ClientConnectionInitialize
Definition: WorldSocket.h:74
arena_t NULL
Definition: jemalloc_internal.h:624
#define sWorld
Definition: World.h:887
voidpf opaque
Definition: zlib.h:99
free_func zfree
Definition: zlib.h:98
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:64
T min(const T &x, const T &y)
Definition: g3dmath.h:305
#define Z_DEFLATED
Definition: zlib.h:205
MessageBuffer _packetBuffer
Definition: WorldSocket.h:152
void ReadCompleted(size_type bytes)
Definition: MessageBuffer.h:62
alloc_func zalloc
Definition: zlib.h:97
int32_t int32
Definition: Define.h:146
uint32_t uint32
Definition: Define.h:150
uint16_t uint16
Definition: Define.h:151
void HandleSendAuthSession()
Definition: WorldSocket.cpp:248
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
float length(float v)
Definition: vectorMath.h:208
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
void Reset()
Definition: MessageBuffer.h:45
z_stream_s * _compressionStream
Definition: WorldSocket.h:155
z_const Bytef * next_in
Definition: zlib.h:86
#define Z_OK
Definition: zlib.h:173
#define ASSERT
Definition: Errors.h:55
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
MessageBuffer & GetReadBuffer()
Definition: Socket.h:159
#define Z_DEFAULT_STRATEGY
Definition: zlib.h:196
struct z_stream_s z_stream
void AsyncRead()
Definition: Socket.h:109
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
void CloseSocket()
Definition: Socket.h:142
Definition: MessageBuffer.h:24
Definition: World.h:209
static uint32 const ConnectionInitializeMagic
Definition: WorldSocket.h:72

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::LoadSessionPermissionsCallback ( PreparedQueryResult  result)
private
841 {
842  // RBAC must be loaded before adding session to check for skip queue permission
844 
845  sWorld->AddSession(_worldSession);
846 }
void LoadFromDBCallback(PreparedQueryResult result)
Definition: RBAC.cpp:198
#define sWorld
Definition: World.h:887
WorldSession * _worldSession
Definition: WorldSocket.h:148
rbac::RBACData * GetRBACData()
Definition: WorldSession.cpp:1254

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

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

483 {
484  if (!guard)
485  {
486  TC_LOG_TRACE("network.opcode", "C->S: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(opcode).c_str());
487  }
488  else
489  {
490  TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(),
491  GetOpcodeNameForLogging(opcode).c_str());
492  }
493 }
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
std::string GetOpcodeNameForLogging(T id)
Lookup opcode name for human understandable logging (T = OpcodeClient|OpcodeServer) ...
Definition: Opcodes.h:1777
WorldSession * _worldSession
Definition: WorldSocket.h:148
#define TC_LOG_TRACE(filterType__,...)
Definition: Log.h:195
std::string GetPlayerInfo() const
Definition: WorldSession.cpp:195

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::OnClose ( )
overrideprotectedvirtual

Reimplemented from Socket< WorldSocket >.

263 {
264  {
265  std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
266  _worldSession = nullptr;
267  }
268 }
WorldSession * _worldSession
Definition: WorldSocket.h:148
std::mutex _worldSessionLock
Definition: WorldSocket.h:147
WorldSocket& WorldSocket::operator= ( WorldSocket const right)
delete
WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler ( )
protected
376 {
377  ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
378  uint32 cmd;
379  uint32 size;
380 
381  ExtractOpcodeAndSize(header, cmd, size);
382 
383  OpcodeClient opcode = static_cast<OpcodeClient>(cmd);
384 
385  WorldPacket packet(opcode, std::move(_packetBuffer), GetConnectionType());
386 
387  if (sPacketLog->CanLogPacket())
389 
390  std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
391 
392  switch (opcode)
393  {
394  case CMSG_PING:
395  LogOpcodeText(opcode, sessionGuard);
397  case CMSG_AUTH_SESSION:
398  {
399  LogOpcodeText(opcode, sessionGuard);
400  if (_authed)
401  {
402  // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
403  if (sessionGuard.try_lock())
404  TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
406  }
407 
408  std::shared_ptr<WorldPackets::Auth::AuthSession> authSession = std::make_shared<WorldPackets::Auth::AuthSession>(std::move(packet));
409  authSession->Read();
410  HandleAuthSession(authSession);
412  }
414  {
415  LogOpcodeText(opcode, sessionGuard);
416  if (_authed)
417  {
418  // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
419  if (sessionGuard.try_lock())
420  TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_CONTINUED_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
422  }
423 
424  std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet));
425  authSession->Read();
426  HandleAuthContinuedSession(authSession);
428  }
429  case CMSG_KEEP_ALIVE:
430  LogOpcodeText(opcode, sessionGuard);
431  break;
432  case CMSG_LOG_DISCONNECT:
433  LogOpcodeText(opcode, sessionGuard);
434  packet.rfinish(); // contains uint32 disconnectReason;
435  break;
436  case CMSG_ENABLE_NAGLE:
437  LogOpcodeText(opcode, sessionGuard);
438  SetNoDelay(false);
439  break;
441  {
442  sessionGuard.lock();
443 
444  LogOpcodeText(opcode, sessionGuard);
445  WorldPackets::Auth::ConnectToFailed connectToFailed(std::move(packet));
446  connectToFailed.Read();
447  HandleConnectToFailed(connectToFailed);
448  break;
449  }
450  default:
451  {
452  sessionGuard.lock();
453 
454  LogOpcodeText(opcode, sessionGuard);
455 
456  if (!_worldSession)
457  {
458  TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
460  }
461 
462  OpcodeHandler const* handler = opcodeTable[opcode];
463  if (!handler)
464  {
465  TC_LOG_ERROR("network.opcode", "No defined handler for opcode %s sent by %s", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet.GetOpcode())).c_str(), _worldSession->GetPlayerInfo().c_str());
466  break;
467  }
468 
469  // Our Idle timer will reset on any non PING opcodes.
470  // Catches people idling on the login screen and any lingering ingame connections.
472 
473  // Copy the packet to the heap before enqueuing
474  _worldSession->QueuePacket(new WorldPacket(std::move(packet)));
475  break;
476  }
477  }
478 
480 }
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
Definition: WorldSocket.cpp:482
OpcodeTable opcodeTable
Definition: Opcodes.cpp:49
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
Definition: WorldSession.cpp:303
Definition: Opcodes.h:260
Definition: Opcodes.h:74
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void HandleAuthContinuedSession(std::shared_ptr< WorldPackets::Auth::AuthContinuedSession > authSession)
Definition: WorldSocket.cpp:848
std::string GetOpcodeNameForLogging(T id)
Lookup opcode name for human understandable logging (T = OpcodeClient|OpcodeServer) ...
Definition: Opcodes.h:1777
void ResetTimeOutTime()
Definition: WorldSession.h:1074
void HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed &connectToFailed)
Definition: WorldSocket.cpp:910
WorldSession * _worldSession
Definition: WorldSocket.h:148
void ExtractOpcodeAndSize(ClientPktHeader const *header, uint32 &opcode, uint32 &size) const
Definition: WorldSocket.cpp:331
void HandleAuthSession(std::shared_ptr< WorldPackets::Auth::AuthSession > authSession)
Definition: WorldSocket.cpp:655
void SetNoDelay(bool enable)
Definition: Socket.h:185
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
MessageBuffer _packetBuffer
Definition: WorldSocket.h:152
Definition: Opcodes.h:508
std::mutex _worldSessionLock
Definition: WorldSocket.h:147
Definition: AuthenticationPackets.h:203
uint32_t uint32
Definition: Define.h:150
Definition: WorldSocket.h:50
uint16 GetRemotePort() const
Definition: Socket.h:104
bool _authed
Definition: WorldSocket.h:149
#define sPacketLog
Definition: PacketLog.h:54
Definition: PacketLog.h:29
ConnectionType GetConnectionType() const
Definition: WorldSocket.h:95
Definition: Opcodes.h:73
bool HandlePing(WorldPacket &recvPacket)
Definition: WorldSocket.cpp:955
std::string GetPlayerInfo() const
Definition: WorldSession.cpp:195
Definition: Opcodes.h:229
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
OpcodeClient
Definition: Opcodes.h:46
Definition: Opcodes.h:1698
uint32_t uint32
Definition: g3dmath.h:168
Definition: Opcodes.h:390
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
Definition: Opcodes.h:360
Definition: WorldPacket.h:26

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::ReadHandler ( )
overrideprotectedvirtual

Implements Socket< WorldSocket >.

271 {
272  if (!IsOpen())
273  return;
274 
275  MessageBuffer& packet = GetReadBuffer();
276  while (packet.GetActiveSize() > 0)
277  {
279  {
280  // need to receive the header
281  std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
282  _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
283  packet.ReadCompleted(readHeaderSize);
284 
286  {
287  // Couldn't receive the whole header this time.
288  ASSERT(packet.GetActiveSize() == 0);
289  break;
290  }
291 
292  // We just received nice new header
293  if (!ReadHeaderHandler())
294  {
295  CloseSocket();
296  return;
297  }
298  }
299 
300  // We have full read header, now check the data payload
302  {
303  // need more data in the payload
304  std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
305  _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
306  packet.ReadCompleted(readDataSize);
307 
309  {
310  // Couldn't receive the whole data this time.
311  ASSERT(packet.GetActiveSize() == 0);
312  break;
313  }
314  }
315 
316  // just received fresh new payload
319  if (result != ReadDataHandlerResult::Ok)
320  {
322  CloseSocket();
323 
324  return;
325  }
326  }
327 
328  AsyncRead();
329 }
size_type GetRemainingSpace() const
Definition: MessageBuffer.h:68
bool ReadHeaderHandler()
Definition: WorldSocket.cpp:352
T min(const T &x, const T &y)
Definition: g3dmath.h:305
bool IsOpen() const
Definition: Socket.h:140
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
MessageBuffer _packetBuffer
Definition: WorldSocket.h:152
void ReadCompleted(size_type bytes)
Definition: MessageBuffer.h:62
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
void Reset()
Definition: MessageBuffer.h:45
ReadDataHandlerResult ReadDataHandler()
Definition: WorldSocket.cpp:375
#define ASSERT
Definition: Errors.h:55
MessageBuffer & GetReadBuffer()
Definition: Socket.h:159
void AsyncRead()
Definition: Socket.h:109
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58
void CloseSocket()
Definition: Socket.h:142
Definition: MessageBuffer.h:24
ReadDataHandlerResult
Definition: WorldSocket.h:105

+ Here is the call graph for this function:

bool WorldSocket::ReadHeaderHandler ( )
protected
353 {
355 
357 
358  ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
359  uint32 opcode;
360  uint32 size;
361 
362  ExtractOpcodeAndSize(header, opcode, size);
363 
365  {
366  TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %u, cmd: %u)",
367  GetRemoteIpAddress().to_string().c_str(), size, opcode);
368  return false;
369  }
370 
371  _packetBuffer.Resize(size);
372  return true;
373 }
uint32 const SizeOfClientHeader[2]
Definition: WorldSocket.cpp:64
#define SZFMTD
Definition: Define.h:143
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void DecryptRecv(uint8 *data, size_t length)
Definition: PacketCrypt.cpp:25
void ExtractOpcodeAndSize(ClientPktHeader const *header, uint32 &opcode, uint32 &size) const
Definition: WorldSocket.cpp:331
static bool IsValidSize(uint32 size)
Definition: WorldSocket.h:64
MessageBuffer _headerBuffer
Definition: WorldSocket.h:151
MessageBuffer _packetBuffer
Definition: WorldSocket.h:152
uint32_t uint32
Definition: Define.h:150
Definition: WorldSocket.h:50
static bool IsValidOpcode(uint32 opcode)
Definition: WorldSocket.h:65
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
#define ASSERT
Definition: Errors.h:55
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:207
bool IsInitialized() const
Definition: PacketCrypt.h:35
uint8 * GetReadPointer()
Definition: MessageBuffer.h:58

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::SendAuthResponseError ( uint32  code)
949 {
951  response.Result = code;
952  SendPacketAndLogOpcode(*response.Write());
953 }
Definition: AuthenticationPackets.h:72
uint32 Result
the result of the authentication process, possible values are BattlenetRpcErrorCode ...
Definition: AuthenticationPackets.h:131
Definition: inftrees.h:24
WorldPacket const * Write() override
Definition: AuthenticationPackets.cpp:63
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
Definition: WorldSocket.cpp:495

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::SendPacket ( WorldPacket const packet)
502 {
503  if (!IsOpen())
504  return;
505 
506  if (sPacketLog->CanLogPacket())
508 
510 }
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
Definition: WorldSocket.cpp:44
void Enqueue(T *input)
Definition: MPSCQueue.h:46
bool IsOpen() const
Definition: Socket.h:140
Definition: PacketLog.h:30
uint16 GetRemotePort() const
Definition: Socket.h:104
#define sPacketLog
Definition: PacketLog.h:54
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
ConnectionType GetConnectionType() const
Definition: WorldSocket.h:95
MPSCQueue< EncryptablePacket > _bufferQueue
Definition: WorldSocket.h:153
bool IsInitialized() const
Definition: PacketCrypt.h:35

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::SendPacketAndLogOpcode ( WorldPacket const packet)
private

sends and logs network.opcode without accessing WorldSession

496 {
497  TC_LOG_TRACE("network.opcode", "S->C: %s %s", GetRemoteIpAddress().to_string().c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str());
498  SendPacket(packet);
499 }
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
std::string GetOpcodeNameForLogging(T id)
Lookup opcode name for human understandable logging (T = OpcodeClient|OpcodeServer) ...
Definition: Opcodes.h:1777
#define TC_LOG_TRACE(filterType__,...)
Definition: Log.h:195
void SendPacket(WorldPacket const &packet)
Definition: WorldSocket.cpp:501

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WorldSocket::SetWorldSession ( WorldSession session)
346 {
347  std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
348  _worldSession = session;
349  _authed = true;
350 }
WorldSession * _worldSession
Definition: WorldSocket.h:148
std::mutex _worldSessionLock
Definition: WorldSocket.h:147
bool _authed
Definition: WorldSocket.h:149
void WorldSocket::Start ( )
overridevirtual

Implements Socket< WorldSocket >.

89 {
90  std::string ip_address = GetRemoteIpAddress().to_string();
92  stmt->setString(0, ip_address);
93  stmt->setUInt32(1, inet_addr(ip_address.c_str()));
94 
95  _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1);
97 }
std::function< void(PreparedQueryResult &&)> _queryCallback
Definition: WorldSocket.h:158
void CheckIpCallback(PreparedQueryResult result)
Definition: WorldSocket.cpp:99
boost::asio::ip::address GetRemoteIpAddress() const
Definition: Socket.h:99
void setString(const uint8 index, const std::string &value)
Definition: PreparedStatement.cpp:187
QueryResultFuture AsyncQuery(const char *sql)
Definition: DatabaseWorkerPool.cpp:149
Definition: PreparedStatement.h:74
LoginDatabaseWorkerPool LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
PreparedStatement * GetPreparedStatement(PreparedStatementIndex index)
Definition: DatabaseWorkerPool.h:263
void setUInt32(const uint8 index, const uint32 value)
Definition: PreparedStatement.cpp:115
PreparedQueryResultFuture _queryFuture
Definition: WorldSocket.h:157
Definition: LoginDatabase.h:35

+ Here is the call graph for this function:

bool WorldSocket::Update ( )
overridevirtual

Reimplemented from Socket< WorldSocket >.

204 {
205  EncryptablePacket* queued;
206  MessageBuffer buffer;
207  while (_bufferQueue.Dequeue(queued))
208  {
209  uint32 sizeOfHeader = SizeOfServerHeader[queued->NeedsEncryption()];
210  uint32 packetSize = queued->size();
211  if (packetSize > MinSizeForCompression && queued->NeedsEncryption())
212  packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket);
213 
214  if (buffer.GetRemainingSpace() < packetSize + sizeOfHeader)
215  {
216  QueuePacket(std::move(buffer));
217  buffer.Resize(4096);
218  }
219 
220  if (buffer.GetRemainingSpace() >= packetSize + sizeOfHeader)
221  WritePacketToBuffer(*queued, buffer);
222  else // single packet larger than 4096 bytes
223  {
224  MessageBuffer packetBuffer(packetSize + sizeOfHeader);
225  WritePacketToBuffer(*queued, packetBuffer);
226  QueuePacket(std::move(packetBuffer));
227  }
228 
229  delete queued;
230  }
231 
232  if (buffer.GetActiveSize() > 0)
233  QueuePacket(std::move(buffer));
234 
235  if (!BaseSocket::Update())
236  return false;
237 
238  if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
239  {
240  auto callback = _queryCallback;
241  _queryCallback = nullptr;
242  callback(_queryFuture.get());
243  }
244 
245  return true;
246 }
bool Dequeue(T *&result)
Definition: MPSCQueue.h:53
Definition: WorldSocket.cpp:37
size_type GetRemainingSpace() const
Definition: MessageBuffer.h:68
std::function< void(PreparedQueryResult &&)> _queryCallback
Definition: WorldSocket.h:158
void WritePacketToBuffer(EncryptablePacket const &packet, MessageBuffer &buffer)
Definition: WorldSocket.cpp:512
virtual bool Update()
Definition: Socket.h:83
Definition: WorldSocket.cpp:44
float seconds()
Definition: units.h:97
bool NeedsEncryption() const
Definition: WorldSocket.cpp:49
uint32 const SizeOfServerHeader[2]
Definition: WorldSocket.cpp:65
size_t size() const
Definition: ByteBuffer.h:587
uint32_t uint32
Definition: Define.h:150
void QueuePacket(MessageBuffer &&buffer)
Definition: Socket.h:131
size_type GetActiveSize() const
Definition: MessageBuffer.h:66
static uint32 const MinSizeForCompression
Definition: WorldSocket.h:75
void Resize(size_type bytes)
Definition: MessageBuffer.h:51
MPSCQueue< EncryptablePacket > _bufferQueue
Definition: WorldSocket.h:153
PreparedQueryResultFuture _queryFuture
Definition: WorldSocket.h:157
Definition: MessageBuffer.h:24

+ Here is the call graph for this function:

void WorldSocket::WritePacketToBuffer ( EncryptablePacket const packet,
MessageBuffer buffer 
)
private
513 {
514  ServerPktHeader header;
515  uint32 sizeOfHeader = SizeOfServerHeader[packet.NeedsEncryption()];
516  uint32 opcode = packet.GetOpcode();
517  uint32 packetSize = packet.size();
518 
519  // Reserve space for buffer
520  uint8* headerPos = buffer.GetWritePointer();
521  buffer.WriteCompleted(sizeOfHeader);
522 
523  if (packetSize > MinSizeForCompression && packet.NeedsEncryption())
524  {
526  cmp.UncompressedSize = packetSize + 2;
527  cmp.UncompressedAdler = adler32(adler32(0x9827D8F1, (Bytef*)&opcode, 2), packet.contents(), packetSize);
528 
529  // Reserve space for compression info - uncompressed size and checksums
530  uint8* compressionInfo = buffer.GetWritePointer();
531  buffer.WriteCompleted(sizeof(CompressedWorldPacket));
532 
533  uint32 compressedSize = CompressPacket(buffer.GetWritePointer(), packet);
534 
535  cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize);
536 
537  memcpy(compressionInfo, &cmp, sizeof(CompressedWorldPacket));
538  buffer.WriteCompleted(compressedSize);
539  packetSize = compressedSize + sizeof(CompressedWorldPacket);
540 
541  opcode = SMSG_COMPRESSED_PACKET;
542  }
543  else if (!packet.empty())
544  buffer.Write(packet.contents(), packet.size());
545 
546  packetSize += 2 /*opcode*/;
547 
548  if (packet.NeedsEncryption())
549  {
550  header.Normal.Size = packetSize;
551  header.Normal.Command = opcode;
552  _authCrypt.EncryptSend((uint8*)&header, 4);
553  }
554  else
555  {
556  header.Setup.Size = packetSize;
557  header.Setup.Command = opcode;
558  }
559 
560  memcpy(headerPos, &header, sizeOfHeader);
561 }
uint32 UncompressedAdler
Definition: WorldSocket.cpp:40
Definition: WorldSocket.cpp:37
uint32 CompressedAdler
Definition: WorldSocket.cpp:41
uint32 UncompressedSize
Definition: WorldSocket.cpp:39
Byte FAR Bytef
Definition: zconf.h:377
uint8 * GetWritePointer()
Definition: MessageBuffer.h:60
void EncryptSend(uint8 *data, size_t length)
Definition: PacketCrypt.cpp:33
uint32 const SizeOfServerHeader[2]
Definition: WorldSocket.cpp:65
Definition: Opcodes.h:1647
void WriteCompleted(size_type bytes)
Definition: MessageBuffer.h:64
uint16 Command
Definition: ServerPktHeader.h:29
uint32_t uint32
Definition: Define.h:150
Definition: ServerPktHeader.h:24
void Write(void const *data, std::size_t size)
Definition: MessageBuffer.h:92
uint16 Size
Definition: ServerPktHeader.h:28
static uint32 const MinSizeForCompression
Definition: WorldSocket.h:75
WorldPacketCrypt _authCrypt
Definition: WorldSocket.h:140
struct ServerPktHeader::@317 Setup
struct ServerPktHeader::@318 Normal
uint8_t uint8
Definition: Define.h:152
uint32 CompressPacket(uint8 *buffer, WorldPacket const &packet)
Definition: WorldSocket.cpp:563

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Member Data Documentation

WorldPacketCrypt WorldSocket::_authCrypt
private
bool WorldSocket::_authed
private
MPSCQueue<EncryptablePacket> WorldSocket::_bufferQueue
private
z_stream_s* WorldSocket::_compressionStream
private
BigNumber WorldSocket::_decryptSeed
private
BigNumber WorldSocket::_encryptSeed
private
MessageBuffer WorldSocket::_headerBuffer
private
std::string WorldSocket::_ipCountry
private
std::chrono::steady_clock::time_point WorldSocket::_LastPingTime
private
uint32 WorldSocket::_OverSpeedPings
private
MessageBuffer WorldSocket::_packetBuffer
private
std::function<void(PreparedQueryResult&&)> WorldSocket::_queryCallback
private
PreparedQueryResultFuture WorldSocket::_queryFuture
private
BigNumber WorldSocket::_serverChallenge
private
ConnectionType WorldSocket::_type
private
WorldSession* WorldSocket::_worldSession
private
std::mutex WorldSocket::_worldSessionLock
private
uint8 const WorldSocket::AuthCheckSeed = { 0xC5, 0xC6, 0x98, 0x95, 0x76, 0x3F, 0x1D, 0xCD, 0xB6, 0xA1, 0x37, 0x28, 0xB3, 0x12, 0xFF, 0x8A }
staticprivate
std::string const WorldSocket::ClientConnectionInitialize
staticprivate
uint32 const WorldSocket::ConnectionInitializeMagic = 0xF5EB1CE
staticprivate
uint8 const WorldSocket::ContinuedSessionSeed = { 0x16, 0xAD, 0x0C, 0xD4, 0x46, 0xF9, 0x4F, 0xB2, 0xEF, 0x7D, 0xEA, 0x2A, 0x17, 0x66, 0x4D, 0x2F }
staticprivate
uint32 const WorldSocket::MinSizeForCompression = 0x400
staticprivate
std::string const WorldSocket::ServerConnectionInitialize
staticprivate
uint8 const WorldSocket::SessionKeySeed = { 0x58, 0xCB, 0xCF, 0x40, 0xFE, 0x2E, 0xCE, 0xA6, 0x5A, 0x90, 0xB8, 0x01, 0x68, 0x6C, 0x28, 0x0B }
staticprivate

The documentation for this class was generated from the following files: