TrinityCore
Loading...
Searching...
No Matches
WorldSocket.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSocket.h"
20#include "BigNumber.h"
21#include "ClientBuildInfo.h"
22#include "DatabaseEnv.h"
23#include "GameTime.h"
24#include "CryptoHash.h"
25#include "CryptoRandom.h"
26#include "IPLocation.h"
28#include "PacketLog.h"
29#include "Random.h"
30#include "RBAC.h"
31#include "Realm.h"
32#include "ScriptMgr.h"
33#include "World.h"
34#include "WorldSession.h"
35#include <memory>
36
37WorldSocket::WorldSocket(Trinity::Net::IoContextTcpSocket&& socket) : BaseSocket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
38{
40}
41
43
45{
46 explicit WorldSocketProtocolInitializer(WorldSocket* socket) : _socket(socket) { }
47
48 void Start() override
49 {
51
52 if (this->next)
53 this->next->Start();
54 }
55
56private:
58};
59
61{
62 // build initializer chain
63 std::array<std::shared_ptr<Trinity::Net::SocketConnectionInitializer>, 3> initializers =
64 { {
65 std::make_shared<Trinity::Net::IpBanCheckConnectionInitializer<WorldSocket>>(this),
66 std::make_shared<WorldSocketProtocolInitializer>(this),
67 std::make_shared<Trinity::Net::ReadConnectionInitializer<WorldSocket>>(this),
68 } };
69
71}
72
74{
75 EncryptablePacket* queued;
76 if (_bufferQueue.Dequeue(queued))
77 {
78 // Allocate buffer only when it's needed but not on every Update() call.
80 do
81 {
82 ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
83 if (queued->NeedsEncryption())
85
86 if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength())
87 {
88 QueuePacket(std::move(buffer));
89 buffer.Resize(_sendBufferSize);
90 }
91
92 if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength())
93 {
94 buffer.Write(header.header, header.getHeaderLength());
95 if (!queued->empty())
96 buffer.Write(queued->contents(), queued->size());
97 }
98 else // single packet larger than buffer size
99 {
100 MessageBuffer packetBuffer(queued->size() + header.getHeaderLength());
101 packetBuffer.Write(header.header, header.getHeaderLength());
102 if (!queued->empty())
103 packetBuffer.Write(queued->contents(), queued->size());
104
105 QueuePacket(std::move(packetBuffer));
106 }
107
108 delete queued;
109 } while (_bufferQueue.Dequeue(queued));
110
111 if (buffer.GetActiveSize() > 0)
112 QueuePacket(std::move(buffer));
113 }
114
115 if (!BaseSocket::Update())
116 return false;
117
119
120 return true;
121}
122
135
137{
138 {
139 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
140 _worldSession = nullptr;
141 }
142}
143
145{
146 MessageBuffer& packet = GetReadBuffer();
147 while (packet.GetActiveSize() > 0)
148 {
150 {
151 // need to receive the header
152 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
153 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
154 packet.ReadCompleted(readHeaderSize);
155
157 {
158 // Couldn't receive the whole header this time.
159 ASSERT(packet.GetActiveSize() == 0);
160 break;
161 }
162
163 // We just received nice new header
164 if (!ReadHeaderHandler())
165 {
166 CloseSocket();
168 }
169 }
170
171 // We have full read header, now check the data payload
173 {
174 // need more data in the payload
175 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
176 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
177 packet.ReadCompleted(readDataSize);
178
180 {
181 // Couldn't receive the whole data this time.
182 ASSERT(packet.GetActiveSize() == 0);
183 break;
184 }
185 }
186
187 // just received fresh new payload
190 if (result != ReadDataHandlerResult::Ok)
191 {
193 CloseSocket();
194
196 }
197 }
198
200}
201
203{
204 _queryProcessor.AddCallback(std::move(queryCallback));
205}
206
208{
210
213
214 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
215 EndianConvertReverse(header->size);
216 EndianConvert(header->cmd);
217
218 if (!header->IsValidSize() || !header->IsValidOpcode())
219 {
220 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, cmd: {})",
221 GetRemoteIpAddress().to_string(), header->size, header->cmd);
222 return false;
223 }
224
225 header->size -= sizeof(header->cmd);
226 _packetBuffer.Resize(header->size);
227 return true;
228}
229
230struct AuthSession
231{
236 std::array<uint8, 4> LocalChallenge = {};
241 std::string Account;
243};
244
245struct AccountInfo
246{
247 uint32 Id;
249 std::string LastIP;
250 bool IsLockedToIP;
251 std::string LockCountry;
256 std::string OS;
260 bool IsBanned;
261
262 explicit AccountInfo(Field const* fields)
263 {
264 // 0 1 2 3 4 5 6 7 8 9 10 11
265 // SELECT a.id, a.sessionkey, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, a.timezone_offset, aa.SecurityLevel,
266 // 12 13
267 // ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id
268 // FROM account a
269 // LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?)
270 // LEFT JOIN account_banned ab ON a.id = ab.id
271 // LEFT JOIN account r ON a.id = r.recruiter
272 // WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1
273 Id = fields[0].GetUInt32();
275 LastIP = fields[2].GetString();
276 IsLockedToIP = fields[3].GetBool();
277 LockCountry = fields[4].GetString();
278 Expansion = fields[5].GetUInt8();
279 MuteTime = fields[6].GetInt64();
280 Locale = LocaleConstant(fields[7].GetUInt8());
281 Recruiter = fields[8].GetUInt32();
282 OS = fields[9].GetString();
283 TimezoneOffset = Minutes(fields[10].GetInt16());
284 Security = AccountTypes(fields[11].GetUInt8());
285 IsBanned = fields[12].GetUInt64() != 0;
286 IsRectuiter = fields[13].GetUInt32() != 0;
287
288 uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
289 if (Expansion > world_expansion)
290 Expansion = world_expansion;
291
292 if (Locale >= TOTAL_LOCALES)
294 }
295};
296
298{
299 ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
300 OpcodeClient opcode = static_cast<OpcodeClient>(header->cmd);
301
302 WorldPacket packet(opcode, std::move(_packetBuffer));
303 WorldPacket* packetToQueue;
304
305 if (sPacketLog->CanLogPacket())
307
308 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock, std::defer_lock);
309
310 switch (opcode)
311 {
312 case CMSG_PING:
313 {
314 LogOpcodeText(opcode, sessionGuard);
315 try
316 {
318 }
319 catch (ByteBufferException const&)
320 {
321 }
322 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
324 }
326 {
327 LogOpcodeText(opcode, sessionGuard);
328 if (_authed)
329 {
330 // locking just to safely log offending user is probably overkill but we are disconnecting him anyway
331 if (sessionGuard.try_lock())
332 TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
334 }
335
336 try
337 {
338 HandleAuthSession(packet);
340 }
341 catch (ByteBufferException const&)
342 {
343 }
344 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string());
346 }
347 case CMSG_KEEP_ALIVE: // todo: handle this packet in the same way of CMSG_TIME_SYNC_RESP
348 sessionGuard.lock();
349 LogOpcodeText(opcode, sessionGuard);
350 if (_worldSession)
351 {
354 }
355 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress().to_string());
358 packetToQueue = new WorldPacket(std::move(packet), std::chrono::steady_clock::now());
359 break;
360
361 default:
362 packetToQueue = new WorldPacket(std::move(packet));
363 break;
364 }
365
366 sessionGuard.lock();
367
368 LogOpcodeText(opcode, sessionGuard);
369
370 if (!_worldSession)
371 {
372 TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = {}", uint32(opcode));
373 delete packetToQueue;
375 }
376
377 OpcodeHandler const* handler = opcodeTable[opcode];
378 if (!handler)
379 {
380 TC_LOG_ERROR("network.opcode", "No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(static_cast<OpcodeClient>(packet.GetOpcode())), _worldSession->GetPlayerInfo());
381 delete packetToQueue;
383 }
384
385 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
387
388 // Copy the packet to the heap before enqueuing
389 _worldSession->QueuePacket(packetToQueue);
390
392}
393
394void WorldSocket::LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const
395{
396 if (!guard || !_worldSession)
397 {
398 TC_LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(opcode));
399 }
400 else
401 {
402 TC_LOG_TRACE("network.opcode", "C->S: {} {}", _worldSession->GetPlayerInfo(), GetOpcodeNameForLogging(opcode));
403 }
404}
405
407{
408 TC_LOG_TRACE("network.opcode", "S->C: {} {}", GetRemoteIpAddress().to_string(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())));
409 SendPacket(packet);
410}
411
413{
414 if (!IsOpen())
415 return;
416
417 if (sPacketLog->CanLogPacket())
419
421}
422
424{
425 std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();
426
427 // Read the content of the packet
428 recvPacket >> authSession->Build;
429 recvPacket >> authSession->LoginServerID;
430 recvPacket >> authSession->Account;
431 recvPacket >> authSession->LoginServerType;
432 recvPacket.read(authSession->LocalChallenge);
433 recvPacket >> authSession->RegionID;
434 recvPacket >> authSession->BattlegroupID;
435 recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table
436 recvPacket >> authSession->DosResponse;
437 recvPacket.read(authSession->Digest);
438 authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos());
439 recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want
440
441 // Get the account information from the auth database
443 stmt->setInt32(0, int32(realm.Id.Realm));
444 stmt->setString(1, authSession->Account);
445
446 QueueQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession)](PreparedQueryResult result) mutable
447 {
448 HandleAuthSessionCallback(std::move(authSession), std::move(result));
449 }));
450}
451
452void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSession, PreparedQueryResult result)
453{
454 // Stop if the account is not found
455 if (!result)
456 {
457 // We can not log here, as we do not know the account. Thus, no accountId.
459 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
461 return;
462 }
463
464 AccountInfo account(result->Fetch());
465
466 // For hook purposes, we get Remoteaddress at this point.
467 std::string address = GetRemoteIpAddress().to_string();
468
469 LoginDatabasePreparedStatement* stmt = nullptr;
470
472 {
473 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
474 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
475 stmt->setString(0, address);
476 stmt->setString(1, authSession->Account);
477 LoginDatabase.Execute(stmt);
478 // This also allows to check for possible "hack" attempts on account
479 }
480
481 // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
482 _authCrypt.Init(account.SessionKey);
483
484 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
485 if (sWorld->IsClosed())
486 {
488 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", GetRemoteIpAddress().to_string());
490 return;
491 }
492
493 if (authSession->RealmID != realm.Id.Realm)
494 {
496 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
497 GetRemoteIpAddress().to_string(), authSession->RealmID, realm.Id.Realm);
499 return;
500 }
501
502 // Must be done before WorldSession is created
503 bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
504 if (wardenActive && !ClientBuild::Platform::IsValid(account.OS))
505 {
507 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} attempted to log in using invalid client OS ({}).", address, account.OS);
509 return;
510 }
511
512 // Check that Key and account name are the same on client and server
513 uint8 t[4] = { 0x00,0x00,0x00,0x00 };
514
516 sha.UpdateData(authSession->Account);
517 sha.UpdateData(t);
518 sha.UpdateData(authSession->LocalChallenge);
520 sha.UpdateData(account.SessionKey);
521 sha.Finalize();
522
523 if (sha.GetDigest() != authSession->Digest)
524 {
526 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Id, authSession->Account, address);
528 return;
529 }
530
531 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
532 _ipCountry = location->CountryCode;
533
535 if (account.IsLockedToIP)
536 {
537 if (account.LastIP != address)
538 {
540 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.LastIP, address);
541 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
542 sScriptMgr->OnFailedAccountLogin(account.Id);
544 return;
545 }
546 }
547 else if (!account.LockCountry.empty() && account.LockCountry != "00" && !_ipCountry.empty())
548 {
549 if (account.LockCountry != _ipCountry)
550 {
552 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.LockCountry, _ipCountry);
553 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
554 sScriptMgr->OnFailedAccountLogin(account.Id);
556 return;
557 }
558 }
559
560 int64 mutetime = account.MuteTime;
562 if (mutetime < 0)
563 {
564 mutetime = GameTime::GetGameTime() + std::llabs(mutetime);
565
566 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
567 stmt->setInt64(0, mutetime);
568 stmt->setUInt32(1, account.Id);
569 LoginDatabase.Execute(stmt);
570 }
571
572 if (account.IsBanned)
573 {
575 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
576 sScriptMgr->OnFailedAccountLogin(account.Id);
578 return;
579 }
580
581 // Check locked state for server
582 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
583 TC_LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Security);
584 if (allowedAccountType > SEC_PLAYER && account.Security < allowedAccountType)
585 {
587 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
588 sScriptMgr->OnFailedAccountLogin(account.Id);
590 return;
591 }
592
593 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", authSession->Account, address);
594
596 {
597 // Update the last_ip in the database as it was successful for login
598 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
599
600 stmt->setString(0, address);
601 stmt->setString(1, authSession->Account);
602
603 LoginDatabase.Execute(stmt);
604 }
605
606 // At this point, we can safely hook a successful login
607 sScriptMgr->OnAccountLogin(account.Id);
608
609 _authed = true;
610 _worldSession = new WorldSession(account.Id, std::move(authSession->Account),
611 static_pointer_cast<WorldSocket>(shared_from_this()), account.Security, account.Expansion, mutetime,
612 account.TimezoneOffset, account.Locale,
613 account.Recruiter, account.IsRectuiter);
614 _worldSession->ReadAddonsInfo(authSession->AddonInfo);
615
616 // Initialize Warden system only if it is enabled by config
617 if (wardenActive)
618 _worldSession->InitWarden(account.SessionKey, account.OS);
619
622}
623
625{
626 // RBAC must be loaded before adding session to check for skip queue permission
628
629 sWorld->AddSession(_worldSession);
630}
631
633{
635 packet << uint8(code);
636
638}
639
641{
642 using namespace std::chrono;
643
644 uint32 ping;
645 uint32 latency;
646
647 // Get the ping packet content
648 recvPacket >> ping;
649 recvPacket >> latency;
650
651 if (_LastPingTime == steady_clock::time_point())
652 {
653 _LastPingTime = steady_clock::now();
654 }
655 else
656 {
657 steady_clock::time_point now = steady_clock::now();
658
659 steady_clock::duration diff = now - _LastPingTime;
660
661 _LastPingTime = now;
662
663 if (diff < seconds(27))
664 {
666
667 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
668
669 if (maxAllowed && _OverSpeedPings > maxAllowed)
670 {
671 std::unique_lock<std::mutex> sessionGuard(_worldSessionLock);
672
674 {
675 TC_LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
677
678 return false;
679 }
680 }
681 }
682 else
683 _OverSpeedPings = 0;
684 }
685
686 {
687 std::lock_guard<std::mutex> sessionGuard(_worldSessionLock);
688
689 if (_worldSession)
690 _worldSession->SetLatency(latency);
691 else
692 {
693 TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress().to_string());
694 return false;
695 }
696 }
697
698 WorldPacket packet(SMSG_PONG, 4);
699 packet << ping;
701 return true;
702}
constexpr size_t SESSION_KEY_LENGTH
Definition AuthDefines.h:24
std::array< uint8, SESSION_KEY_LENGTH > SessionKey
Definition AuthDefines.h:25
void EndianConvertReverse(T &)
void EndianConvert(T &val)
LocaleConstant
Definition Common.h:48
@ TOTAL_LOCALES
Definition Common.h:59
@ LOCALE_enUS
Definition Common.h:49
AccountTypes
Definition Common.h:39
@ SEC_PLAYER
Definition Common.h:40
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
uint8_t uint8
Definition Define.h:135
int64_t int64
Definition Define.h:128
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint32_t uint32
Definition Define.h:133
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
#define ASSERT
Definition Errors.h:68
#define sIPLocation
Definition IPLocation.h:48
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_TRACE(filterType__,...)
Definition Log.h:153
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
@ LOGIN_UPD_MUTE_TIME_LOGIN
@ LOGIN_UPD_LAST_ATTEMPT_IP
@ LOGIN_UPD_LAST_IP
@ LOGIN_SEL_ACCOUNT_INFO_BY_NAME
#define sPacketLog
Definition PacketLog.h:53
@ SERVER_TO_CLIENT
Definition PacketLog.h:29
@ CLIENT_TO_SERVER
Definition PacketLog.h:28
Role Based Access Control related classes definition.
#define sScriptMgr
Definition ScriptMgr.h:1168
@ AUTH_REJECT
@ REALM_LIST_REALM_NOT_FOUND
@ AUTH_FAILED
@ AUTH_UNKNOWN_ACCOUNT
@ AUTH_BANNED
@ AUTH_UNAVAILABLE
std::string Account
ByteBuffer AddonInfo
uint64 DosResponse
uint32 LoginServerID
uint32 BattlegroupID
std::array< uint8, 4 > LocalChallenge
uint32 LoginServerType
Trinity::Crypto::SHA1::Digest Digest
size_t rpos() const
Definition ByteBuffer.h:308
size_t size() const
Definition ByteBuffer.h:409
bool empty() const
Definition ByteBuffer.h:410
uint8 * contents()
Definition ByteBuffer.h:395
bool NeedsEncryption() const
Definition WorldSocket.h:40
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
std::vector< uint8 > GetBinary() const
Definition Field.cpp:149
int64 GetInt64() const
Definition Field.cpp:85
uint64 GetUInt64() const
Definition Field.cpp:77
bool GetBool() const
Definition Field.h:100
uint32 GetUInt32() const
Definition Field.cpp:61
void Resize(size_type bytes)
size_type GetRemainingSpace() const
void ReadCompleted(size_type bytes)
uint8 * GetReadPointer()
size_type GetActiveSize() const
void Write(void const *data, std::size_t size)
void setUInt32(uint8 index, uint32 value)
void setInt64(uint8 index, int64 value)
void setInt32(uint8 index, int32 value)
void setString(uint8 index, std::string const &value)
QueryCallback && WithPreparedCallback(std::function< void(PreparedQueryResult)> &&callback)
std::array< uint8, DIGEST_LENGTH > Digest
Definition CryptoHash.h:47
void UpdateData(uint8 const *data, size_t len)
Definition CryptoHash.h:111
Digest const & GetDigest() const
Definition CryptoHash.h:130
uint16 GetRemotePort() const
Definition Socket.h:158
bool IsOpen() const
Definition Socket.h:189
boost::asio::ip::address const & GetRemoteIpAddress() const
Definition Socket.h:153
void AsyncRead(Callback &&callback)
Definition Socket.h:164
void QueuePacket(MessageBuffer &&buffer)
Definition Socket.h:180
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:206
MessageBuffer & GetReadBuffer()
Definition Socket.h:215
bool IsInitialized() const
void EncryptSend(uint8 *data, size_t len)
void Init(SessionKey const &K)
void DecryptRecv(uint8 *data, size_t len)
uint16 GetOpcode() const
Definition WorldPacket.h:80
WorldPacket const * Write() override
Player session in the World.
void InitWarden(SessionKey const &k, std::string const &os)
rbac::RBACData * GetRBACData() const
void ReadAddonsInfo(ByteBuffer &data)
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
std::string GetPlayerInfo() const
QueryCallback LoadPermissionsAsync()
bool HasPermission(uint32 permissionId)
void ResetTimeOutTime(bool onlyActive)
void SetLatency(uint32 latency)
MessageBuffer _headerBuffer
void LogOpcodeText(OpcodeClient opcode, std::unique_lock< std::mutex > const &guard) const
void QueueQuery(QueryCallback &&queryCallback)
bool ReadHeaderHandler()
void HandleAuthSession(WorldPacket &recvPacket)
bool HandlePing(WorldPacket &recvPacket)
bool Update() override
void LoadSessionPermissionsCallback(PreparedQueryResult result)
MessageBuffer _packetBuffer
QueryCallbackProcessor _queryProcessor
WorldPacketCrypt _authCrypt
std::array< uint8, 4 > _serverChallenge
Socket BaseSocket
Definition WorldSocket.h:69
void Start() override
std::size_t _sendBufferSize
std::array< uint8, 32 > _dosChallenge
Trinity::Net::SocketReadCallbackResult ReadHandler() override
WorldSocket(Trinity::Net::IoContextTcpSocket &&socket)
uint32 _OverSpeedPings
TimePoint _LastPingTime
WorldSession * _worldSession
std::string _ipCountry
void SendPacket(WorldPacket const &packet)
MPSCQueue< EncryptablePacket, &EncryptablePacket::SocketQueueLink > _bufferQueue
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
void HandleAuthSessionCallback(std::shared_ptr< AuthSession > authSession, PreparedQueryResult result)
std::mutex _worldSessionLock
void OnClose() override
ReadDataHandlerResult ReadDataHandler()
void SendAuthSession()
void SendAuthResponseError(uint8 code)
void LoadFromDBCallback(PreparedQueryResult result)
Definition RBAC.cpp:200
Opcodes
Definition Opcodes.h:29
std::string GetOpcodeNameForLogging(Opcodes opcode)
Lookup opcode name for human understandable logging.
Definition Opcodes.cpp:1469
OpcodeTable opcodeTable
Definition Opcodes.cpp:51
@ CMSG_TIME_SYNC_RESP
Definition Opcodes.h:942
@ CMSG_PING
Definition Opcodes.h:505
@ SMSG_PONG
Definition Opcodes.h:506
@ CMSG_KEEP_ALIVE
Definition Opcodes.h:1060
@ SMSG_AUTH_RESPONSE
Definition Opcodes.h:523
@ CMSG_AUTH_SESSION
Definition Opcodes.h:522
#define sWorld
Definition World.h:900
Realm realm
Definition World.cpp:3605
@ CONFIG_MAX_OVERSPEED_PINGS
Definition World.h:281
@ CONFIG_EXPANSION
Definition World.h:282
@ CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE
Definition World.h:180
@ CONFIG_WARDEN_ENABLED
Definition World.h:155
TC_SHARED_API bool IsValid(std::string_view platform)
time_t GetGameTime()
Definition GameTime.cpp:42
std::array< uint8, S > GetRandomBytes()
SocketReadCallbackResult
Definition Socket.h:44
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
Definition Socket.h:41
@ RBAC_PERM_SKIP_CHECK_OVERSPEED_PING
Definition RBAC.h:76
STL namespace.
std::string LockCountry
Definition AuthSession.h:56
std::string OS
LocaleConstant Locale
::SessionKey SessionKey
AccountTypes Security
AccountInfo(Field const *fields)
bool IsLockedToIP
Definition AuthSession.h:55
std::string LastIP
Definition AuthSession.h:57
Minutes TimezoneOffset
bool IsValidSize() const
Definition WorldSocket.h:59
bool IsValidOpcode() const
Definition WorldSocket.h:60
uint32 Realm
Definition Realm.h:44
RealmHandle Id
Definition Realm.h:67
static std::shared_ptr< SocketConnectionInitializer > & SetupChain(std::span< std::shared_ptr< SocketConnectionInitializer > > initializers)
std::shared_ptr< SocketConnectionInitializer > next
WorldSocketProtocolInitializer(WorldSocket *socket)