diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index ce0adffb9..fef9fa5fd 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -4001,7 +4001,7 @@ void ObjectMgr::LoadQuests() // 80 81 82 83 "`ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`, `ReqCurrencyCount1`," // 84 85 86 87 88 - "`ReqSpellCast1`, `ReqSpellCast2`, `ReqSpellCast3`, `ReqSpellCast4`, `ReqSpellLearnedv`," + "`ReqSpellCast1`, `ReqSpellCast2`, `ReqSpellCast3`, `ReqSpellCast4`, `ReqSpellLearned`," // 89 90 91 92 93 94 "`RewChoiceItemId1`, `RewChoiceItemId2`, `RewChoiceItemId3`, `RewChoiceItemId4`, `RewChoiceItemId5`, `RewChoiceItemId6`," // 95 96 97 98 99 100 diff --git a/src/game/Server/WorldSocket.cpp b/src/game/Server/WorldSocket.cpp index faf47fc1d..6d81e910b 100644 --- a/src/game/Server/WorldSocket.cpp +++ b/src/game/Server/WorldSocket.cpp @@ -841,21 +841,30 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; - uint16 clientBuild, security; - uint32 id, m_addonSize, clientSeed, expansion; - std::string accountName; + uint32 clientSeed, id, security; + uint32 m_addonSize; + uint16 BuiltNumberClient; + uint8 expansion = 0; LocaleConstant locale; - + std::string account; Sha1Hash sha1; BigNumber v, s, g, N, K; + std::string os; WorldPacket packet; + bool wardenActive = (sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) || sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED)); + // Read the content of the packet recvPacket.read_skip(); recvPacket.read_skip(); recvPacket >> digest[18]; recvPacket >> digest[14]; recvPacket >> digest[3]; - recvPacket >> digest[4]; + recvPacket >> BuiltNumberClient; + recvPacket >> digest[8]; + recvPacket.read_skip(); + recvPacket.read_skip(); + recvPacket >> digest[17]; + recvPacket >> digest[6]; recvPacket >> digest[0]; recvPacket.read_skip(); recvPacket >> digest[11]; @@ -886,15 +895,21 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) addonsData.resize(m_addonSize); recvPacket.read((uint8*)addonsData.contents(), m_addonSize); - accountName = recvPacket.ReadString(recvPacket.ReadBits(11)); + uint8 nameLenLow, nameLenHigh; + recvPacket >> nameLenHigh; + recvPacket >> nameLenLow; + + uint8 accNameLen = (nameLenHigh << 5) | (nameLenLow >> 3); + + account = recvPacket.ReadString(accNameLen); DEBUG_LOG("WorldSocket::HandleAuthSession: client build %u, account %s, clientseed %X", - clientBuild, - accountName.c_str(), - clientSeed); + BuiltNumberClient, + account.c_str(), + clientSeed); // Check the version of client trying to connect - if(!IsAcceptableClientBuild(clientBuild)) + if (!IsAcceptableClientBuild(BuiltNumberClient)) { SendAuthResponseError(AUTH_VERSION_MISMATCH); sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (version mismatch)."); @@ -902,7 +917,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) } // Get the account information from the realmd database - std::string safe_account = accountName; // Duplicate, else will screw the SHA hash verification below + std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below LoginDatabase.escape_string (safe_account); // No SQL injection, username escaped. @@ -917,7 +932,8 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) "`s`, " // 6 "`expansion`, " // 7 "`mutetime`, " // 8 - "`locale` " // 9 + "`locale`, " // 9 + "`os` " // 10 "FROM `account` " "WHERE `username` = '%s'", safe_account.c_str()); @@ -1017,7 +1033,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) uint32 t = 0; uint32 seed = m_Seed; - sha.UpdateData (accountName); + sha.UpdateData (account); sha.UpdateData((uint8*) & t, 4); sha.UpdateData((uint8*) & clientSeed, 4); sha.UpdateData((uint8*) & seed, 4); @@ -1042,7 +1058,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) static SqlStatementID updAccount; SqlStatement stmt = LoginDatabase.CreateStatement(updAccount, "UPDATE `account` SET `last_ip` = ? WHERE `username` = ?"); - stmt.PExecute(address.c_str(), accountName.c_str()); + stmt.PExecute(address.c_str(), account.c_str()); // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale), -1); @@ -1054,7 +1070,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) m_Session->ReadAddonsInfo(addonsData); // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec - ACE_OS::sleep (ACE_Time_Value (0, 10000)); + ACE_OS::sleep(ACE_Time_Value(0, 10000)); + + // Warden: Initialize Warden system only if it is enabled by config + if (wardenActive) + m_Session->InitWarden(uint16(BuiltNumberClient), &K, os); sWorld.AddSession(m_Session); diff --git a/src/game/Warden/Warden.cpp b/src/game/Warden/Warden.cpp index e0e910db2..97dded50e 100644 --- a/src/game/Warden/Warden.cpp +++ b/src/game/Warden/Warden.cpp @@ -36,11 +36,12 @@ #include "AccountMgr.h" Warden::Warden() : _session(NULL), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), - _dataSent(false), _previousTimestamp(0), _module(NULL), _initialized(false) + _module(NULL), _state(WardenState::STATE_INITIAL) { memset(_inputKey, 0, sizeof(_inputKey)); memset(_outputKey, 0, sizeof(_outputKey)); memset(_seed, 0, sizeof(_seed)); + _previousTimestamp = WorldTimer::getMSTime(); } Warden::~Warden() @@ -48,7 +49,11 @@ Warden::~Warden() delete[] _module->CompressedData; delete _module; _module = NULL; - _initialized = false; +} + +void Warden::InitializeModule() +{ + SetNewState(WardenState::STATE_INITIALIZE_MODULE); } void Warden::RequestHash() @@ -66,6 +71,8 @@ void Warden::RequestHash() WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenHashRequest)); pkt.append((uint8*)&Request, sizeof(WardenHashRequest)); _session->SendPacket(&pkt); + + SetNewState(WardenState::STATE_REQUESTED_HASH); } void Warden::SendModuleToClient() @@ -92,6 +99,8 @@ void Warden::SendModuleToClient() pkt1.append((uint8*)&packet, burstSize + 3); _session->SendPacket(&pkt1); } + + SetNewState(WardenState::STATE_SENT_MODULE); } void Warden::RequestModule() @@ -112,17 +121,24 @@ void Warden::RequestModule() WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenModuleUse)); pkt.append((uint8*)&request, sizeof(WardenModuleUse)); _session->SendPacket(&pkt); + + SetNewState(WardenState::STATE_REQUESTED_MODULE); } void Warden::Update() { - if (_initialized) - { - uint32 currentTimestamp = WorldTimer::getMSTime(); - uint32 diff = currentTimestamp - _previousTimestamp; - _previousTimestamp = currentTimestamp; + uint32 currentTimestamp = WorldTimer::getMSTime(); + uint32 diff = currentTimestamp - _previousTimestamp; + _previousTimestamp = currentTimestamp; - if (_dataSent) + switch (_state) + { + case WardenState::STATE_INITIAL: + break; + case WardenState::STATE_REQUESTED_MODULE: + case WardenState::STATE_SENT_MODULE: + case WardenState::STATE_REQUESTED_HASH: + case WardenState::STATE_REQUESTED_DATA: { uint32 maxClientResponseDelay = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_RESPONSE_DELAY); @@ -131,23 +147,34 @@ void Warden::Update() // Kick player if client response delays more than set in config if (_clientResponseTimer > maxClientResponseDelay * IN_MILLISECONDS) { - sLog.outWarden("%s (latency: %u, IP: %s) exceeded Warden module response delay for more than %s - disconnecting client", - _session->GetPlayerName(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), secsToTimeString(maxClientResponseDelay, true).c_str()); + sLog.outWarden("%s (latency: %u, IP: %s) exceeded Warden module response delay on state %s for more than %s - disconnecting client", + _session->GetPlayerName(), _session->GetLatency(), _session->GetRemoteAddress().c_str(), WardenState::to_string(_state), secsToTimeString(maxClientResponseDelay, true).c_str()); _session->KickPlayer(); } else + { _clientResponseTimer += diff; + } + } } - else + break; + case WardenState::STATE_INITIALIZE_MODULE: + case WardenState::STATE_RESTING: { if (diff >= _checkTimer) { RequestData(); } else + { _checkTimer -= diff; + } } + break; + default: + sLog.outWarden("Unimplemented warden state!"); + break; } } @@ -161,6 +188,28 @@ void Warden::EncryptData(uint8* buffer, uint32 length) _outputCrypto.UpdateData(length, buffer); } +void Warden::SetNewState(WardenState::Value state) +{ + //if we pass all initial checks, allow change + if (state < WardenState::STATE_REQUESTED_DATA) + { + if (state < _state) + { + sLog.outWarden("Warden Error: jump from %s to %s which is lower by initialization routine", WardenState::to_string(_state), WardenState::to_string(state)); + return; + } + } + + _state = state; + + //Reset timers + // Set hold off timer, minimum timer should at least be 1 second + uint32 holdOff = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF); + _checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS; + + _clientResponseTimer = 0; +} + bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length) { uint32 newChecksum = BuildChecksum(data, length); @@ -284,11 +333,14 @@ void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData) } } +void Warden::RequestData() +{ + SetNewState(WardenState::STATE_REQUESTED_DATA); +} + void Warden::HandleData(ByteBuffer& /*buff*/) { - // Set hold off timer, minimum timer should at least be 1 second - uint32 holdOff = sWorld.getConfig(CONFIG_UINT32_WARDEN_CLIENT_CHECK_HOLDOFF); - _checkTimer = (holdOff < 1 ? 1 : holdOff) * IN_MILLISECONDS; + SetNewState(WardenState::STATE_RESTING); } void Warden::LogPositiveToDB(WardenCheck* check) diff --git a/src/game/Warden/Warden.h b/src/game/Warden/Warden.h index 46f9921c2..ae2ccd2e9 100644 --- a/src/game/Warden/Warden.h +++ b/src/game/Warden/Warden.h @@ -34,7 +34,7 @@ #include "Database/DatabaseEnv.h" // the default client version with info in warden_checks; for other version checks, see warden_build_specific -#define DEFAULT_CLIENT_BUILD 5875 +#define DEFAULT_CLIENT_BUILD 12340 enum WardenOpcodes { @@ -95,6 +95,42 @@ struct WardenHashRequest uint8 Seed[16]; }; +namespace WardenState +{ + enum Value + { + STATE_INITIAL, + STATE_REQUESTED_MODULE, + STATE_SENT_MODULE, + STATE_REQUESTED_HASH, + STATE_INITIALIZE_MODULE, + STATE_REQUESTED_DATA, + STATE_RESTING + }; + + inline const char* to_string(WardenState::Value value) + { + switch (value) + { + case WardenState::STATE_INITIAL: + return "STATE_INITIAL"; + case WardenState::STATE_REQUESTED_MODULE: + return "STATE_REQUESTED_MODULE"; + case WardenState::STATE_SENT_MODULE: + return "STATE_SENT_MODULE"; + case WardenState::STATE_REQUESTED_HASH: + return "STATE_REQUESTED_HASH"; + case WardenState::STATE_INITIALIZE_MODULE: + return "STATE_INITIALIZE_MODULE"; + case WardenState::STATE_REQUESTED_DATA: + return "STATE_REQUESTED_DATA"; + case WardenState::STATE_RESTING: + return "STATE_RESTING"; + } + return "UNDEFINED STATE"; + } +}; + #if defined(__GNUC__) #pragma pack() #else @@ -119,10 +155,10 @@ class Warden virtual void Init(WorldSession* session, BigNumber* k) = 0; virtual ClientWardenModule* GetModuleForClient() = 0; - virtual void InitializeModule() = 0; + virtual void InitializeModule(); virtual void RequestHash(); virtual void HandleHashResult(ByteBuffer &buff) = 0; - virtual void RequestData() = 0; + virtual void RequestData(); virtual void HandleData(ByteBuffer &buff); void SendModuleToClient(); @@ -131,6 +167,8 @@ class Warden void DecryptData(uint8* buffer, uint32 length); void EncryptData(uint8* buffer, uint32 length); + void SetNewState(WardenState::Value state); + static bool IsValidCheckSum(uint32 checksum, const uint8 *data, const uint16 length); static uint32 BuildChecksum(const uint8 *data, uint32 length); @@ -148,10 +186,9 @@ class Warden ARC4 _outputCrypto; uint32 _checkTimer; // Timer for sending check requests uint32 _clientResponseTimer; // Timer for client response delay - bool _dataSent; uint32 _previousTimestamp; ClientWardenModule* _module; - bool _initialized; + WardenState::Value _state; }; #endif diff --git a/src/game/Warden/WardenCheckMgr.cpp b/src/game/Warden/WardenCheckMgr.cpp index 502c7147f..963c45ae2 100644 --- a/src/game/Warden/WardenCheckMgr.cpp +++ b/src/game/Warden/WardenCheckMgr.cpp @@ -32,19 +32,18 @@ #include "WardenCheckMgr.h" #include "Warden.h" -WardenCheckMgr::WardenCheckMgr() { } +WardenCheckMgr::WardenCheckMgr() : m_lock(0), CheckStore(), CheckResultStore() { } WardenCheckMgr::~WardenCheckMgr() { - for (uint16 i = 0; i < CheckStore.size(); ++i) - { - delete CheckStore[i]; - } + for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it) + delete it->second; - for (CheckResultContainer::iterator itr = CheckResultStore.begin(); itr != CheckResultStore.end(); ++itr) - { - delete itr->second; - } + for (CheckResultMap::iterator it = CheckResultStore.begin(); it != CheckResultStore.end(); ++it) + delete it->second; + + CheckStore.clear(); + CheckResultStore.clear(); } void WardenCheckMgr::LoadWardenChecks() @@ -52,48 +51,34 @@ void WardenCheckMgr::LoadWardenChecks() // Check if Warden is enabled by config before loading anything if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED)) { - sLog.outWarden(">> Warden disabled, loading checks skipped."); + sLog.outString(">> Warden disabled, loading checks skipped."); return; } - - QueryResult *result = WorldDatabase.Query("SELECT MAX(`id`) FROM `warden_checks`"); + // 0 1 2 3 4 5 6 7 8 + QueryResult *result = WorldDatabase.Query("SELECT id, build, type, data, result, address, length, str, comment FROM warden ORDER BY build ASC, id ASC"); if (!result) { - sLog.outWarden(">> Loaded 0 Warden checks. DB table `warden_checks` is empty!"); + sLog.outString("[Warden]: >> Loaded 0 warden data and results"); return; } - Field* fields = result->Fetch(); - - uint16 maxCheckId = fields[0].GetUInt16(); - - CheckStore.resize(maxCheckId + 1); - - delete result; - // 0 1 2 3 4 5 6 7 - result = WorldDatabase.Query("SELECT id, type, data, result, address, length, str, comment FROM warden_checks ORDER BY id ASC"); - uint32 count = 0; - - if (!result) - { - sLog.outString("[Warden]: >> Loaded %u warden data and results", count); - return; - } + Field* fields; do { fields = result->Fetch(); - uint16 id = fields[0].GetUInt16(); - uint8 checkType = fields[1].GetUInt8(); - std::string data = fields[2].GetString(); - std::string checkResult = fields[3].GetString(); - uint32 address = fields[4].GetUInt32(); - uint8 length = fields[5].GetUInt8(); - std::string str = fields[6].GetString(); - std::string comment = fields[7].GetString(); + uint16 id = fields[0].GetUInt16(); + uint16 build = fields[1].GetUInt16(); + uint8 checkType = fields[2].GetUInt8(); + std::string data = fields[3].GetString(); + std::string checkResult = fields[4].GetString(); + uint32 address = fields[5].GetUInt32(); + uint8 length = fields[6].GetUInt8(); + std::string str = fields[7].GetString(); + std::string comment = fields[8].GetString(); WardenCheck* wardenCheck = new WardenCheck(); wardenCheck->Type = checkType; @@ -117,11 +102,6 @@ void WardenCheckMgr::LoadWardenChecks() } } - if (checkType == MEM_CHECK || checkType == MODULE_CHECK) - MemChecksIdPool.push_back(id); - else - OtherChecksIdPool.push_back(id); - if (checkType == MEM_CHECK || checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == PROC_CHECK) { wardenCheck->Address = address; @@ -132,11 +112,12 @@ void WardenCheckMgr::LoadWardenChecks() if (checkType == MEM_CHECK || checkType == MPQ_CHECK || checkType == LUA_STR_CHECK || checkType == DRIVER_CHECK || checkType == MODULE_CHECK) wardenCheck->Str = str; - CheckStore[id] = wardenCheck; + CheckStore.insert(std::pair(build, wardenCheck)); if (checkType == MPQ_CHECK || checkType == MEM_CHECK) { WardenCheckResult* wr = new WardenCheckResult(); + wr->Id = id; wr->Result.SetHexStr(checkResult.c_str()); int len = checkResult.size() / 2; if (wr->Result.GetNumBytes() < len) @@ -148,7 +129,7 @@ void WardenCheckMgr::LoadWardenChecks() wr->Result.SetBinary((uint8*)temp, len); delete[] temp; } - CheckResultStore[id] = wr; + CheckResultStore.insert(std::pair(build, wr)); } if (comment.empty()) @@ -159,82 +140,9 @@ void WardenCheckMgr::LoadWardenChecks() ++count; } while (result->NextRow()); - sLog.outWarden(">> Loaded %u warden checks.", count); + sLog.outString(">> Loaded %u warden checks.", count); delete result; - // 0 1 2 3 4 5 6 - result = WorldDatabase.Query("SELECT id, build, data, result, address, length, str FROM warden_build_specific ORDER BY id ASC"); - - if (!result) - { - sLog.outString("[Warden]: >> Loaded 0 warden client build-specific data."); - return; - } - - count = 0; - do - { - fields = result->Fetch(); - - uint16 id = fields[0].GetUInt16(); - if (id >= CheckStore.size()) - { - sLog.outWarden("ERROR: Build-specific, check is missing in warden_checks, skipping id %u.", id); - continue; - } - - uint16 build = fields[1].GetUInt16(); - if (build == DEFAULT_CLIENT_BUILD) - { - sLog.outWarden("ERROR: Build-specific table may not contain checks for default %u build, skipping id %u.", DEFAULT_CLIENT_BUILD, id); - continue; - } - - //std::string data = fields[2].GetString(); //unused for now - std::string checkResult = fields[3].GetString(); - uint32 address = fields[4].GetUInt32(); - uint8 length = fields[5].GetUInt8(); - std::string str = fields[6].GetString(); - - WardenCheck* wardenCheck = new WardenCheck(); - wardenCheck->CheckId = id; - wardenCheck->Type = CheckStore[id]->Type; - - WardenCheckResult* wr = new WardenCheckResult(); - switch (wardenCheck->Type) - { - case MEM_CHECK: - wardenCheck->Address = address; - wardenCheck->Length = length; - wardenCheck->Str = str; - wr->Result.SetHexStr(checkResult.c_str()); - { - int len = checkResult.size() / 2; - if (wr->Result.GetNumBytes() < len) - { - uint8 *temp = new uint8[len]; - memset(temp, 0, len); - memcpy(temp, wr->Result.AsByteArray(), wr->Result.GetNumBytes()); - std::reverse(temp, temp + len); - wr->Result.SetBinary((uint8*)temp, len); - delete[] temp; - } - } - break; - default: - sLog.outWarden("The check type %u is considered as build-independent, skipping id %u.", wardenCheck->Type, id); - delete wr; - delete wardenCheck; - continue; - } - - MCheckStore[ComposeMultiCheckKey(build, id)] = wardenCheck; - MCheckResultStore[ComposeMultiCheckKey(build, id)] = wr; - ++count; - - } while (result->NextRow()); - - sLog.outString(">> Loaded %u warden client build-specific check overrides.", count); } void WardenCheckMgr::LoadWardenOverrides() @@ -242,22 +150,22 @@ void WardenCheckMgr::LoadWardenOverrides() // Check if Warden is enabled by config before loading anything if (!sWorld.getConfig(CONFIG_BOOL_WARDEN_WIN_ENABLED) && !sWorld.getConfig(CONFIG_BOOL_WARDEN_OSX_ENABLED)) { - sLog.outWarden(">> Warden disabled, loading check overrides skipped."); + sLog.outString(">> Warden disabled, loading check overrides skipped."); return; } // 0 1 - QueryResult* result = CharacterDatabase.Query("SELECT `wardenId`, `action` FROM `warden_action`"); + QueryResult* result = CharacterDatabase.Query("SELECT wardenId, action FROM warden_action"); if (!result) { - sLog.outWarden(">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!"); + sLog.outString(">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!"); return; } uint32 count = 0; - ACE_WRITE_GUARD(ACE_RW_Mutex, g, _checkStoreLock); + ACE_WRITE_GUARD(LOCK, g, m_lock) do { @@ -269,54 +177,68 @@ void WardenCheckMgr::LoadWardenOverrides() // Check if action value is in range (0-2, see WardenActions enum) if (action > WARDEN_ACTION_BAN) sLog.outWarden("Warden check override action out of range (ID: %u, action: %u)", checkId, action); - // Check if check actually exists before accessing the CheckStore vector - else if (checkId > CheckStore.size()) - sLog.outWarden("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action); else { - CheckStore[checkId]->Action = WardenActions(action); - ++count; + bool found = false; + for (CheckMap::iterator it = CheckStore.begin(); it != CheckStore.end(); ++it) + { + if (it->second->CheckId == checkId) + { + it->second->Action = WardenActions(action); + ++count; + found = true; + } + } + if (!found) + sLog.outWarden("Warden check action override for non-existing check (ID: %u, action: %u), skipped", checkId, action); } } while (result->NextRow()); - sLog.outWarden(">> Loaded %u warden action overrides.", count); + sLog.outString(">> Loaded %u warden action overrides.", count); } -WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 build, uint16 Id) +WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 build, uint16 id) { - if (Id < CheckStore.size()) + WardenCheck* result = NULL; + + ACE_READ_GUARD_RETURN(LOCK, g, m_lock, result) + for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it) { - if (build != DEFAULT_CLIENT_BUILD) - { - MultiCheckContainer::const_iterator it = MCheckStore.find(ComposeMultiCheckKey(build, Id)); - if (it != MCheckStore.end()) - { - return it->second; - } - } - return CheckStore[Id]; + if (it->second->CheckId == id) + result = it->second; } - return NULL; + return result; } -WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 build, uint16 Id) +WardenCheckResult* WardenCheckMgr::GetWardenResultById(uint16 build, uint16 id) { - if (build != DEFAULT_CLIENT_BUILD) + WardenCheckResult* result = NULL; + + ACE_READ_GUARD_RETURN(LOCK, g, m_lock, result) + for (CheckResultMap::iterator it = CheckResultStore.lower_bound(build); it != CheckResultStore.upper_bound(build); ++it) { - MultiResultContainer::const_iterator it = MCheckResultStore.find(ComposeMultiCheckKey(build, Id)); - if (it != MCheckResultStore.end()) - { - return it->second; - } + if (it->second->Id == id) + result = it->second; } - CheckResultContainer::const_iterator itr = CheckResultStore.find(Id); - if (itr != CheckResultStore.end()) - { - return itr->second; - } - - return NULL; + return result; } + +void WardenCheckMgr::GetWardenCheckIds(bool isMemCheck, uint16 build, std::list& idl) +{ + idl.clear(); //just to be sure + + ACE_READ_GUARD(LOCK, g, m_lock) + for (CheckMap::iterator it = CheckStore.lower_bound(build); it != CheckStore.upper_bound(build); ++it) + { + if (isMemCheck) + { + if ((it->second->Type == MEM_CHECK) || (it->second->Type == MODULE_CHECK)) + idl.push_back(it->second->CheckId); + } + else + idl.push_back(it->second->CheckId); + } +} \ No newline at end of file diff --git a/src/game/Warden/WardenCheckMgr.h b/src/game/Warden/WardenCheckMgr.h index c87f49f24..aae915ec0 100644 --- a/src/game/Warden/WardenCheckMgr.h +++ b/src/game/Warden/WardenCheckMgr.h @@ -50,6 +50,7 @@ struct WardenCheck struct WardenCheckResult { + uint16 Id; BigNumber Result; // MEM_CHECK }; @@ -66,33 +67,22 @@ class WardenCheckMgr return &instance; } - WardenCheck* GetWardenDataById(uint16 build, uint16 Id); - WardenCheckResult* GetWardenResultById(uint16 build, uint16 Id); - - std::vector MemChecksIdPool; - std::vector OtherChecksIdPool; + WardenCheck* GetWardenDataById(uint16 /*build*/, uint16 /*id*/); + WardenCheckResult* GetWardenResultById(uint16 /*build*/, uint16 /*id*/); + void GetWardenCheckIds(bool isMemCheck /* true = MEM */, uint16 build, std::list& list); void LoadWardenChecks(); void LoadWardenOverrides(); - ACE_RW_Mutex _checkStoreLock; - private: - uint32 inline ComposeMultiCheckKey(uint16 clientBuild, uint16 checkID) { return (uint32(checkID) << 16) | clientBuild; } + typedef ACE_RW_Thread_Mutex LOCK; + typedef std::multimap< uint16, WardenCheck* > CheckMap; + typedef std::multimap< uint16, WardenCheckResult* > CheckResultMap; - // We have a linear key without any gaps, so we use vector for fast access - typedef std::vector CheckContainer; - typedef std::map CheckResultContainer; + LOCK m_lock; + CheckMap CheckStore; + CheckResultMap CheckResultStore; - CheckContainer CheckStore; - CheckResultContainer CheckResultStore; - - // here we have just few checks, vector is not appropriate; key is from ComposeMultiCheckKey - typedef std::map MultiCheckContainer; - typedef std::map MultiResultContainer; - - MultiCheckContainer MCheckStore; - MultiResultContainer MCheckResultStore; }; #define sWardenCheckMgr WardenCheckMgr::instance() diff --git a/src/game/Warden/WardenMac.cpp b/src/game/Warden/WardenMac.cpp index 03af8c187..6e0564cf0 100644 --- a/src/game/Warden/WardenMac.cpp +++ b/src/game/Warden/WardenMac.cpp @@ -98,6 +98,7 @@ ClientWardenModule* WardenMac::GetModuleForClient() void WardenMac::InitializeModule() { sLog.outWarden("Initialize module"); + Warden::InitializeModule(); } struct keyData { @@ -174,8 +175,6 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); - _initialized = true; - _previousTimestamp = WorldTimer::getMSTime(); } @@ -200,16 +199,13 @@ void WardenMac::RequestData() pkt.append(buff); _session->SendPacket(&pkt); - _dataSent = true; + Warden::RequestData(); } void WardenMac::HandleData(ByteBuffer &buff) { sLog.outWarden("Handle data"); - _dataSent = false; - _clientResponseTimer = 0; - //uint16 Length; //buff >> Length; //uint32 Checksum; diff --git a/src/game/Warden/WardenWin.cpp b/src/game/Warden/WardenWin.cpp index dca685781..836eef4ba 100644 --- a/src/game/Warden/WardenWin.cpp +++ b/src/game/Warden/WardenWin.cpp @@ -132,6 +132,8 @@ void WardenWin::InitializeModule() WorldPacket pkt(SMSG_WARDEN_DATA, sizeof(WardenInitModuleRequest)); pkt.append((uint8*)&Request, sizeof(WardenInitModuleRequest)); _session->SendPacket(&pkt); + + Warden::InitializeModule(); } void WardenWin::HandleHashResult(ByteBuffer &buff) @@ -154,8 +156,6 @@ void WardenWin::HandleHashResult(ByteBuffer &buff) _inputCrypto.Init(_inputKey); _outputCrypto.Init(_outputKey); - _initialized = true; - _previousTimestamp = WorldTimer::getMSTime(); } @@ -163,18 +163,20 @@ void WardenWin::RequestData() { sLog.outWarden("Request data"); + uint16 build = _session->GetClientBuild(); + uint16 id = 0; + uint8 type = 0; + WardenCheck* wd = NULL; + // If all checks were done, fill the todo list again if (_memChecksTodo.empty()) - _memChecksTodo.assign(sWardenCheckMgr->MemChecksIdPool.begin(), sWardenCheckMgr->MemChecksIdPool.end()); + sWardenCheckMgr->GetWardenCheckIds(true, build, _memChecksTodo); if (_otherChecksTodo.empty()) - _otherChecksTodo.assign(sWardenCheckMgr->OtherChecksIdPool.begin(), sWardenCheckMgr->OtherChecksIdPool.end()); + sWardenCheckMgr->GetWardenCheckIds(false, build, _otherChecksTodo); _serverTicks = WorldTimer::getMSTime(); - uint16 id; - uint8 type; - WardenCheck* wd; _currentChecks.clear(); // Build check request @@ -195,8 +197,6 @@ void WardenWin::RequestData() ByteBuffer buff; buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST); - ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock); - for (uint16 i = 0; i < sWorld.getConfig(CONFIG_UINT32_WARDEN_NUM_OTHER_CHECKS); ++i) { // If todo list is done break loop (will be filled on next Update() run) @@ -210,18 +210,22 @@ void WardenWin::RequestData() // Add the id to the list sent in this cycle _currentChecks.push_back(id); - wd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), id); - - switch (wd->Type) + // if we are here, the function is guaranteed to not return NULL + // but ... who knows + wd = sWardenCheckMgr->GetWardenDataById(build, id); + if (wd) { - case MPQ_CHECK: - case LUA_STR_CHECK: - case DRIVER_CHECK: - buff << uint8(wd->Str.size()); - buff.append(wd->Str.c_str(), wd->Str.size()); - break; - default: - break; + switch (wd->Type) + { + case MPQ_CHECK: + case LUA_STR_CHECK: + case DRIVER_CHECK: + buff << uint8(wd->Str.size()); + buff.append(wd->Str.c_str(), wd->Str.size()); + break; + default: + break; + } } } @@ -235,7 +239,7 @@ void WardenWin::RequestData() for (std::list::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) { - wd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr); + wd = sWardenCheckMgr->GetWardenDataById(build, *itr); type = wd->Type; buff << uint8(type ^ xorByte); @@ -301,8 +305,6 @@ void WardenWin::RequestData() pkt.append(buff); _session->SendPacket(&pkt); - _dataSent = true; - std::stringstream stream; stream << "Sent check id's: "; for (std::list::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) @@ -311,15 +313,14 @@ void WardenWin::RequestData() } sLog.outWarden("%s", stream.str().c_str()); + + Warden::RequestData(); } void WardenWin::HandleData(ByteBuffer &buff) { sLog.outWarden("Handle data"); - _dataSent = false; - _clientResponseTimer = 0; - uint16 Length; buff >> Length; uint32 Checksum; @@ -349,8 +350,9 @@ void WardenWin::HandleData(ByteBuffer &buff) uint32 ticksNow = WorldTimer::getMSTime(); uint32 ourTicks = newClientTicks + (ticksNow - _serverTicks); - sLog.outWarden("ServerTicks %u, RequestTicks %u, CLientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response + sLog.outWarden("ServerTicks %u, RequestTicks %u, ClientTicks %u", ticksNow, _serverTicks, newClientTicks); // Now, At request, At response sLog.outWarden("Waittime %u", ourTicks - newClientTicks); + } WardenCheckResult* rs; @@ -358,8 +360,6 @@ void WardenWin::HandleData(ByteBuffer &buff) uint8 type; uint16 checkFailed = 0; - ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock); - for (std::list::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) { rd = sWardenCheckMgr->GetWardenDataById(_session->GetClientBuild(), *itr); diff --git a/src/shared/revision.h b/src/shared/revision.h index 5079e0ede..3529cdf3f 100644 --- a/src/shared/revision.h +++ b/src/shared/revision.h @@ -39,5 +39,5 @@ #define WORLD_DB_VERSION_NR 21 #define WORLD_DB_STRUCTURE_NR 12 #define WORLD_DB_CONTENT_NR 001 - #define WORLD_DB_UPDATE_DESCRIPTION "GM_Commands_localization" + #define WORLD_DB_UPDATE_DESCRIPTION "warden_refactor" #endif // __REVISION_H__