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;
205 if (_bufferQueue.Dequeue(queued))
206 {
207 // Allocate buffer only when it's needed but not on every Update() call.
209 do
210 {
211 uint32 packetSize = queued->size() + 4 /*opcode*/;
212 if (packetSize > MinSizeForCompression && queued->NeedsEncryption())
213 packetSize = deflateBound(_compressionStream, packetSize) + sizeof(CompressedWorldPacket);
214
215 // Flush current buffer if too small for next packet
216 if (buffer.GetRemainingSpace() < packetSize + sizeof(PacketHeader))
217 {
218 QueuePacket(std::move(buffer));
219 buffer.Resize(_sendBufferSize);
220 }
221
222 if (buffer.GetRemainingSpace() >= packetSize + sizeof(PacketHeader))
223 WritePacketToBuffer(*queued, buffer);
224 else // single packet larger than _sendBufferSize
225 {
226 MessageBuffer packetBuffer(packetSize + sizeof(PacketHeader));
227 WritePacketToBuffer(*queued, packetBuffer);
228 QueuePacket(std::move(packetBuffer));
229 }
230
231 delete queued;
232 } while (_bufferQueue.Dequeue(queued));
233
234 if (buffer.GetActiveSize() > 0)
235 QueuePacket(std::move(buffer));
236 }
237
238 if (!BaseSocket::Update())
239 return false;
240
242
243 return true;
244}
245
247{
249
251 challenge.Challenge = _serverChallenge;
252 memcpy(challenge.DosChallenge.data(), Trinity::Crypto::GetRandomBytes<32>().data(), 32);
253 challenge.DosZeroBits = 1;
254
255 SendPacketAndLogOpcode(*challenge.Write());
256}
257
259{
260 {
261 std::scoped_lock sessionGuard(_worldSessionLock);
262 _worldSession = nullptr;
263 }
264}
265
267{
268 MessageBuffer& packet = GetReadBuffer();
269 while (packet.GetActiveSize() > 0)
270 {
272 {
273 // need to receive the header
274 std::size_t readHeaderSize = std::min(packet.GetActiveSize(), _headerBuffer.GetRemainingSpace());
275 _headerBuffer.Write(packet.GetReadPointer(), readHeaderSize);
276 packet.ReadCompleted(readHeaderSize);
277
279 {
280 // Couldn't receive the whole header this time.
281 ASSERT(packet.GetActiveSize() == 0);
282 break;
283 }
284
285 // We just received nice new header
286 if (!ReadHeaderHandler())
287 {
288 CloseSocket();
290 }
291 }
292
293 // We have full read header, now check the data payload
295 {
296 // need more data in the payload
297 std::size_t readDataSize = std::min(packet.GetActiveSize(), _packetBuffer.GetRemainingSpace());
298 _packetBuffer.Write(packet.GetReadPointer(), readDataSize);
299 packet.ReadCompleted(readDataSize);
300
302 {
303 // Couldn't receive the whole data this time.
304 ASSERT(packet.GetActiveSize() == 0);
305 break;
306 }
307 }
308
309 // just received fresh new payload
312 if (result != ReadDataHandlerResult::Ok)
313 {
315 CloseSocket();
316
318 }
319 }
320
322}
323
325{
326 _queryProcessor.AddCallback(std::move(queryCallback));
327}
328
330{
331 std::scoped_lock sessionGuard(_worldSessionLock);
332 _worldSession = session;
333 _authed = true;
334}
335
337{
338 ASSERT(_headerBuffer.GetActiveSize() == sizeof(IncomingPacketHeader), "Header size " SZFMTD " different than expected " SZFMTD, _headerBuffer.GetActiveSize(), sizeof(IncomingPacketHeader));
339
341 uint32 encryptedOpcode = header->EncryptedOpcode;
342
343 if (!header->IsValidSize())
344 {
345 _authCrypt.PeekDecryptRecv(reinterpret_cast<uint8*>(&header->EncryptedOpcode), sizeof(encryptedOpcode));
346
347 // CMSG_HOTFIX_REQUEST can be much larger than normal packets, allow receiving it once per session
348 if (header->EncryptedOpcode != CMSG_HOTFIX_REQUEST || header->Size > 0x100000 || !_canRequestHotfixes)
349 {
350 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent malformed packet (size: {}, opcode {})",
351 GetRemoteIpAddress(), header->Size, uint32(header->EncryptedOpcode));
352 return false;
353 }
354 }
355
356 _packetBuffer.Resize(header->Size);
357 _packetBuffer.Write(&encryptedOpcode, sizeof(encryptedOpcode));
358 return true;
359}
360
362{
363 PacketHeader* header = reinterpret_cast<PacketHeader*>(_headerBuffer.GetReadPointer());
364
365 if (!_authCrypt.DecryptRecv(_packetBuffer.GetReadPointer(), header->Size, header->Tag))
366 {
367 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} failed to decrypt packet (size: {})",
368 GetRemoteIpAddress(), header->Size);
370 }
371
372 WorldPacket packet(std::move(_packetBuffer).Release(), GetConnectionType());
373 OpcodeClient opcode = packet.read<OpcodeClient>();
374 if (!opcodeTable.IsValid(opcode))
375 {
376 TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client {} sent wrong opcode (opcode: {})",
377 GetRemoteIpAddress(), uint32(opcode));
379 }
380
381 packet.SetOpcode(opcode);
382
383 if (sPacketLog->CanLogPacket())
385
386 switch (opcode)
387 {
388 case CMSG_PING:
389 return HandlePing(std::move(packet));
391 return HandleAuthSession(std::move(packet));
393 return HandleAuthContinuedSession(std::move(packet));
394 case CMSG_KEEP_ALIVE:
395 return HandleKeepAlive();
397 return HandleLogDisconnect(std::move(packet));
400 SetNoDelay(false);
401 break;
403 return HandleConnectToFailed(std::move(packet));
406 default:
407 {
409 packet.SetReceiveTime(std::chrono::steady_clock::now());
410 else if (opcode == CMSG_HOTFIX_REQUEST)
411 _canRequestHotfixes = false;
412
413 std::scoped_lock sessionGuard(_worldSessionLock);
414
415 LogOpcodeText(opcode, sessionGuard);
416
417 if (!_worldSession)
418 {
419 TC_LOG_ERROR("network.opcode", "WorldSocket::ReadDataHandler: Client not authed opcode {}", GetOpcodeNameForLogging(opcode));
421 }
422
423 if (!opcodeTable[opcode])
424 {
425 TC_LOG_ERROR("network.opcode", "WorldSocket::ReadDataHandler: No defined handler for opcode {} sent by {}", GetOpcodeNameForLogging(opcode), _worldSession->GetPlayerInfo());
426 break;
427 }
428
429 // Our Idle timer will reset on any non PING opcodes on login screen, allowing us to catch people idling.
431
432 _worldSession->QueuePacket(std::move(packet));
433 break;
434 }
435 }
436
438}
439
441{
442 TC_LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(opcode));
443}
444
445void WorldSocket::LogOpcodeText(OpcodeClient opcode, std::scoped_lock<std::mutex> const& /*guard*/) const
446{
447 if (!_worldSession)
448 {
449 TC_LOG_TRACE("network.opcode", "C->S: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(opcode));
450 }
451 else
452 {
453 TC_LOG_TRACE("network.opcode", "C->S: {} {}", _worldSession->GetPlayerInfo(), GetOpcodeNameForLogging(opcode));
454 }
455}
456
458{
459 TC_LOG_TRACE("network.opcode", "S->C: {} {}", GetRemoteIpAddress(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())));
460 SendPacket(packet);
461}
462
464{
465 if (!IsOpen())
466 return;
467
468 if (sPacketLog->CanLogPacket())
470
472}
473
475{
476 uint32 opcode = packet.GetOpcode();
477 uint32 packetSize = packet.size();
478
479 // Reserve space for buffer
480 uint8* headerPos = buffer.GetWritePointer();
481 buffer.WriteCompleted(sizeof(PacketHeader));
482 uint8* dataPos = buffer.GetWritePointer();
483 buffer.WriteCompleted(sizeof(opcode));
484
485 if (packetSize > MinSizeForCompression && packet.NeedsEncryption())
486 {
488 cmp.UncompressedSize = packetSize + sizeof(opcode);
489 cmp.UncompressedAdler = adler32(adler32(0x9827D8F1, (Bytef*)&opcode, sizeof(opcode)), packet.data(), packetSize);
490
491 // Reserve space for compression info - uncompressed size and checksums
492 uint8* compressionInfo = buffer.GetWritePointer();
494
495 uint32 compressedSize = CompressPacket(buffer.GetWritePointer(), packet);
496
497 cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize);
498
499 memcpy(compressionInfo, &cmp, sizeof(CompressedWorldPacket));
500 buffer.WriteCompleted(compressedSize);
501 packetSize = compressedSize + sizeof(CompressedWorldPacket);
502
503 opcode = SMSG_COMPRESSED_PACKET;
504 }
505 else if (!packet.empty())
506 buffer.Write(packet.data(), packet.size());
507
508 memcpy(dataPos, &opcode, sizeof(opcode));
509 packetSize += sizeof(opcode);
510
511 PacketHeader header;
512 header.Size = packetSize;
513 _authCrypt.EncryptSend(dataPos, header.Size, header.Tag);
514
515 memcpy(headerPos, &header, sizeof(PacketHeader));
516}
517
519{
520 uint32 opcode = packet.GetOpcode();
521 uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode));
522
523 _compressionStream->next_out = buffer;
524 _compressionStream->avail_out = bufferSize;
525 _compressionStream->next_in = (Bytef*)&opcode;
526 _compressionStream->avail_in = sizeof(opcode);
527
528 int32 z_res = deflate(_compressionStream, Z_NO_FLUSH);
529 if (z_res != Z_OK)
530 {
531 TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: {} ({}, msg: {})", z_res, zError(z_res), _compressionStream->msg);
532 return 0;
533 }
534
535 _compressionStream->next_in = (Bytef*)packet.data();
536 _compressionStream->avail_in = packet.size();
537
538 z_res = deflate(_compressionStream, Z_SYNC_FLUSH);
539 if (z_res != Z_OK)
540 {
541 TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: {} ({}, msg: {})", z_res, zError(z_res), _compressionStream->msg);
542 return 0;
543 }
544
545 return bufferSize - _compressionStream->avail_out;
546}
547
549{
550 struct
551 {
553 std::string Email;
555 std::string LastIP;
556 std::string LockCountry;
559
560 struct
561 {
562 uint32 Id;
563 std::array<uint8, 64> KeyData;
569 std::string OS;
573 bool IsBanned;
575
576 bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; }
577
578 explicit AccountInfo(PreparedResultSet const* result)
579 {
580 // 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,
581 // 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
582 // FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id
583 // 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
584 // WHERE a.username = ? AND LENGTH(a.session_key_bnet) = 64 ORDER BY aa.RealmID DESC LIMIT 1
585
586 DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (account_id)(session_key_bnet)(last_ip)(locked)(lock_country)(expansion)(mutetime)(client_build)
587 (locale)(recruiter)(os)(timezone_offset)(bnet_account_id)(bnet_account_email)(SecurityLevel)(is_bnet_banned)(is_banned)(recruitId)) fields { *result };
588
589 Game.Id = fields.account_id().GetUInt32();
590 Game.KeyData = fields.session_key_bnet().GetBinary<64>();
591 BattleNet.LastIP = fields.last_ip().GetStringView();
592 BattleNet.IsLockedToIP = fields.locked().GetBool();
593 BattleNet.LockCountry = fields.lock_country().GetStringView();
594 Game.Expansion = fields.expansion().GetUInt8();
595 Game.MuteTime = fields.mutetime().GetInt64();
596 Game.Build = fields.client_build().GetUInt32();
597 Game.Locale = LocaleConstant(fields.locale().GetUInt8());
598 Game.Recruiter = fields.recruiter().GetUInt32();
599 Game.OS = fields.os().GetStringView();
600 Game.TimezoneOffset = Minutes(fields.timezone_offset().GetInt16());
601 BattleNet.Id = fields.bnet_account_id().GetUInt32();
602 BattleNet.Email = fields.bnet_account_email().GetStringView();
603 Game.Security = AccountTypes(fields.SecurityLevel().GetUInt8());
604 BattleNet.IsBanned = fields.is_bnet_banned().GetUInt32() != 0;
605 Game.IsBanned = fields.is_banned().GetUInt32() != 0;
606 Game.IsRecruiter = fields.recruitId().GetUInt32() != 0;
607
608 if (Game.Locale >= TOTAL_LOCALES)
609 Game.Locale = LOCALE_enUS;
610 }
611};
612
614{
616
617 if (_authed)
618 {
619 std::scoped_lock guard(_worldSessionLock);
620 TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from {}", _worldSession->GetPlayerInfo());
622 }
623
624 std::shared_ptr callbackData = std::make_shared<std::pair<WorldPackets::Auth::AuthSession, JSON::RealmList::RealmJoinTicket>>(
625 std::piecewise_construct, std::forward_as_tuple(std::move(packet)), std::forward_as_tuple());
626 if (!callbackData->first.ReadNoThrow())
627 {
628 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress());
630 }
631
632 if (!JSON::Deserialize(callbackData->first.RealmJoinTicket, &callbackData->second))
633 {
637 }
638
639 // Get the account information from the auth database
641 stmt->setInt32(0, int32(sRealmList->GetCurrentRealmId().Realm));
642 stmt->setString(1, callbackData->second.gameaccount());
643
644 QueueQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, callbackData = std::move(callbackData)](PreparedQueryResult const& result) mutable
645 {
646 HandleAuthSessionCallback(&callbackData->first, &callbackData->second, result.get());
647 }));
649}
650
651void WorldSocket::HandleAuthSessionCallback(WorldPackets::Auth::AuthSession const* authSession, JSON::RealmList::RealmJoinTicket* joinTicket, PreparedResultSet const* result)
652{
653 // Stop if the account is not found
654 if (!result)
655 {
656 // We can not log here, as we do not know the account. Thus, no accountId.
657 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
659 return;
660 }
661
662 std::string address = GetRemoteIpAddress().to_string();
663
664 AccountInfo account(result);
665
666 ClientBuild::Info const* buildInfo = ClientBuild::GetBuildInfo(account.Game.Build);
667 if (!buildInfo)
668 {
670 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build info for build {} ({}).", account.Game.Build, address);
672 return;
673 }
674
675 ClientBuild::VariantId buildVariant =
676 {
677 .Platform = ClientBuild::Platform::Id(joinTicket->platform()),
678 .Arch = ClientBuild::Arch::Id(joinTicket->clientarch()),
679 .Type = ClientBuild::Type::Id(joinTicket->type())
680 };
681 auto clientBuildAuthKey = std::ranges::find(buildInfo->AuthKeys, buildVariant, &ClientBuild::AuthKey::Variant);
682 if (clientBuildAuthKey == buildInfo->AuthKeys.end())
683 {
685 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Missing client build auth key for build {} variant {}-{}-{} ({}).", account.Game.Build,
686 buildVariant.Platform, buildVariant.Arch, buildVariant.Type, address);
688 return;
689 }
690
691 Trinity::Crypto::SHA512 digestKeyHash;
692 digestKeyHash.UpdateData(account.Game.KeyData.data(), account.Game.KeyData.size());
693 digestKeyHash.UpdateData(clientBuildAuthKey->Key.data(), clientBuildAuthKey->Key.size());
694 digestKeyHash.Finalize();
695
696 Trinity::Crypto::HMAC_SHA512 hmac(digestKeyHash.GetDigest());
697 hmac.UpdateData(authSession->LocalChallenge);
700 hmac.Finalize();
701
702 // Check that Key and account name are the same on client and server
703 if (memcmp(hmac.GetDigest().data(), authSession->Digest.data(), authSession->Digest.size()) != 0)
704 {
706 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: {} ('{}') address: {}", account.Game.Id, joinTicket->gameaccount(), address);
708 return;
709 }
710
712 keyData.UpdateData(account.Game.KeyData.data(), account.Game.KeyData.size());
713 keyData.Finalize();
714
715 Trinity::Crypto::HMAC_SHA512 sessionKeyHmac(keyData.GetDigest());
716 sessionKeyHmac.UpdateData(_serverChallenge);
717 sessionKeyHmac.UpdateData(authSession->LocalChallenge);
718 sessionKeyHmac.UpdateData(SessionKeySeed);
719 sessionKeyHmac.Finalize();
720
721 SessionKeyGenerator<Trinity::Crypto::SHA512> sessionKeyGenerator(sessionKeyHmac.GetDigest());
722 sessionKeyGenerator.Generate(_sessionKey.data(), 40);
723
725 encryptKeyGen.UpdateData(authSession->LocalChallenge);
726 encryptKeyGen.UpdateData(_serverChallenge);
727 encryptKeyGen.UpdateData(EncryptionKeySeed);
728 encryptKeyGen.Finalize();
729
730 // only first 32 bytes of the hmac are used
731 memcpy(_encryptKey.data(), encryptKeyGen.GetDigest().data(), 32);
732
733 LoginDatabasePreparedStatement* stmt = nullptr;
734
736 {
737 // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
738 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
739 stmt->setString(0, address);
740 stmt->setString(1, joinTicket->gameaccount());
741 LoginDatabase.Execute(stmt);
742 // This also allows to check for possible "hack" attempts on account
743 }
744
745 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_INFO_CONTINUED_SESSION);
746 stmt->setBinary(0, _sessionKey);
747 stmt->setUInt32(1, account.Game.Id);
748 LoginDatabase.Execute(stmt);
749
750 // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
751 if (sWorld->IsClosed())
752 {
754 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client ({}).", address);
756 return;
757 }
758
759 if (authSession->RealmID != sRealmList->GetCurrentRealmId().Realm)
760 {
762 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
763 address, authSession->RealmID, sRealmList->GetCurrentRealmId().Realm);
765 return;
766 }
767
768 if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(address))
769 _ipCountry = location->CountryCode;
770
772 if (account.BattleNet.IsLockedToIP)
773 {
774 if (account.BattleNet.LastIP != address)
775 {
777 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: {}, new IP: {}).", account.BattleNet.LastIP, address);
778 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
779 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
781 return;
782 }
783 }
784 else if (!account.BattleNet.LockCountry.empty() && account.BattleNet.LockCountry != "00" && !_ipCountry.empty())
785 {
786 if (account.BattleNet.LockCountry != _ipCountry)
787 {
789 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: {}, new country: {}).", account.BattleNet.LockCountry, _ipCountry);
790 // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
791 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
793 return;
794 }
795 }
796
797 int64 mutetime = account.Game.MuteTime;
799 if (mutetime < 0)
800 {
801 mutetime = GameTime::GetGameTime() - mutetime;
802
803 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
804 stmt->setInt64(0, mutetime);
805 stmt->setUInt32(1, account.Game.Id);
806 LoginDatabase.Execute(stmt);
807 }
808
809 if (account.IsBanned())
810 {
812 TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
813 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
815 return;
816 }
817
818 // Check locked state for server
819 AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
820 TC_LOG_DEBUG("network", "Allowed Level: {} Player Level {}", allowedAccountType, account.Game.Security);
821 if (allowedAccountType > SEC_PLAYER && account.Game.Security < allowedAccountType)
822 {
824 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
825 sScriptMgr->OnFailedAccountLogin(account.Game.Id);
827 return;
828 }
829
830 TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '{}' authenticated successfully from {}.", joinTicket->gameaccount(), address);
831
833 {
834 // Update the last_ip in the database as it was successful for login
835 stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
836
837 stmt->setString(0, address);
838 stmt->setString(1, joinTicket->gameaccount());
839
840 LoginDatabase.Execute(stmt);
841 }
842
843 // At this point, we can safely hook a successful login
844 sScriptMgr->OnAccountLogin(account.Game.Id);
845
846 _authed = true;
847 _worldSession = new WorldSession(account.Game.Id, std::move(*joinTicket->mutable_gameaccount()), account.BattleNet.Id,
848 std::move(account.BattleNet.Email), static_pointer_cast<WorldSocket>(shared_from_this()), account.Game.Security,
849 account.Game.Expansion, mutetime, std::move(account.Game.OS), account.Game.TimezoneOffset, account.Game.Build, buildVariant,
850 account.Game.Locale, account.Game.Recruiter, account.Game.IsRecruiter);
851
853 {
854 LoadSessionPermissionsCallback(std::move(result));
855 }));
857}
858
860{
861 // RBAC must be loaded before adding session to check for skip queue permission
862 _worldSession->GetRBACData()->LoadFromDBCallback(std::move(result));
863
865}
866
868{
870
871 if (_authed)
872 {
873 std::scoped_lock guard(_worldSessionLock);
874 TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_CONTINUED_SESSION from {}", _worldSession->GetPlayerInfo());
876 }
877
878 std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet));
879 if (!authSession->ReadNoThrow())
880 {
881 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_AUTH_CONTINUED_SESSION", GetRemoteIpAddress());
883 }
884
886 key.Raw = authSession->Key;
887
890 {
894 }
895
896 uint32 accountId = uint32(key.Fields.AccountId);
898 stmt->setUInt32(0, accountId);
899
900 QueueQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession)](PreparedQueryResult const& result) mutable
901 {
902 HandleAuthContinuedSessionCallback(authSession.get(), result.get());
903 }));
905}
906
908{
909 if (!result)
910 {
913 return;
914 }
915
917 _key = key.Raw = authSession->Key;
918
919 uint32 accountId = uint32(key.Fields.AccountId);
920 Field* fields = result->Fetch();
921 std::string login = fields[0].GetString();
923
925 hmac.UpdateData(reinterpret_cast<uint8 const*>(&authSession->Key), sizeof(authSession->Key));
926 hmac.UpdateData(authSession->LocalChallenge);
927 hmac.UpdateData(_serverChallenge);
928 hmac.UpdateData(ContinuedSessionSeed);
929 hmac.Finalize();
930
931 if (memcmp(hmac.GetDigest().data(), authSession->Digest.data(), authSession->Digest.size()))
932 {
933 TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: {} ('{}') address: {}", accountId, login, GetRemoteIpAddress());
935 return;
936 }
937
939 encryptKeyGen.UpdateData(authSession->LocalChallenge);
940 encryptKeyGen.UpdateData(_serverChallenge);
941 encryptKeyGen.UpdateData(EncryptionKeySeed);
942 encryptKeyGen.Finalize();
943
944 // only first 32 bytes of the hmac are used
945 memcpy(_encryptKey.data(), encryptKeyGen.GetDigest().data(), 32);
946
949}
950
952{
953 std::scoped_lock sessionGuard(_worldSessionLock);
954
955 LogOpcodeText(CMSG_KEEP_ALIVE, sessionGuard);
956
957 if (!_worldSession)
958 {
959 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_KEEP_ALIVE without being authenticated", GetRemoteIpAddress());
961 }
962
965}
966
968{
970
971 WorldPackets::Auth::LogDisconnect logDisconnect(std::move(packet));
972 if (!logDisconnect.ReadNoThrow())
973 {
974 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_LOG_DISCONNECT", GetRemoteIpAddress());
976 }
977
978 TC_LOG_DEBUG("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_LOG_DISCONNECT reason {}", GetRemoteIpAddress(), logDisconnect.Reason);
980}
981
983{
984 std::scoped_lock sessionGuard(_worldSessionLock);
985
987
988 WorldPackets::Auth::ConnectToFailed connectToFailed(std::move(packet));
989 if (!connectToFailed.ReadNoThrow())
990 {
991 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_CONNECT_TO_FAILED", GetRemoteIpAddress());
993 }
994
995 if (_worldSession)
996 {
998 {
999 switch (connectToFailed.Serial)
1000 {
1003 break;
1006 break;
1009 break;
1012 break;
1014 {
1015 TC_LOG_ERROR("network", "{} failed to connect 5 times to world socket, aborting login", _worldSession->GetPlayerInfo());
1017 break;
1018 }
1019 default:
1020 break;
1021 }
1022 }
1023 //else
1024 //{
1025 // transfer_aborted when/if we get map node redirection
1026 // SendPacketAndLogOpcode(*WorldPackets::Auth::ResumeComms().Write());
1027 //}
1028 }
1029
1031}
1032
1034{
1036
1039 sWorld->AddSession(_worldSession);
1040 else
1041 sWorld->AddInstanceSocket(static_pointer_cast<WorldSocket>(shared_from_this()), _key);
1042
1044}
1045
1047{
1049 response.Result = code;
1050 SendPacketAndLogOpcode(*response.Write());
1051}
1052
1054{
1056
1057 WorldPackets::Auth::Ping ping(std::move(packet));
1058 if (!ping.ReadNoThrow())
1059 {
1060 TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress());
1062 }
1063
1064 TimePoint lastPingTime = std::exchange(_lastPingTime, TimePoint::clock::now());
1065
1066 if (lastPingTime != TimePoint())
1067 {
1068 TimePoint::duration diff = _lastPingTime - lastPingTime;
1069
1070 if (diff < 27s)
1071 {
1073
1074 uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS);
1075
1076 if (maxAllowed && _overSpeedPings > maxAllowed)
1077 {
1078 bool ignoresOverspeedPingsLimit = [&]
1079 {
1080 std::scoped_lock sessionGuard(_worldSessionLock);
1082 }();
1083
1084 if (!ignoresOverspeedPingsLimit)
1085 {
1086 TC_LOG_ERROR("network", "WorldSocket::HandlePing: {} kicked for over-speed pings (address: {})",
1088
1090 }
1091 }
1092 }
1093 else
1094 _overSpeedPings = 0;
1095 }
1096
1097 bool success = [&]
1098 {
1099 std::scoped_lock sessionGuard(_worldSessionLock);
1100 if (_worldSession)
1101 {
1103 return true;
1104 }
1105 return false;
1106 }();
1107
1108 if (!success)
1109 {
1110 TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = {}", GetRemoteIpAddress());
1112 }
1113
1116}
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:72
#define sIPLocation
Definition IPLocation.h:56
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_TRACE(filterType__, message__,...)
Definition Log.h:170
@ 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:1105
@ SMSG_COMPRESSED_PACKET
Definition Opcodes.h:1383
constexpr FormattedOpcodeName< OpcodeClient > GetOpcodeNameForLogging(OpcodeClient opcode)
Lookup opcode name for human understandable logging.
Definition Opcodes.h:2639
OpcodeClient
Definition Opcodes.h:38
@ CMSG_TIME_SYNC_RESPONSE
Definition Opcodes.h:1008
@ CMSG_CONNECT_TO_FAILED
Definition Opcodes.h:285
@ CMSG_AUTH_CONTINUED_SESSION
Definition Opcodes.h:86
@ CMSG_ENTER_ENCRYPTED_MODE_ACK
Definition Opcodes.h:350
@ CMSG_ENABLE_NAGLE
Definition Opcodes.h:346
@ CMSG_QUEUED_MESSAGES_END
Definition Opcodes.h:819
@ CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE
Definition Opcodes.h:641
@ CMSG_PING
Definition Opcodes.h:771
@ CMSG_LOG_DISCONNECT
Definition Opcodes.h:576
@ CMSG_HOTFIX_REQUEST
Definition Opcodes.h:462
@ CMSG_KEEP_ALIVE
Definition Opcodes.h:534
@ 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:95
#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:37
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
size_t size() const
Definition ByteBuffer.h:580
bool empty() const
Definition ByteBuffer.h:581
uint8 * data()
Definition ByteBuffer.h:577
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
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:2650
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:192
void SetNoDelay(bool enable)
Definition Socket.h:290
bool IsOpen() const
Definition Socket.h:226
boost::asio::ip::address const & GetRemoteIpAddress() const
Definition Socket.h:187
void AsyncRead(Callback &&callback)
Definition Socket.h:203
void QueuePacket(MessageBuffer &&buffer)
Definition Socket.h:217
void DelayedCloseSocket()
Marks the socket for closing after write buffer becomes empty.
Definition Socket.h:243
MessageBuffer & GetReadBuffer()
Definition Socket.h:253
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:68
uint32 GetOpcode() const
Definition WorldPacket.h:62
void SetOpcode(uint32 opcode)
Definition WorldPacket.h:63
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)
rbac::RBACData * GetRBACData() const
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)
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:919
@ CONFIG_MAX_OVERSPEED_PINGS
Definition World.h:305
@ CONFIG_COMPRESSION
Definition World.h:238
@ CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE
Definition World.h:196
Info const * GetBuildInfo(uint32 build)
time_t GetGameTime()
Definition GameTime.cpp:52
TC_SHARED_API bool Deserialize(std::string_view json, google::protobuf::Message *message)
std::array< uint8, S > GetRandomBytes()
SocketReadCallbackResult
Definition Socket.h:49
boost::asio::basic_stream_socket< boost::asio::ip::tcp, Asio::IoContextExecutor > 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)
struct AccountInfo::@322 Game
AccountTypes Security
std::array< uint8, 64 > KeyData
std::string LastIP
struct AccountInfo::@321 BattleNet
Minutes TimezoneOffset
std::string Email
FourCC< Arch > Id
std::vector< AuthKey > AuthKeys
FourCC< Platform > Id
FourCC< Type > Id
ClientBuild::Type::Id Type
ClientBuild::Arch::Id Arch
ClientBuild::Platform::Id Platform
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::@320 Fields