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"
21#include "CharacterPackets.h"
22#include "CryptoHash.h"
23#include "CryptoRandom.h"
24#include "DatabaseEnv.h"
25#include "Errors.h"
26#include "GameTime.h"
27#include "HMAC.h"
28#include "IPLocation.h"
30#include "PacketLog.h"
31#include "ProtobufJSON.h"
33#include "RealmList.h"
34#include "RBAC.h"
35#include "RealmList.pb.h"
36#include "ScriptMgr.h"
37#include "SessionKeyGenerator.h"
38#include "World.h"
39#include "WorldPacket.h"
40#include "WorldSession.h"
41#include <zlib.h>
42
43#pragma pack(push, 1)
44
51
52#pragma pack(pop)
53
55
56std::array<uint8, 32> const WorldSocket::AuthCheckSeed = { 0xDE, 0x3A, 0x2A, 0x8E, 0x6B, 0x89, 0x52, 0x66, 0x88, 0x9D, 0x7E, 0x7A, 0x77, 0x1D, 0x5D, 0x1F,
57 0x4E, 0xD9, 0x0C, 0x23, 0x9B, 0xCD, 0x0E, 0xDC, 0xD2, 0xE8, 0x04, 0x3A, 0x68, 0x64, 0xC7, 0xB0 };
58std::array<uint8, 32> const WorldSocket::SessionKeySeed = { 0xE8, 0x1E, 0x8B, 0x59, 0x27, 0x62, 0x1E, 0xAA, 0x86, 0x15, 0x18, 0xEA, 0xC0, 0xBF, 0x66, 0x8C,
59 0x6D, 0xBF, 0x83, 0x93, 0xBC, 0xAA, 0x80, 0x52, 0x5B, 0x1E, 0xDC, 0x23, 0xA0, 0x12, 0xB7, 0x50 };
60std::array<uint8, 32> const WorldSocket::ContinuedSessionSeed = { 0x56, 0x5C, 0x61, 0x9C, 0x48, 0x3A, 0x52, 0x1F, 0x61, 0x5D, 0x05, 0x49, 0xB2, 0x9A, 0x39, 0xBF,
61 0x4B, 0x97, 0xB0, 0x1B, 0xF9, 0x6C, 0xDE, 0xD6, 0x80, 0x1D, 0xAB, 0x26, 0x02, 0xA9, 0x9B, 0x9D };
62std::array<uint8, 32> const WorldSocket::EncryptionKeySeed = { 0x71, 0xC9, 0xED, 0x5A, 0xA7, 0x0E, 0x4D, 0xFF, 0x4C, 0x36, 0xA6, 0x5A, 0x3E, 0x46, 0x8A, 0x4A,
63 0x5D, 0xA1, 0x48, 0xC8, 0x30, 0x47, 0x4A, 0xDE, 0xF6, 0x0D, 0x6C, 0xBE, 0x6F, 0xE4, 0x55, 0x73 };
64
66 _type(CONNECTION_TYPE_REALM), _key(0), _serverChallenge(), _sessionKey(), _encryptKey(), _overSpeedPings(0),
67 _worldSession(nullptr), _authed(false), _canRequestHotfixes(true), _headerBuffer(sizeof(IncomingPacketHeader)), _sendBufferSize(4096), _compressionStream(nullptr)
68{
69}
70
72{
74 {
75 deflateEnd(_compressionStream);
76 delete _compressionStream;
77 }
78}
79
81{
82 static constexpr std::string_view ServerConnectionInitialize = "WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT - V2\n";
83 static constexpr std::string_view ClientConnectionInitialize = "WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER - V2\n";
84
85 explicit WorldSocketProtocolInitializer(WorldSocket* socket) : _socket(socket) { }
86
87 void Start() override
88 {
90
91 AsyncRead();
92
93 MessageBuffer initializer;
95
96 // - IoContext.run thread, safe.
97 _socket->QueuePacket(std::move(initializer));
98 }
99
101 {
103 [socketRef = _socket->weak_from_this(), self = static_pointer_cast<WorldSocketProtocolInitializer>(this->shared_from_this())]
104 {
105 if (!socketRef.expired())
106 return self->ReadHandler();
107
108 return Trinity::Net::SocketReadCallbackResult::Stop;
109 });
110 }
111
113
114 void HandleDataReady();
115
116private:
119};
120
122{
123 // build initializer chain
124 std::array<std::shared_ptr<Trinity::Net::SocketConnectionInitializer>, 3> initializers =
125 { {
126 std::make_shared<Trinity::Net::IpBanCheckConnectionInitializer<WorldSocket>>(this),
127 std::make_shared<WorldSocketProtocolInitializer>(this),
128 std::make_shared<Trinity::Net::ReadConnectionInitializer<WorldSocket>>(this),
129 } };
130
132}
133
135{
137 if (packet.GetActiveSize() > 0 && _packetBuffer.GetRemainingSpace() > 0)
138 {
139 // need to receive the header
140 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
141 _packetBuffer.Write(packet.GetReadPointer(), readHeaderSize);
142 packet.ReadCompleted(readHeaderSize);
143
145 {
148 }
149
150 // Couldn't receive the whole header this time.
151 ASSERT(packet.GetActiveSize() == 0);
152 }
153
155}
156
158{
159 try
160 {
161 ByteBuffer buffer(std::move(_packetBuffer).Release());
163 {
165 return;
166 }
167 }
168 catch (ByteBufferException const& ex)
169 {
170 TC_LOG_ERROR("network", "WorldSocket::InitializeHandler ByteBufferException {} occured while parsing initial packet from {}",
173 return;
174 }
175
177 return;
178
180 InvokeNext();
181}
182
184{
186 _compressionStream->zalloc = (alloc_func)nullptr;
187 _compressionStream->zfree = (free_func)nullptr;
188 _compressionStream->opaque = (voidpf)nullptr;
189 _compressionStream->avail_in = 0;
190 _compressionStream->next_in = nullptr;
191 int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
192 if (z_res != Z_OK)
193 {
194 CloseSocket();
195 TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: {} ({})", z_res, zError(z_res));
196 return false;
197 }
198
199 return true;
200}
201
203{
204 EncryptablePacket* queued;
206 while (_bufferQueue.Dequeue(queued))
207 {
208 uint32 packetSize = queued->size() + 4 /*opcode*/;
209 if (packetSize > MinSizeForCompression && queued->NeedsEncryption())
210 packetSize = deflateBound(_compressionStream, packetSize) + sizeof(CompressedWorldPacket);
211
212 // Flush current buffer if too small for next packet
213 if (buffer.GetRemainingSpace() < packetSize + sizeof(PacketHeader))
214 {
215 QueuePacket(std::move(buffer));
216 buffer.Resize(_sendBufferSize);
217 }
218
219 if (buffer.GetRemainingSpace() >= packetSize + sizeof(PacketHeader))
220 WritePacketToBuffer(*queued, buffer);
221 else // single packet larger than _sendBufferSize
222 {
223 MessageBuffer packetBuffer(packetSize + sizeof(PacketHeader));
224 WritePacketToBuffer(*queued, packetBuffer);
225 QueuePacket(std::move(packetBuffer));
226 }
227
228 delete queued;
229 }
230
231 if (buffer.GetActiveSize() > 0)
232 QueuePacket(std::move(buffer));
233
234 if (!BaseSocket::Update())
235 return false;
236
238
239 return true;
240}
241
243{
245
247 challenge.Challenge = _serverChallenge;
248 memcpy(challenge.DosChallenge.data(), Trinity::Crypto::GetRandomBytes<32>().data(), 32);
249 challenge.DosZeroBits = 1;
250
251 SendPacketAndLogOpcode(*challenge.Write());
252}
253
255{
256 {
257 std::scoped_lock sessionGuard(_worldSessionLock);
258 _worldSession = nullptr;
259 }
260}
261
263{
264 MessageBuffer& packet = GetReadBuffer();
265 while (packet.GetActiveSize() > 0)
266 {
268 {
269 // need to receive the header
270 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
271 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
272 packet.ReadCompleted(readHeaderSize);
273
275 {
276 // Couldn't receive the whole header this time.
277 ASSERT(packet.GetActiveSize() == 0);
278 break;
279 }
280
281 // We just received nice new header
282 if (!ReadHeaderHandler())
283 {
284 CloseSocket();
286 }
287 }
288
289 // We have full read header, now check the data payload
291 {
292 // need more data in the payload
293 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
294 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
295 packet.ReadCompleted(readDataSize);
296
298 {
299 // Couldn't receive the whole data this time.
300 ASSERT(packet.GetActiveSize() == 0);
301 break;
302 }
303 }
304
305 // just received fresh new payload
308 if (result != ReadDataHandlerResult::Ok)
309 {
311 CloseSocket();
312
314 }
315 }
316
318}
319
321{
322 _queryProcessor.AddCallback(std::move(queryCallback));
323}
324
326{
327 std::scoped_lock sessionGuard(_worldSessionLock);
328 _worldSession = session;
329 _authed = true;
330}
331
333{
334 ASSERT(_headerBuffer.GetActiveSize() == sizeof(IncomingPacketHeader), "Header size " SZFMTD " different than expected " SZFMTD, _headerBuffer.GetActiveSize(), sizeof(IncomingPacketHeader));
335
337 uint32 encryptedOpcode = header->EncryptedOpcode;
338
339 if (!header->IsValidSize())
340 {
341 _authCrypt.PeekDecryptRecv(reinterpret_cast<uint8*>(&header->EncryptedOpcode), sizeof(encryptedOpcode));
342
343 // CMSG_HOTFIX_REQUEST can be much larger than normal packets, allow receiving it once per session
344 if (header->EncryptedOpcode != CMSG_HOTFIX_REQUEST || header->Size > 0x100000 || !_canRequestHotfixes)
345 {
346 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, opcode {})",
347 GetRemoteIpAddress(), header->Size, uint32(header->EncryptedOpcode));
348 return false;
349 }
350 }
351
352 _packetBuffer.Resize(header->Size);
353 _packetBuffer.Write(&encryptedOpcode, sizeof(encryptedOpcode));
354 return true;
355}
356
358{
359 PacketHeader* header = reinterpret_cast<PacketHeader*>(_headerBuffer.GetReadPointer());
360
361 if (!_authCrypt.DecryptRecv(_packetBuffer.GetReadPointer(), header->Size, header->Tag))
362 {
363 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} failed to decrypt packet (size: {})",
364 GetRemoteIpAddress(), header->Size);
366 }
367
368 WorldPacket packet(std::move(_packetBuffer).Release(), GetConnectionType());
369 OpcodeClient opcode = packet.read<OpcodeClient>();
370 if (!opcodeTable.IsValid(opcode))
371 {
372 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent wrong opcode (opcode: {})",
373 GetRemoteIpAddress(), uint32(opcode));
375 }
376
377 packet.SetOpcode(opcode);
378
379 if (sPacketLog->CanLogPacket())
381
382 switch (opcode)
383 {
384 case CMSG_PING:
385 return HandlePing(std::move(packet));
387 return HandleAuthSession(std::move(packet));
389 return HandleAuthContinuedSession(std::move(packet));
390 case CMSG_KEEP_ALIVE:
391 return HandleKeepAlive();
393 return HandleLogDisconnect(std::move(packet));
396 SetNoDelay(false);
397 break;
399 return HandleConnectToFailed(std::move(packet));
402 default:
403 {
405 packet.SetReceiveTime(std::chrono::steady_clock::now());
406 else if (opcode == CMSG_HOTFIX_REQUEST)
407 _canRequestHotfixes = false;
408
409 std::scoped_lock sessionGuard(_worldSessionLock);
410
411 LogOpcodeText(opcode, sessionGuard);
412
413 if (!_worldSession)
414 {
415 TC_LOG_ERROR("network.opcode", "WorldSocket::ReadDataHandler: Client not authed opcode {}", GetOpcodeNameForLogging(opcode));
417 }
418
419 if (!opcodeTable[opcode])
420 {
421 TC_LOG_ERROR("network.opcode", "WorldSocket::ReadDataHandler: No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(opcode), _worldSession->GetPlayerInfo());
422 break;
423 }
424
425 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
427
428 _worldSession->QueuePacket(std::move(packet));
429 break;
430 }
431 }
432
434}
435
437{
438 TC_LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(opcode));
439}
440
441void WorldSocket::LogOpcodeText(OpcodeClient opcode, std::scoped_lock<std::mutex> const& /*guard*/) const
442{
443 if (!_worldSession)
444 {
445 TC_LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(opcode));
446 }
447 else
448 {
449 TC_LOG_TRACE("network.opcode", "C->S: {} {}", _worldSession->GetPlayerInfo(), GetOpcodeNameForLogging(opcode));
450 }
451}
452
454{
455 TC_LOG_TRACE("network.opcode", "S->C: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())));
456 SendPacket(packet);
457}
458
460{
461 if (!IsOpen())
462 return;
463
464 if (sPacketLog->CanLogPacket())
466
468}
469
471{
472 uint32 opcode = packet.GetOpcode();
473 uint32 packetSize = packet.size();
474
475 // Reserve space for buffer
476 uint8* headerPos = buffer.GetWritePointer();
477 buffer.WriteCompleted(sizeof(PacketHeader));
478 uint8* dataPos = buffer.GetWritePointer();
479 buffer.WriteCompleted(sizeof(opcode));
480
481 if (packetSize > MinSizeForCompression && packet.NeedsEncryption())
482 {
484 cmp.UncompressedSize = packetSize + sizeof(opcode);
485 cmp.UncompressedAdler = adler32(adler32(0x9827D8F1, (Bytef*)&opcode, sizeof(opcode)), packet.data(), packetSize);
486
487 // Reserve space for compression info - uncompressed size and checksums
488 uint8* compressionInfo = buffer.GetWritePointer();
490
491 uint32 compressedSize = CompressPacket(buffer.GetWritePointer(), packet);
492
493 cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize);
494
495 memcpy(compressionInfo, &cmp, sizeof(CompressedWorldPacket));
496 buffer.WriteCompleted(compressedSize);
497 packetSize = compressedSize + sizeof(CompressedWorldPacket);
498
499 opcode = SMSG_COMPRESSED_PACKET;
500 }
501 else if (!packet.empty())
502 buffer.Write(packet.data(), packet.size());
503
504 memcpy(dataPos, &opcode, sizeof(opcode));
505 packetSize += sizeof(opcode);
506
507 PacketHeader header;
508 header.Size = packetSize;
509 _authCrypt.EncryptSend(dataPos, header.Size, header.Tag);
510
511 memcpy(headerPos, &header, sizeof(PacketHeader));
512}
513
515{
516 uint32 opcode = packet.GetOpcode();
517 uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode));
518
519 _compressionStream->next_out = buffer;
520 _compressionStream->avail_out = bufferSize;
521 _compressionStream->next_in = (Bytef*)&opcode;
522 _compressionStream->avail_in = sizeof(opcode);
523
524 int32 z_res = deflate(_compressionStream, Z_NO_FLUSH);
525 if (z_res != Z_OK)
526 {
527 TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: {} ({}, msg: {})", z_res, zError(z_res), _compressionStream->msg);
528 return 0;
529 }
530
531 _compressionStream->next_in = (Bytef*)packet.data();
532 _compressionStream->avail_in = packet.size();
533
534 z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
535 if (z_res != Z_OK)
536 {
537 TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: {} ({}, msg: {})", z_res, zError(z_res), _compressionStream->msg);
538 return 0;
539 }
540
541 return bufferSize - _compressionStream->avail_out;
542}
543
545{
546 struct
547 {
549 std::string Email;
551 std::string LastIP;
552 std::string LockCountry;
555
556 struct
557 {
558 uint32 Id;
559 std::array<uint8, 64> KeyData;
565 std::string OS;
569 bool IsBanned;
571
572 bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; }
573
574 explicit AccountInfo(PreparedResultSet const* result)
575 {
576 // SELECT a.id AS accountId, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id AS bnet_account_id, ba.email as bnet_account_email, aa.SecurityLevel,
577 // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate AS is_bnet_banned, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate AS is_banned, r.id AS recruitId
578 // FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id
579 // LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1
580 // WHERE a.username = ? AND LENGTH(a.session_key_bnet) = 64 ORDER BY aa.RealmID DESC LIMIT 1
581
582 DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (account_id)(session_key_bnet)(last_ip)(locked)(lock_country)(expansion)(mutetime)(client_build)
583 (locale)(recruiter)(os)(timezone_offset)(bnet_account_id)(bnet_account_email)(SecurityLevel)(is_bnet_banned)(is_banned)(recruitId)) fields { *result };
584
585 Game.Id = fields.account_id().GetUInt32();
586 Game.KeyData = fields.session_key_bnet().GetBinary<64>();
587 BattleNet.LastIP = fields.last_ip().GetStringView();
588 BattleNet.IsLockedToIP = fields.locked().GetBool();
589 BattleNet.LockCountry = fields.lock_country().GetStringView();
590 Game.Expansion = fields.expansion().GetUInt8();
591 Game.MuteTime = fields.mutetime().GetInt64();
592 Game.Build = fields.client_build().GetUInt32();
593 Game.Locale = LocaleConstant(fields.locale().GetUInt8());
594 Game.Recruiter = fields.recruiter().GetUInt32();
595 Game.OS = fields.os().GetStringView();
596 Game.TimezoneOffset = Minutes(fields.timezone_offset().GetInt16());
597 BattleNet.Id = fields.bnet_account_id().GetUInt32();
598 BattleNet.Email = fields.bnet_account_email().GetStringView();
599 Game.Security = AccountTypes(fields.SecurityLevel().GetUInt8());
600 BattleNet.IsBanned = fields.is_bnet_banned().GetUInt32() != 0;
601 Game.IsBanned = fields.is_banned().GetUInt32() != 0;
602 Game.IsRecruiter = fields.recruitId().GetUInt32() != 0;
603
604 if (Game.Locale >= TOTAL_LOCALES)
605 Game.Locale = LOCALE_enUS;
606 }
607};
608
610{
612
613 if (_authed)
614 {
615 std::scoped_lock guard(_worldSessionLock);
616 TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
618 }
619
620 std::shared_ptr callbackData = std::make_shared<std::pair<WorldPackets::Auth::AuthSession, JSON::RealmList::RealmJoinTicket>>(
621 std::piecewise_construct, std::forward_as_tuple(std::move(packet)), std::forward_as_tuple());
622 if (!callbackData->first.ReadNoThrow())
623 {
624 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress());
626 }
627
628 if (!JSON::Deserialize(callbackData->first.RealmJoinTicket, &callbackData->second))
629 {
633 }
634
635 // Get the account information from the auth database
637 stmt->setInt32(0, int32(sRealmList->GetCurrentRealmId().Realm));
638 stmt->setString(1, callbackData->second.gameaccount());
639
640 QueueQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, callbackData = std::move(callbackData)](PreparedQueryResult const& result) mutable
641 {
642 HandleAuthSessionCallback(&callbackData->first, &callbackData->second, result.get());
643 }));
645}
646
648{
649 // Stop if the account is not found
650 if (!result)
651 {
652 // We can not log here, as we do not know the account. Thus, no accountId.
653 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
655 return;
656 }
657
658 std::string address = GetRemoteIpAddress().to_string();
659
660 AccountInfo account(result);
661
662 ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(account.Game.Build);
663 if (!buildInfo)
664 {
666 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build info for build {} ({}).", account.Game.Build, address);
668 return;
669 }
670
671 ClientBuild::VariantId buildVariant = { .Platform = joinTicket->platform(), .Arch = joinTicket->clientarch(), .Type = joinTicket->type() };
672 auto clientBuildAuthKey = std::ranges::find(buildInfo->AuthKeys, buildVariant, &ClientBuild::AuthKey::Variant);
673 if (clientBuildAuthKey == buildInfo->AuthKeys.end())
674 {
676 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build auth key for build {} variant {}-{}-{} ({}).", account.Game.Build,
677 ClientBuild::ToCharArray(buildVariant.Platform).data(), ClientBuild::ToCharArray(buildVariant.Arch).data(),
678 ClientBuild::ToCharArray(buildVariant.Type).data(), address);
680 return;
681 }
682
683 Trinity::Crypto::SHA512 digestKeyHash;
684 digestKeyHash.UpdateData(account.Game.KeyData.data(), account.Game.KeyData.size());
685 digestKeyHash.UpdateData(clientBuildAuthKey->Key.data(), clientBuildAuthKey->Key.size());
686 digestKeyHash.Finalize();
687
688 Trinity::Crypto::HMAC_SHA512 hmac(digestKeyHash.GetDigest());
689 hmac.UpdateData(authSession->LocalChallenge);
692 hmac.Finalize();
693
694 // Check that Key and account name are the same on client and server
695 if (memcmp(hmac.GetDigest().data(), authSession->Digest.data(), authSession->Digest.size()) != 0)
696 {
698 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Game.Id, joinTicket->gameaccount(), address);
700 return;
701 }
702
704 keyData.UpdateData(account.Game.KeyData.data(), account.Game.KeyData.size());
705 keyData.Finalize();
706
707 Trinity::Crypto::HMAC_SHA512 sessionKeyHmac(keyData.GetDigest());
708 sessionKeyHmac.UpdateData(_serverChallenge);
709 sessionKeyHmac.UpdateData(authSession->LocalChallenge);
710 sessionKeyHmac.UpdateData(SessionKeySeed);
711 sessionKeyHmac.Finalize();
712
713 SessionKeyGenerator<Trinity::Crypto::SHA512> sessionKeyGenerator(sessionKeyHmac.GetDigest());
714 sessionKeyGenerator.Generate(_sessionKey.data(), 40);
715
717 encryptKeyGen.UpdateData(authSession->LocalChallenge);
718 encryptKeyGen.UpdateData(_serverChallenge);
719 encryptKeyGen.UpdateData(EncryptionKeySeed);
720 encryptKeyGen.Finalize();
721
722 // only first 32 bytes of the hmac are used
723 memcpy(_encryptKey.data(), encryptKeyGen.GetDigest().data(), 32);
724
725 LoginDatabasePreparedStatement* stmt = nullptr;
726
728 {
729 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
730 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
731 stmt->setString(0, address);
732 stmt->setString(1, joinTicket->gameaccount());
733 LoginDatabase.Execute(stmt);
734 // This also allows to check for possible "hack" attempts on account
735 }
736
737 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_INFO_CONTINUED_SESSION);
738 stmt->setBinary(0, _sessionKey);
739 stmt->setUInt32(1, account.Game.Id);
740 LoginDatabase.Execute(stmt);
741
742 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
743 if (sWorld->IsClosed())
744 {
746 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", address);
748 return;
749 }
750
751 if (authSession->RealmID != sRealmList->GetCurrentRealmId().Realm)
752 {
754 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
755 address, authSession->RealmID, sRealmList->GetCurrentRealmId().Realm);
757 return;
758 }
759
760 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
761 _ipCountry = location->CountryCode;
762
764 if (account.BattleNet.IsLockedToIP)
765 {
766 if (account.BattleNet.LastIP != address)
767 {
769 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.BattleNet.LastIP, address);
770 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
771 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
773 return;
774 }
775 }
776 else if (!account.BattleNet.LockCountry.empty() && account.BattleNet.LockCountry != "00" && !_ipCountry.empty())
777 {
778 if (account.BattleNet.LockCountry != _ipCountry)
779 {
781 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.BattleNet.LockCountry, _ipCountry);
782 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
783 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
785 return;
786 }
787 }
788
789 int64 mutetime = account.Game.MuteTime;
791 if (mutetime < 0)
792 {
793 mutetime = GameTime::GetGameTime() - mutetime;
794
795 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
796 stmt->setInt64(0, mutetime);
797 stmt->setUInt32(1, account.Game.Id);
798 LoginDatabase.Execute(stmt);
799 }
800
801 if (account.IsBanned())
802 {
804 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
805 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
807 return;
808 }
809
810 // Check locked state for server
811 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
812 TC_LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Game.Security);
813 if (allowedAccountType > SEC_PLAYER && account.Game.Security < allowedAccountType)
814 {
816 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
817 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
819 return;
820 }
821
822 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", joinTicket->gameaccount(), address);
823
825 {
826 // Update the last_ip in the database as it was successful for login
827 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
828
829 stmt->setString(0, address);
830 stmt->setString(1, joinTicket->gameaccount());
831
832 LoginDatabase.Execute(stmt);
833 }
834
835 // At this point, we can safely hook a successful login
836 sScriptMgr->OnAccountLogin(account.Game.Id);
837
838 _authed = true;
839 _worldSession = new WorldSession(account.Game.Id, std::move(*joinTicket->mutable_gameaccount()), account.BattleNet.Id,
840 std::move(account.BattleNet.Email), static_pointer_cast<WorldSocket>(shared_from_this()), account.Game.Security,
841 account.Game.Expansion, mutetime, std::move(account.Game.OS), account.Game.TimezoneOffset, account.Game.Build, buildVariant,
842 account.Game.Locale, account.Game.Recruiter, account.Game.IsRecruiter);
843
845 {
846 LoadSessionPermissionsCallback(std::move(result));
847 }));
849}
850
852{
853 // RBAC must be loaded before adding session to check for skip queue permission
854 _worldSession->GetRBACData()->LoadFromDBCallback(std::move(result));
855
857}
858
860{
862
863 if (_authed)
864 {
865 std::scoped_lock guard(_worldSessionLock);
866 TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_CONTINUED_SESSION from {}", _worldSession->GetPlayerInfo());
868 }
869
870 std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet));
871 if (!authSession->ReadNoThrow())
872 {
873 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_CONTINUED_SESSION", GetRemoteIpAddress());
875 }
876
878 key.Raw = authSession->Key;
879
882 {
886 }
887
888 uint32 accountId = uint32(key.Fields.AccountId);
890 stmt->setUInt32(0, accountId);
891
892 QueueQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession)](PreparedQueryResult const& result) mutable
893 {
894 HandleAuthContinuedSessionCallback(authSession.get(), result.get());
895 }));
897}
898
900{
901 if (!result)
902 {
905 return;
906 }
907
909 _key = key.Raw = authSession->Key;
910
911 uint32 accountId = uint32(key.Fields.AccountId);
912 Field* fields = result->Fetch();
913 std::string login = fields[0].GetString();
915
917 hmac.UpdateData(reinterpret_cast<uint8 const*>(&authSession->Key), sizeof(authSession->Key));
918 hmac.UpdateData(authSession->LocalChallenge);
919 hmac.UpdateData(_serverChallenge);
920 hmac.UpdateData(ContinuedSessionSeed);
921 hmac.Finalize();
922
923 if (memcmp(hmac.GetDigest().data(), authSession->Digest.data(), authSession->Digest.size()))
924 {
925 TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: {} ('{}') address: {}", accountId, login, GetRemoteIpAddress());
927 return;
928 }
929
931 encryptKeyGen.UpdateData(authSession->LocalChallenge);
932 encryptKeyGen.UpdateData(_serverChallenge);
933 encryptKeyGen.UpdateData(EncryptionKeySeed);
934 encryptKeyGen.Finalize();
935
936 // only first 32 bytes of the hmac are used
937 memcpy(_encryptKey.data(), encryptKeyGen.GetDigest().data(), 32);
938
941}
942
944{
945 std::scoped_lock sessionGuard(_worldSessionLock);
946
947 LogOpcodeText(CMSG_KEEP_ALIVE, sessionGuard);
948
949 if (!_worldSession)
950 {
951 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress());
953 }
954
957}
958
960{
962
963 WorldPackets::Auth::LogDisconnect logDisconnect(std::move(packet));
964 if (!logDisconnect.ReadNoThrow())
965 {
966 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_LOG_DISCONNECT", GetRemoteIpAddress());
968 }
969
970 TC_LOG_DEBUG("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_LOG_DISCONNECT reason {}", GetRemoteIpAddress(), logDisconnect.Reason);
972}
973
975{
976 std::scoped_lock sessionGuard(_worldSessionLock);
977
979
980 WorldPackets::Auth::ConnectToFailed connectToFailed(std::move(packet));
981 if (!connectToFailed.ReadNoThrow())
982 {
983 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_CONNECT_TO_FAILED", GetRemoteIpAddress());
985 }
986
987 if (_worldSession)
988 {
990 {
991 switch (connectToFailed.Serial)
992 {
995 break;
998 break;
1001 break;
1004 break;
1006 {
1007 TC_LOG_ERROR("network", "{} failed to connect 5 times to world socket, aborting login", _worldSession->GetPlayerInfo());
1009 break;
1010 }
1011 default:
1012 break;
1013 }
1014 }
1015 //else
1016 //{
1017 // transfer_aborted when/if we get map node redirection
1018 // SendPacketAndLogOpcode(*WorldPackets::Auth::ResumeComms().Write());
1019 //}
1020 }
1021
1023}
1024
1026{
1028
1031 sWorld->AddSession(_worldSession);
1032 else
1033 sWorld->AddInstanceSocket(static_pointer_cast<WorldSocket>(shared_from_this()), _key);
1034
1036}
1037
1039{
1041 response.Result = code;
1042 SendPacketAndLogOpcode(*response.Write());
1043}
1044
1046{
1048
1049 WorldPackets::Auth::Ping ping(std::move(packet));
1050 if (!ping.ReadNoThrow())
1051 {
1052 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress());
1054 }
1055
1056 TimePoint lastPingTime = std::exchange(_lastPingTime, TimePoint::clock::now());
1057
1058 if (lastPingTime != TimePoint())
1059 {
1060 TimePoint::duration diff = _lastPingTime - lastPingTime;
1061
1062 if (diff < 27s)
1063 {
1065
1066 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
1067
1068 if (maxAllowed && _overSpeedPings > maxAllowed)
1069 {
1070 bool ignoresOverspeedPingsLimit = [&]
1071 {
1072 std::scoped_lock sessionGuard(_worldSessionLock);
1074 }();
1075
1076 if (!ignoresOverspeedPingsLimit)
1077 {
1078 TC_LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
1080
1082 }
1083 }
1084 }
1085 else
1086 _overSpeedPings = 0;
1087 }
1088
1089 bool success = [&]
1090 {
1091 std::scoped_lock sessionGuard(_worldSessionLock);
1092 if (_worldSession)
1093 {
1095 return true;
1096 }
1097 return false;
1098 }();
1099
1100 if (!success)
1101 {
1102 TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress());
1104 }
1105
1108}
constexpr size_t SESSION_KEY_LENGTH
Definition AuthDefines.h:24
@ ERROR_GAME_ACCOUNT_BANNED
@ ERROR_RISK_ACCOUNT_LOCKED
@ ERROR_BAD_VERSION
@ ERROR_WOW_SERVICES_INVALID_JOIN_TICKET
@ ERROR_SERVER_IS_PRIVATE
LocaleConstant
Definition Common.h:51
@ TOTAL_LOCALES
Definition Common.h:65
@ LOCALE_enUS
Definition Common.h:52
AccountTypes
Definition Common.h:42
@ SEC_PLAYER
Definition Common.h:43
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define SZFMTD
Definition Define.h:144
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition Duration.h:40
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:32
#define ASSERT
Definition Errors.h:80
#define sIPLocation
Definition IPLocation.h:56
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_TRACE(filterType__, message__,...)
Definition Log.h:178
@ LOGIN_UPD_MUTE_TIME_LOGIN
@ LOGIN_UPD_ACCOUNT_INFO_CONTINUED_SESSION
@ LOGIN_UPD_LAST_ATTEMPT_IP
@ LOGIN_UPD_LAST_IP
@ LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION
@ LOGIN_SEL_ACCOUNT_INFO_BY_NAME
OpcodeTable opcodeTable
Definition Opcodes.cpp:37
ConnectionType
Definition Opcodes.h:27
@ CONNECTION_TYPE_INSTANCE
Definition Opcodes.h:29
@ CONNECTION_TYPE_REALM
Definition Opcodes.h:28
OpcodeServer
Definition Opcodes.h:1085
@ SMSG_COMPRESSED_PACKET
Definition Opcodes.h:1361
constexpr FormattedOpcodeName< OpcodeClient > GetOpcodeNameForLogging(OpcodeClient opcode)
Lookup opcode name for human understandable logging.
Definition Opcodes.h:2603
OpcodeClient
Definition Opcodes.h:38
@ CMSG_TIME_SYNC_RESPONSE
Definition Opcodes.h:989
@ CMSG_CONNECT_TO_FAILED
Definition Opcodes.h:284
@ CMSG_AUTH_CONTINUED_SESSION
Definition Opcodes.h:86
@ CMSG_ENTER_ENCRYPTED_MODE_ACK
Definition Opcodes.h:344
@ CMSG_ENABLE_NAGLE
Definition Opcodes.h:340
@ CMSG_QUEUED_MESSAGES_END
Definition Opcodes.h:802
@ CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE
Definition Opcodes.h:624
@ CMSG_PING
Definition Opcodes.h:754
@ CMSG_LOG_DISCONNECT
Definition Opcodes.h:559
@ CMSG_HOTFIX_REQUEST
Definition Opcodes.h:455
@ CMSG_KEEP_ALIVE
Definition Opcodes.h:518
@ CMSG_AUTH_SESSION
Definition Opcodes.h:87
#define sPacketLog
Definition PacketLog.h:68
@ SERVER_TO_CLIENT
Definition PacketLog.h:27
@ CLIENT_TO_SERVER
Definition PacketLog.h:26
#define DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(result_type, fields_list)
const size_t bufferSize
Definition RASession.h:28
Role Based Access Control related classes definition.
#define sRealmList
Definition RealmList.h:93
#define sScriptMgr
Definition ScriptMgr.h:1449
struct z_stream_s z_stream
Definition WorldSocket.h:37
char const * what() const noexcept override
Definition ByteBuffer.h:36
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
size_t size() const
Definition ByteBuffer.h:568
bool empty() const
Definition ByteBuffer.h:569
uint8 * data()
Definition ByteBuffer.h:565
bool NeedsEncryption() const
Definition WorldSocket.h:52
Class used to access individual fields of database query result.
Definition Field.h:94
std::vector< uint8 > GetBinary() const noexcept
Definition Field.cpp:125
std::string GetString() const noexcept
Definition Field.cpp:113
inline ::google::protobuf::uint32 type() const
inline ::std::string * mutable_gameaccount()
inline ::google::protobuf::uint32 clientarch() const
inline ::google::protobuf::uint32 platform() const
const ::std::string & gameaccount() const
void Resize(size_type bytes)
size_type GetRemainingSpace() const
void ReadCompleted(size_type bytes)
void WriteCompleted(size_type bytes)
uint8 * GetReadPointer()
size_type GetActiveSize() const
uint8 * GetWritePointer()
void Write(void const *data, std::size_t size)
bool IsValid(OpcodeClient index) const
Definition Opcodes.h:2614
Field * Fetch() const
void setBinary(uint8 index, std::vector< uint8 > &&value)
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setInt64(uint8 index, int64 value)
void setInt32(uint8 index, int32 value)
QueryCallback && WithPreparedCallback(std::function< void(PreparedQueryResult)> &&callback)
void Generate(uint8 *buf, uint32 sz)
void UpdateData(uint8 const *data, size_t len)
Definition HMAC.h:108
Digest const & GetDigest() const
Definition HMAC.h:127
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:191
void SetNoDelay(bool enable)
Definition Socket.h:289
bool IsOpen() const
Definition Socket.h:225
boost::asio::ip::address const & GetRemoteIpAddress() const
Definition Socket.h:186
void AsyncRead(Callback &&callback)
Definition Socket.h:202
void QueuePacket(MessageBuffer &&buffer)
Definition Socket.h:216
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:242
MessageBuffer & GetReadBuffer()
Definition Socket.h:252
bool IsInitialized() const
bool PeekDecryptRecv(uint8 *data, size_t length)
void Init(Key const &key)
bool EncryptSend(uint8 *data, size_t length, Trinity::Crypto::AES::Tag &tag)
bool DecryptRecv(uint8 *data, size_t length, Trinity::Crypto::AES::Tag &tag)
void SetReceiveTime(TimePoint receivedTime)
Definition WorldPacket.h:89
uint32 GetOpcode() const
Definition WorldPacket.h:83
void SetOpcode(uint32 opcode)
Definition WorldPacket.h:84
WorldPacket const * Write() override
std::array< uint8, DigestLength > Digest
uint32 Result
the result of the authentication process, possible values are BattlenetRpcErrorCode
WorldPacket const * Write() override
std::array< uint8, DigestLength > Digest
WorldPacket const * Write() override
Player session in the World.
void AbortLogin(WorldPackets::Character::LoginFailureReason reason)
void SendConnectToInstance(WorldPackets::Auth::ConnectToSerial serial)
std::string GetPlayerInfo() const
bool PlayerLoading() const
QueryCallback LoadPermissionsAsync()
bool HasPermission(uint32 permissionId)
void QueuePacket(WorldPacket &&new_packet)
Add an incoming packet to the queue.
void ResetTimeOutTime(bool onlyActive)
void SetLatency(uint32 latency)
rbac::RBACData * GetRBACData()
SessionKey _sessionKey
ConnectionType _type
MessageBuffer _headerBuffer
static std::array< uint8, 32 > const SessionKeySeed
Definition WorldSocket.h:58
TimePoint _lastPingTime
ReadDataHandlerResult HandleKeepAlive()
ConnectionType GetConnectionType() const
bool InitializeCompression()
void LogOpcodeText(OpcodeClient opcode) const
writes network.opcode log
void QueueQuery(QueryCallback &&queryCallback)
bool ReadHeaderHandler()
static std::array< uint8, 32 > const ContinuedSessionSeed
Definition WorldSocket.h:60
ReadDataHandlerResult HandleAuthSession(WorldPacket &&packet)
bool _canRequestHotfixes
bool Update() override
void LoadSessionPermissionsCallback(PreparedQueryResult result)
MessageBuffer _packetBuffer
void SendAuthResponseError(uint32 code)
QueryCallbackProcessor _queryProcessor
WorldPacketCrypt _authCrypt
ReadDataHandlerResult HandleAuthContinuedSession(WorldPacket &&packet)
Socket BaseSocket
Definition WorldSocket.h:92
void Start() override
std::size_t _sendBufferSize
static std::array< uint8, 32 > const AuthCheckSeed
Definition WorldSocket.h:56
Trinity::Net::SocketReadCallbackResult ReadHandler() override
WorldSocket(Trinity::Net::IoContextTcpSocket &&socket)
void SetWorldSession(WorldSession *session)
static std::array< uint8, 32 > const EncryptionKeySeed
Definition WorldSocket.h:62
ReadDataHandlerResult HandlePing(WorldPacket &&packet)
std::array< uint8, 32 > _serverChallenge
WorldSession * _worldSession
uint32 CompressPacket(uint8 *buffer, WorldPacket const &packet)
std::string _ipCountry
z_stream * _compressionStream
void SendPacket(WorldPacket const &packet)
MPSCQueue< EncryptablePacket, &EncryptablePacket::SocketQueueLink > _bufferQueue
std::array< uint8, 32 > _encryptKey
void SendPacketAndLogOpcode(WorldPacket const &packet)
sends and logs network.opcode without accessing WorldSession
ReadDataHandlerResult HandleConnectToFailed(WorldPacket &&packet)
void WritePacketToBuffer(EncryptablePacket const &packet, MessageBuffer &buffer)
ReadDataHandlerResult HandleLogDisconnect(WorldPacket &&packet) const
ReadDataHandlerResult HandleEnterEncryptedModeAck()
std::mutex _worldSessionLock
void OnClose() override
void HandleAuthSessionCallback(WorldPackets::Auth::AuthSession const *authSession, JSON::RealmList::RealmJoinTicket *joinTicket, PreparedResultSet const *result)
ReadDataHandlerResult ReadDataHandler()
void SendAuthSession()
void HandleAuthContinuedSessionCallback(WorldPackets::Auth::AuthContinuedSession const *authSession, PreparedResultSet const *result)
uint32 _overSpeedPings
static uint32 const MinSizeForCompression
Definition WorldSocket.h:85
void LoadFromDBCallback(PreparedQueryResult result)
Definition RBAC.cpp:213
#define sWorld
Definition World.h:916
@ CONFIG_MAX_OVERSPEED_PINGS
Definition World.h:305
@ CONFIG_COMPRESSION
Definition World.h:237
@ CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE
Definition World.h:196
Info const * GetBuildInfo(uint32 build)
std::array< char, 5 > ToCharArray(uint32 value)
time_t GetGameTime()
Definition GameTime.cpp:52
TC_SHARED_API bool Deserialize(std::string const &json, google::protobuf::Message *message)
std::array< uint8, S > GetRandomBytes()
SocketReadCallbackResult
Definition Socket.h:49
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
Definition Socket.h:40
@ RBAC_PERM_SKIP_CHECK_OVERSPEED_PING
Definition RBAC.h:76
STL namespace.
std::string LockCountry
std::string OS
LocaleConstant Locale
bool IsBanned() const
AccountInfo(PreparedResultSet const *result)
AccountTypes Security
struct AccountInfo::@320 Game
std::array< uint8, 64 > KeyData
std::string LastIP
Minutes TimezoneOffset
struct AccountInfo::@319 BattleNet
std::string Email
std::vector< AuthKey > AuthKeys
uint8 Tag[12]
Definition WorldSocket.h:71
bool IsValidSize() const
Definition WorldSocket.h:73
static std::shared_ptr< SocketConnectionInitializer > & SetupChain(std::span< std::shared_ptr< SocketConnectionInitializer > > initializers)
Trinity::Net::SocketReadCallbackResult ReadHandler()
static constexpr std::string_view ServerConnectionInitialize
WorldSocketProtocolInitializer(WorldSocket *socket)
static constexpr std::string_view ClientConnectionInitialize
struct WorldSession::ConnectToKey::@318 Fields