diff options
Diffstat (limited to 'src/server/shared')
42 files changed, 888 insertions, 262 deletions
diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index a61248f01ea..7a02e415d69 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -77,6 +77,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} + ${VALGRIND_INCLUDE_DIR} ) add_library(shared STATIC diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index e74e707a942..4e23b4a4770 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -19,46 +19,6 @@ #ifndef TRINITYCORE_COMMON_H #define TRINITYCORE_COMMON_H -// config.h needs to be included 1st -/// @todo this thingy looks like hack, but its not, need to -// make separate header however, because It makes mess here. -#ifdef HAVE_CONFIG_H -// Remove Some things that we will define -// This is in case including another config.h -// before trinity config.h -#ifdef PACKAGE -#undef PACKAGE -#endif //PACKAGE -#ifdef PACKAGE_BUGREPORT -#undef PACKAGE_BUGREPORT -#endif //PACKAGE_BUGREPORT -#ifdef PACKAGE_NAME -#undef PACKAGE_NAME -#endif //PACKAGE_NAME -#ifdef PACKAGE_STRING -#undef PACKAGE_STRING -#endif //PACKAGE_STRING -#ifdef PACKAGE_TARNAME -#undef PACKAGE_TARNAME -#endif //PACKAGE_TARNAME -#ifdef PACKAGE_VERSION -#undef PACKAGE_VERSION -#endif //PACKAGE_VERSION -#ifdef VERSION -#undef VERSION -#endif //VERSION - -# include "Config.h" - -#undef PACKAGE -#undef PACKAGE_BUGREPORT -#undef PACKAGE_NAME -#undef PACKAGE_STRING -#undef PACKAGE_TARNAME -#undef PACKAGE_VERSION -#undef VERSION -#endif //HAVE_CONFIG_H - #include "Define.h" #include <unordered_map> @@ -66,7 +26,7 @@ #include <stdlib.h> #include <string.h> #include <time.h> -#include <math.h> +#include <cmath> #include <errno.h> #include <signal.h> #include <assert.h> @@ -85,6 +45,13 @@ #if PLATFORM == PLATFORM_WINDOWS # include <ws2tcpip.h> + +# if defined(__INTEL_COMPILER) +# if !defined(BOOST_ASIO_HAS_MOVE) +# define BOOST_ASIO_HAS_MOVE +# endif // !defined(BOOST_ASIO_HAS_MOVE) +# endif // if defined(__INTEL_COMPILER) + #else # include <sys/types.h> # include <sys/ioctl.h> @@ -186,7 +153,7 @@ struct LocalizedString #endif #ifndef M_PI -#define M_PI 3.14159265358979323846f +#define M_PI 3.14159265358979323846 #endif #define MAX_QUERY_LEN 32*1024 diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index 6b83f562520..21bbd063b53 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -59,7 +59,7 @@ bool ConfigMgr::LoadInitial(std::string const& file, std::string& error) bool ConfigMgr::Reload(std::string& error) { - return LoadInitial(_filename.c_str(), error); + return LoadInitial(_filename, error); } std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) diff --git a/src/server/shared/DataStores/DBCFileLoader.cpp b/src/server/shared/DataStores/DBCFileLoader.cpp index f8c8693216d..ea9bf23d383 100644 --- a/src/server/shared/DataStores/DBCFileLoader.cpp +++ b/src/server/shared/DataStores/DBCFileLoader.cpp @@ -114,11 +114,9 @@ bool DBCFileLoader::Load(const char* filename, const char* fmt) DBCFileLoader::~DBCFileLoader() { - if (data) - delete [] data; + delete[] data; - if (fieldsOffset) - delete [] fieldsOffset; + delete[] fieldsOffset; } DBCFileLoader::Record DBCFileLoader::getRecord(size_t id) diff --git a/src/server/shared/Database/DatabaseWorker.cpp b/src/server/shared/Database/DatabaseWorker.cpp index ca48ebdd811..e130429c8d0 100644 --- a/src/server/shared/Database/DatabaseWorker.cpp +++ b/src/server/shared/Database/DatabaseWorker.cpp @@ -50,7 +50,7 @@ void DatabaseWorker::WorkerThread() _queue->WaitAndPop(operation); - if (_cancelationToken) + if (_cancelationToken || !operation) return; operation->SetConnection(_connection); diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 18797b6b12a..61385d92437 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -35,7 +35,7 @@ class PingOperation : public SQLOperation { //! Operation for idle delaythreads - bool Execute() + bool Execute() override { m_conn->Ping(); return true; @@ -45,6 +45,14 @@ class PingOperation : public SQLOperation template <class T> class DatabaseWorkerPool { + private: + enum InternalIndex + { + IDX_ASYNC, + IDX_SYNCH, + IDX_SIZE + }; + public: /* Activity state */ DatabaseWorkerPool() : _connectionInfo(NULL) @@ -68,40 +76,22 @@ class DatabaseWorkerPool bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads) { - bool res = true; _connectionInfo = new MySQLConnectionInfo(infoString); TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", GetDatabaseName(), async_threads, synch_threads); - //! Open asynchronous connections (delayed operations) - _connections[IDX_ASYNC].resize(async_threads); - for (uint8 i = 0; i < async_threads; ++i) - { - T* t = new T(_queue, *_connectionInfo); - res &= t->Open(); - if (res) // only check mysql version if connection is valid - WPFatal(mysql_get_server_version(t->GetHandle()) >= MIN_MYSQL_SERVER_VERSION, "TrinityCore does not support MySQL versions below 5.1"); - _connections[IDX_ASYNC][i] = t; - ++_connectionCount[IDX_ASYNC]; - } + bool res = OpenConnections(IDX_ASYNC, async_threads); - //! Open synchronous connections (direct, blocking operations) - _connections[IDX_SYNCH].resize(synch_threads); - for (uint8 i = 0; i < synch_threads; ++i) - { - T* t = new T(*_connectionInfo); - res &= t->Open(); - _connections[IDX_SYNCH][i] = t; - ++_connectionCount[IDX_SYNCH]; - } + if (!res) + return res; + + res = OpenConnections(IDX_SYNCH, synch_threads); if (res) TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC])); - else - TC_LOG_ERROR("sql.driver", "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " - "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", GetDatabaseName()); + return res; } @@ -112,8 +102,6 @@ class DatabaseWorkerPool for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) { T* t = _connections[IDX_ASYNC][i]; - DatabaseWorker* worker = t->m_worker; - delete worker; t->Close(); //! Closes the actualy MySQL connection. } @@ -442,7 +430,7 @@ class DatabaseWorkerPool if (str.empty()) return; - char* buf = new char[str.size()*2+1]; + char* buf = new char[str.size() * 2 + 1]; EscapeString(buf, str.c_str(), str.size()); str = buf; delete[] buf; @@ -470,6 +458,54 @@ class DatabaseWorkerPool } private: + bool OpenConnections(InternalIndex type, uint8 numConnections) + { + _connections[type].resize(numConnections); + for (uint8 i = 0; i < numConnections; ++i) + { + T* t; + + if (type == IDX_ASYNC) + t = new T(_queue, *_connectionInfo); + else if (type == IDX_SYNCH) + t = new T(*_connectionInfo); + else + ASSERT(false); + + _connections[type][i] = t; + ++_connectionCount[type]; + + bool res = t->Open(); + + if (res) + { + if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION) + { + TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); + res = false; + } + } + + // Failed to open a connection or invalid version, abort and cleanup + if (!res) + { + TC_LOG_ERROR("sql.driver", "DatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile " + "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", GetDatabaseName()); + + while (_connectionCount[type] != 0) + { + T* t = _connections[type][i--]; + delete t; + --_connectionCount[type]; + } + + return false; + } + } + + return true; + } + unsigned long EscapeString(char *to, const char *from, unsigned long length) { if (!to || !from || !length) @@ -507,14 +543,6 @@ class DatabaseWorkerPool return _connectionInfo->database.c_str(); } - private: - enum _internalIndex - { - IDX_ASYNC, - IDX_SYNCH, - IDX_SIZE - }; - ProducerConsumerQueue<SQLOperation*>* _queue; //! Queue shared by async worker threads. std::vector< std::vector<T*> > _connections; uint32 _connectionCount[2]; //! Counter of MySQL connections; diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index 5f427a5871b..2e888be5ed3 100644 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -50,7 +50,7 @@ class Field if (data.raw) return *reinterpret_cast<uint8*>(data.value); - return static_cast<uint8>(atol((char*)data.value)); + return static_cast<uint8>(strtoul((char*)data.value, nullptr, 10)); } int8 GetInt8() const @@ -68,7 +68,7 @@ class Field if (data.raw) return *reinterpret_cast<int8*>(data.value); - return static_cast<int8>(atol((char*)data.value)); + return static_cast<int8>(strtol((char*)data.value, NULL, 10)); } uint16 GetUInt16() const @@ -86,7 +86,7 @@ class Field if (data.raw) return *reinterpret_cast<uint16*>(data.value); - return static_cast<uint16>(atol((char*)data.value)); + return static_cast<uint16>(strtoul((char*)data.value, nullptr, 10)); } int16 GetInt16() const @@ -104,7 +104,7 @@ class Field if (data.raw) return *reinterpret_cast<int16*>(data.value); - return static_cast<int16>(atol((char*)data.value)); + return static_cast<int16>(strtol((char*)data.value, NULL, 10)); } uint32 GetUInt32() const @@ -122,7 +122,7 @@ class Field if (data.raw) return *reinterpret_cast<uint32*>(data.value); - return static_cast<uint32>(atol((char*)data.value)); + return static_cast<uint32>(strtoul((char*)data.value, nullptr, 10)); } int32 GetInt32() const @@ -140,7 +140,7 @@ class Field if (data.raw) return *reinterpret_cast<int32*>(data.value); - return static_cast<int32>(atol((char*)data.value)); + return static_cast<int32>(strtol((char*)data.value, NULL, 10)); } uint64 GetUInt64() const @@ -158,7 +158,7 @@ class Field if (data.raw) return *reinterpret_cast<uint64*>(data.value); - return static_cast<uint64>(atol((char*)data.value)); + return static_cast<uint64>(strtoull((char*)data.value, nullptr, 10)); } int64 GetInt64() const @@ -176,7 +176,7 @@ class Field if (data.raw) return *reinterpret_cast<int64*>(data.value); - return static_cast<int64>(strtol((char*)data.value, NULL, 10)); + return static_cast<int64>(strtoll((char*)data.value, NULL, 10)); } float GetFloat() const diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index f2e9ed88e2e..a0fb6e74a39 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -34,7 +34,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHARACTER_BAN, "INSERT INTO character_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER_BAN, "UPDATE character_banned SET active = 0 WHERE guid = ? AND active != 0", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_BAN, "DELETE cb FROM character_banned cb INNER JOIN characters c ON c.guid = cb.guid WHERE c.account = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_BANINFO, "SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate, banreason, bannedby FROM character_banned WHERE guid = ? ORDER BY bandate ASC", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_BANINFO, "SELECT bandate, unbandate-bandate, active, unbandate, banreason, bannedby FROM character_banned WHERE guid = ? ORDER BY bandate ASC", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH); @@ -362,9 +362,6 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_GM_SUBSURVEY, "INSERT INTO gm_subsurveys (surveyId, subsurveyId, rank, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_LAG_REPORT, "INSERT INTO lag_reports (guid, lagType, mapId, posX, posY, posZ, latency, createTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - // For loading and deleting expired auctions at startup - PrepareStatement(CHAR_SEL_EXPIRED_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid WHERE ah.time <= ?", CONNECTION_SYNCH); - // LFG Data PrepareStatement(CHAR_INS_LFG_DATA, "INSERT INTO lfg_data (guid, dungeon, state) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_LFG_DATA, "DELETE FROM lfg_data WHERE guid = ?", CONNECTION_ASYNC); @@ -435,7 +432,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHARACTER_SOCIAL, "DELETE FROM character_social WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE, "UPDATE character_social SET note = ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remaintime FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); @@ -632,4 +629,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)", CONNECTION_ASYNC); + + // PvPstats + PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_PVPSTATS_BATTLEGROUND, "INSERT INTO pvpstats_battlegrounds (id, winner_faction, bracket_id, type, date) VALUES (?, ?, ?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PVPSTATS_PLAYER, "INSERT INTO pvpstats_players (battleground_id, character_guid, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done, attr_1, attr_2, attr_3, attr_4, attr_5) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index 73eac6e30d6..4764d653f17 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -29,7 +29,7 @@ class CharacterDatabaseConnection : public MySQLConnection CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } //- Loads database type specific prepared statements - void DoPrepareStatements(); + void DoPrepareStatements() override; }; typedef DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabaseWorkerPool; @@ -319,8 +319,6 @@ enum CharacterDatabaseStatements CHAR_INS_GM_SUBSURVEY, CHAR_INS_LAG_REPORT, - CHAR_SEL_EXPIRED_AUCTIONS, - CHAR_INS_CHARACTER, CHAR_UPD_CHARACTER, @@ -561,6 +559,10 @@ enum CharacterDatabaseStatements CHAR_DEL_ITEMCONTAINER_MONEY, CHAR_INS_ITEMCONTAINER_MONEY, + CHAR_SEL_PVPSTATS_MAXID, + CHAR_INS_PVPSTATS_BATTLEGROUND, + CHAR_INS_PVPSTATS_PLAYER, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index b9f281d3f2a..2bdbc70933d 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -43,8 +43,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_BNET, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE battlenet_account = ? AND battlenet_index = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os, battlenet_account FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); @@ -118,9 +117,12 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN, "SELECT bandate, unbandate FROM battlenet_account_bans WHERE id = ? AND active = 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ?, online = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.battlenet_index = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.battlenet_index, a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_index = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT ba.id, ba.sessionKey, a.id FROM battlenet_accounts ba LEFT JOIN account a ON ba.id = a.battlenet_account WHERE ba.email = ? AND a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE username = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED, "SELECT a.id, a.username, ab.bandate, ab.unbandate, ab.active FROM account a LEFT JOIN account_banned ab ON a.id = ab.id WHERE battlenet_index = ? AND battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_FAILED_LOGINS, "SELECT failed_logins FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_FAILED_LOGINS, "UPDATE battlenet_accounts SET failed_logins = failed_logins + 1 WHERE email = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_BNET_ACCOUNT, "INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 830fd625931..c1816784f07 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -29,7 +29,7 @@ class LoginDatabaseConnection : public MySQLConnection LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } //- Loads database type specific prepared statements - void DoPrepareStatements(); + void DoPrepareStatements() override; }; typedef DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabaseWorkerPool; @@ -62,7 +62,6 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_ID_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_NAME, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, - LOGIN_SEL_ACCOUNT_INFO_BY_BNET, LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, LOGIN_SEL_NUM_CHARS_ON_REALM, LOGIN_SEL_ACCOUNT_BY_IP, @@ -137,6 +136,9 @@ enum LoginDatabaseStatements LOGIN_SEL_BNET_RECONNECT_INFO, LOGIN_SEL_BNET_GAME_ACCOUNTS, LOGIN_SEL_BNET_GAME_ACCOUNT, + LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED, + LOGIN_SEL_BNET_FAILED_LOGINS, + LOGIN_UPD_BNET_FAILED_LOGINS, LOGIN_UPD_BNET_LAST_LOGIN_INFO, LOGIN_SEL_BNET_CHARACTER_COUNTS, LOGIN_INS_BNET_ACCOUNT, diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index 53f3b5519cd..531d092d039 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -25,7 +25,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_QUEST_POOLS, "SELECT entry, pool_entry FROM pool_quest", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CRELINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_REP_CREATURE_LINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(WORLD_SEL_CREATURE_TEXT, "SELECT entry, groupid, id, text, type, language, probability, emote, duration, sound, BroadcastTextID FROM creature_text", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEXT, "SELECT entry, groupid, id, text, type, language, probability, emote, duration, sound, BroadcastTextId, TextRange FROM creature_text", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_GAMEOBJECT, "DELETE FROM gameobject WHERE guid = ?", CONNECTION_ASYNC); @@ -76,7 +76,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); @@ -89,6 +89,6 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_DISABLES, "DELETE FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_ASYNC); - // 0: uint8 - PrepareStatement(WORLD_SEL_REQ_XP, "SELECT xp_for_next_level FROM player_xp_for_level WHERE lvl = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA, "UPDATE creature SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, "UPDATE gameobject SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index c8c38d8a629..a398b412c50 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -29,7 +29,7 @@ class WorldDatabaseConnection : public MySQLConnection WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } //- Loads database type specific prepared statements - void DoPrepareStatements(); + void DoPrepareStatements() override; }; typedef DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabaseWorkerPool; @@ -110,7 +110,8 @@ enum WorldDatabaseStatements WORLD_SEL_DISABLES, WORLD_INS_DISABLES, WORLD_DEL_DISABLES, - WORLD_SEL_REQ_XP, + WORLD_UPD_CREATURE_ZONE_AREA_DATA, + WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, MAX_WORLDDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 8b24f508331..24290009625 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -57,12 +57,13 @@ m_connectionFlags(CONNECTION_ASYNC) MySQLConnection::~MySQLConnection() { - ASSERT (m_Mysql); /// MySQL context must be present at this point + delete m_worker; for (size_t i = 0; i < m_stmts.size(); ++i) delete m_stmts[i]; - mysql_close(m_Mysql); + if (m_Mysql) + mysql_close(m_Mysql); } void MySQLConnection::Close() @@ -112,7 +113,7 @@ bool MySQLConnection::Open() else // generic case { port = atoi(m_connectionInfo.port_or_socket.c_str()); - unix_socket = 0; + unix_socket = nullptr; } #endif diff --git a/src/server/shared/Database/PreparedStatement.h b/src/server/shared/Database/PreparedStatement.h index 16f7a9141d3..5af52cde016 100644 --- a/src/server/shared/Database/PreparedStatement.h +++ b/src/server/shared/Database/PreparedStatement.h @@ -163,7 +163,7 @@ class PreparedStatementTask : public SQLOperation PreparedStatementTask(PreparedStatement* stmt, bool async = false); ~PreparedStatementTask(); - bool Execute(); + bool Execute() override; PreparedQueryResultFuture GetFuture() { return m_result->get_future(); } protected: diff --git a/src/server/shared/Database/QueryHolder.cpp b/src/server/shared/Database/QueryHolder.cpp index bd938561b50..f0dc3c96e4e 100644 --- a/src/server/shared/Database/QueryHolder.cpp +++ b/src/server/shared/Database/QueryHolder.cpp @@ -166,8 +166,16 @@ void SQLQueryHolder::SetSize(size_t size) m_queries.resize(size); } +SQLQueryHolderTask::~SQLQueryHolderTask() +{ + if (!m_executed) + delete m_holder; +} + bool SQLQueryHolderTask::Execute() { + m_executed = true; + if (!m_holder) return false; diff --git a/src/server/shared/Database/QueryHolder.h b/src/server/shared/Database/QueryHolder.h index 37e23ecd653..39e51b591c5 100644 --- a/src/server/shared/Database/QueryHolder.h +++ b/src/server/shared/Database/QueryHolder.h @@ -47,14 +47,16 @@ class SQLQueryHolderTask : public SQLOperation private: SQLQueryHolder* m_holder; QueryResultHolderPromise m_result; + bool m_executed; public: SQLQueryHolderTask(SQLQueryHolder* holder) - : m_holder(holder) { }; + : m_holder(holder), m_executed(false) { } - bool Execute(); - QueryResultHolderFuture GetFuture() { return m_result.get_future(); } + ~SQLQueryHolderTask(); + bool Execute() override; + QueryResultHolderFuture GetFuture() { return m_result.get_future(); } }; -#endif
\ No newline at end of file +#endif diff --git a/src/server/shared/Database/QueryResult.cpp b/src/server/shared/Database/QueryResult.cpp index 06b09d43168..a7b8ec2b107 100644 --- a/src/server/shared/Database/QueryResult.cpp +++ b/src/server/shared/Database/QueryResult.cpp @@ -124,7 +124,7 @@ m_length(NULL) *m_rBind[fIndex].length); break; default: - m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(0, + m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(nullptr, m_rBind[fIndex].buffer_length, m_rBind[fIndex].buffer_type, *m_rBind[fIndex].length); diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h index c7cbbbbe712..3822c2c82c1 100644 --- a/src/server/shared/Database/Transaction.h +++ b/src/server/shared/Database/Transaction.h @@ -63,7 +63,7 @@ class TransactionTask : public SQLOperation ~TransactionTask(){ }; protected: - bool Execute(); + bool Execute() override; SQLTransaction m_trans; }; diff --git a/src/server/shared/Debugging/Errors.cpp b/src/server/shared/Debugging/Errors.cpp index 0621cfa5b6d..8b1b9454850 100644 --- a/src/server/shared/Debugging/Errors.cpp +++ b/src/server/shared/Debugging/Errors.cpp @@ -21,6 +21,7 @@ #include <cstdio> #include <cstdlib> #include <thread> +#include <cstdarg> namespace Trinity { @@ -32,6 +33,21 @@ void Assert(char const* file, int line, char const* function, char const* messag exit(1); } +void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) +{ + va_list args; + va_start(args, format); + + fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s ", file, line, function, message); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + + va_end(args); + *((volatile int*)NULL) = 0; + exit(1); +} + void Fatal(char const* file, int line, char const* function, char const* message) { fprintf(stderr, "\n%s:%i in %s FATAL ERROR:\n %s\n", diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index 218acfa453e..e6da19eb00d 100644 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -23,8 +23,8 @@ namespace Trinity { - DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; + DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) ATTR_NORETURN ATTR_PRINTF(5, 6); DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message) ATTR_NORETURN; @@ -42,7 +42,7 @@ namespace Trinity #define ASSERT_END #endif -#define WPAssert(cond) ASSERT_BEGIN do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond); } while(0) ASSERT_END +#define WPAssert(cond, ...) ASSERT_BEGIN do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond, ##__VA_ARGS__); } while(0) ASSERT_END #define WPFatal(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END #define WPError(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END #define WPWarning(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 2eb456ddd02..e9f4f9ca9ac 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -1043,7 +1043,7 @@ bool logChildren) offset, bHandled, Name, "", false, false); // Set Value back to an empty string since the Array object itself has no value, only its elements have - symbolDetails.top().Value = ""; + symbolDetails.top().Value.clear(); DWORD elementsCount; if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) diff --git a/src/server/shared/Define.h b/src/server/shared/Define.h index 2a04b8cdfad..2723d287c53 100644 --- a/src/server/shared/Define.h +++ b/src/server/shared/Define.h @@ -28,6 +28,14 @@ # if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS # endif +# if !defined(_GLIBCXX_USE_NANOSLEEP) +# define _GLIBCXX_USE_NANOSLEEP +# endif +# if defined(HELGRIND) +# include <valgrind/helgrind.h> +# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) ANNOTATE_HAPPENS_BEFORE(A) +# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) ANNOTATE_HAPPENS_AFTER(A) +# endif #endif #include <cstddef> @@ -47,6 +55,7 @@ #if PLATFORM == PLATFORM_WINDOWS # define TRINITY_PATH_MAX MAX_PATH +# define _USE_MATH_DEFINES # ifndef DECLSPEC_NORETURN # define DECLSPEC_NORETURN __declspec(noreturn) # endif //DECLSPEC_NORETURN @@ -84,6 +93,8 @@ #define SI64FMTD "%" PRId64 #define SI64LIT(N) INT64_C(N) +#define SZFMTD "%" PRIuPTR + typedef int64_t int64; typedef int32_t int32; typedef int16_t int16; diff --git a/src/server/shared/Dynamic/LinkedList.h b/src/server/shared/Dynamic/LinkedList.h index 402aaf3d40c..87bbeaac380 100644 --- a/src/server/shared/Dynamic/LinkedList.h +++ b/src/server/shared/Dynamic/LinkedList.h @@ -150,7 +150,7 @@ class LinkedListHead typedef _Ty& reference; typedef _Ty const & const_reference; - Iterator() : _Ptr(0) + Iterator() : _Ptr(nullptr) { // construct with null node pointer } diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h index b8f15b4fa0f..5b66f86650d 100644 --- a/src/server/shared/Logging/AppenderConsole.h +++ b/src/server/shared/Logging/AppenderConsole.h @@ -51,7 +51,7 @@ class AppenderConsole: public Appender private: void SetColor(bool stdout_stream, ColorTypes color); void ResetColor(bool stdout_stream); - void _write(LogMessage const& message); + void _write(LogMessage const& message) override; bool _colored; ColorTypes _colors[MaxLogLevels]; }; diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h index 660992261fd..b86252d0d67 100644 --- a/src/server/shared/Logging/AppenderDB.h +++ b/src/server/shared/Logging/AppenderDB.h @@ -31,7 +31,7 @@ class AppenderDB: public Appender private: uint32 realmId; bool enabled; - void _write(LogMessage const& message); + void _write(LogMessage const& message) override; }; #endif diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index a600c92d152..37ba2769e19 100644 --- a/src/server/shared/Logging/AppenderFile.h +++ b/src/server/shared/Logging/AppenderFile.h @@ -30,7 +30,7 @@ class AppenderFile: public Appender private: void CloseFile(); - void _write(LogMessage const& message); + void _write(LogMessage const& message) override; FILE* logfile; std::string filename; std::string logDir; diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index a7b6b418cc4..3305b364f0f 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -334,7 +334,7 @@ bool Log::SetLogLevel(std::string const& name, const char* newLevelc, bool isLog return true; } -void Log::outCharDump(char const* str, uint32 accountId, uint32 guid, char const* name) +void Log::outCharDump(char const* str, uint32 accountId, uint64 guid, char const* name) { if (!str || !ShouldLog("entities.player.dump", LOG_LEVEL_INFO)) return; diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 78e7e012bbe..e2d4baa5f0e 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -62,7 +62,7 @@ class Log void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5); void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4); - void outCharDump(char const* str, uint32 account_id, uint32 guid, char const* name); + void outCharDump(char const* str, uint32 account_id, uint64 guid, char const* name); void SetRealmId(uint32 id); diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index d056731bb79..c8f8e2dbd90 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -18,48 +18,73 @@ #ifndef __ASYNCACCEPT_H_ #define __ASYNCACCEPT_H_ +#include "Log.h" #include <boost/asio.hpp> using boost::asio::ip::tcp; -template <class T> class AsyncAcceptor { public: - AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port) : - _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)), - _socket(ioService) - { - AsyncAccept(); - }; + typedef void(*ManagerAcceptHandler)(tcp::socket&& newSocket); - AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port, bool tcpNoDelay) : + AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) : _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)), _socket(ioService) { - _acceptor.set_option(boost::asio::ip::tcp::no_delay(tcpNoDelay)); + } - AsyncAccept(); - }; + template <class T> + void AsyncAccept(); -private: - void AsyncAccept() + void AsyncAcceptManaged(ManagerAcceptHandler mgrHandler) { - _acceptor.async_accept(_socket, [this](boost::system::error_code error) + _acceptor.async_accept(_socket, [this, mgrHandler](boost::system::error_code error) { if (!error) { - // this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class - std::make_shared<T>(std::move(this->_socket))->Start(); + try + { + _socket.non_blocking(true); + + mgrHandler(std::move(_socket)); + } + catch (boost::system::system_error const& err) + { + TC_LOG_INFO("network", "Failed to initialize client's socket %s", err.what()); + } } - // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face - this->AsyncAccept(); + AsyncAcceptManaged(mgrHandler); }); } +private: tcp::acceptor _acceptor; tcp::socket _socket; }; +template<class T> +void AsyncAcceptor::AsyncAccept() +{ + _acceptor.async_accept(_socket, [this](boost::system::error_code error) + { + if (!error) + { + try + { + // this-> is required here to fix an segmentation fault in gcc 4.7.2 - reason is lambdas in a templated class + std::make_shared<T>(std::move(this->_socket))->Start(); + } + catch (boost::system::system_error const& err) + { + TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what()); + } + } + + // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face + this->AsyncAccept<T>(); + }); +} + #endif /* __ASYNCACCEPT_H_ */ diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h new file mode 100644 index 00000000000..2dcd4fbc161 --- /dev/null +++ b/src/server/shared/Networking/MessageBuffer.h @@ -0,0 +1,130 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __MESSAGEBUFFER_H_ +#define __MESSAGEBUFFER_H_ + +#include "Define.h" +#include <vector> + +class MessageBuffer +{ + typedef std::vector<uint8>::size_type size_type; + +public: + MessageBuffer() : _wpos(0), _rpos(0), _storage() + { + _storage.resize(4096); + } + + explicit MessageBuffer(std::size_t initialSize) : _wpos(0), _rpos(0), _storage() + { + _storage.resize(initialSize); + } + + MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right._storage) + { + } + + MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _rpos(right._rpos), _storage(right.Move()) { } + + void Reset() + { + _wpos = 0; + _rpos = 0; + } + + void Resize(size_type bytes) + { + _storage.resize(bytes); + } + + uint8* GetBasePointer() { return _storage.data(); } + + uint8* GetReadPointer() { return &_storage[_rpos]; } + + uint8* GetWritePointer() { return &_storage[_wpos]; } + + void ReadCompleted(size_type bytes) { _rpos += bytes; } + + void WriteCompleted(size_type bytes) { _wpos += bytes; } + + size_type GetActiveSize() const { return _wpos - _rpos; } + + size_type GetRemainingSpace() const { return _storage.size() - _wpos; } + + size_type GetBufferSize() const { return _storage.size(); } + + // Discards inactive data + void Normalize() + { + if (_rpos) + { + if (_rpos != _wpos) + memmove(GetBasePointer(), GetReadPointer(), GetActiveSize()); + _wpos -= _rpos; + _rpos = 0; + } + } + + void Write(void const* data, std::size_t size) + { + if (size) + { + memcpy(GetWritePointer(), data, size); + WriteCompleted(size); + } + } + + std::vector<uint8>&& Move() + { + _wpos = 0; + _rpos = 0; + return std::move(_storage); + } + + MessageBuffer& operator=(MessageBuffer& right) + { + if (this != &right) + { + _wpos = right._wpos; + _rpos = right._rpos; + _storage = right._storage; + } + + return *this; + } + + MessageBuffer& operator=(MessageBuffer&& right) + { + if (this != &right) + { + _wpos = right._wpos; + _rpos = right._rpos; + _storage = right.Move(); + } + + return *this; + } + +private: + size_type _wpos; + size_type _rpos; + std::vector<uint8> _storage; +}; + +#endif /* __MESSAGEBUFFER_H_ */ diff --git a/src/server/shared/Networking/NetworkThread.h b/src/server/shared/Networking/NetworkThread.h new file mode 100644 index 00000000000..043aee56504 --- /dev/null +++ b/src/server/shared/Networking/NetworkThread.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NetworkThread_h__ +#define NetworkThread_h__ + +#include "Define.h" +#include "Errors.h" +#include "Log.h" +#include "Timer.h" +#include <atomic> +#include <chrono> +#include <memory> +#include <mutex> +#include <set> +#include <thread> + +template<class SocketType> +class NetworkThread +{ +public: + NetworkThread() : _connections(0), _stopped(false), _thread(nullptr) + { + } + + virtual ~NetworkThread() + { + Stop(); + if (_thread) + { + Wait(); + delete _thread; + } + } + + void Stop() + { + _stopped = true; + } + + bool Start() + { + if (_thread) + return false; + + _thread = new std::thread(&NetworkThread::Run, this); + return true; + } + + void Wait() + { + ASSERT(_thread); + + _thread->join(); + delete _thread; + _thread = nullptr; + } + + int32 GetConnectionCount() const + { + return _connections; + } + + virtual void AddSocket(std::shared_ptr<SocketType> sock) + { + std::lock_guard<std::mutex> lock(_newSocketsLock); + + ++_connections; + _newSockets.insert(sock); + SocketAdded(sock); + } + +protected: + virtual void SocketAdded(std::shared_ptr<SocketType> /*sock*/) { } + virtual void SocketRemoved(std::shared_ptr<SocketType> /*sock*/) { } + + void AddNewSockets() + { + std::lock_guard<std::mutex> lock(_newSocketsLock); + + if (_newSockets.empty()) + return; + + for (typename SocketSet::const_iterator i = _newSockets.begin(); i != _newSockets.end(); ++i) + { + if (!(*i)->IsOpen()) + { + SocketRemoved(*i); + + --_connections; + } + else + _Sockets.insert(*i); + } + + _newSockets.clear(); + } + + void Run() + { + TC_LOG_DEBUG("misc", "Network Thread Starting"); + + typename SocketSet::iterator i, t; + + uint32 sleepTime = 10; + uint32 tickStart = 0, diff = 0; + while (!_stopped) + { + std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); + + tickStart = getMSTime(); + + AddNewSockets(); + + for (i = _Sockets.begin(); i != _Sockets.end();) + { + if (!(*i)->Update()) + { + if ((*i)->IsOpen()) + (*i)->CloseSocket(); + + SocketRemoved(*i); + + --_connections; + _Sockets.erase(i++); + } + else + ++i; + } + + diff = GetMSTimeDiffToNow(tickStart); + sleepTime = diff > 10 ? 0 : 10 - diff; + } + + TC_LOG_DEBUG("misc", "Network Thread exits"); + } + +private: + typedef std::set<std::shared_ptr<SocketType> > SocketSet; + + std::atomic<int32> _connections; + std::atomic<bool> _stopped; + + std::thread* _thread; + + SocketSet _Sockets; + + std::mutex _newSocketsLock; + SocketSet _newSockets; +}; + +#endif // NetworkThread_h__ diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index 38d88e3592c..d3e29ceaaea 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -18,8 +18,9 @@ #ifndef __SOCKET_H__ #define __SOCKET_H__ -#include "Define.h" +#include "MessageBuffer.h" #include "Log.h" +#include <atomic> #include <vector> #include <mutex> #include <queue> @@ -28,129 +29,276 @@ #include <type_traits> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/write.hpp> +#include <boost/asio/read.hpp> using boost::asio::ip::tcp; -template<class T, class PacketType> +#define READ_BLOCK_SIZE 4096 +#define TC_SOCKET_USE_IOCP BOOST_ASIO_HAS_IOCP + +template<class T> class Socket : public std::enable_shared_from_this<T> { - typedef typename std::conditional<std::is_pointer<PacketType>::value, PacketType, PacketType const&>::type WritePacketType; - public: - Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _headerSize(headerSize) { } + explicit Socket(tcp::socket&& socket) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()), + _remotePort(_socket.remote_endpoint().port()), _readBuffer(), _closed(false), _closing(false), _isWritingAsync(false) + { + _readBuffer.Resize(READ_BLOCK_SIZE); + } + + virtual ~Socket() + { + boost::system::error_code error; + _socket.close(error); + } virtual void Start() = 0; - boost::asio::ip::address GetRemoteIpAddress() const + virtual bool Update() { - boost::system::error_code error; - auto ep = _socket.remote_endpoint(error); + if (!IsOpen()) + return false; - if (error) - { - TC_LOG_DEBUG("network", "Socket::GetRemoteIpAddress: errored with: %i (%s)", error.value(), error.message().c_str()); - return boost::asio::ip::address(); - } - else - return ep.address(); +#ifndef TC_SOCKET_USE_IOCP + std::unique_lock<std::mutex> guard(_writeLock, std::try_to_lock); + if (!guard) + return true; + + if (_isWritingAsync || (!_writeBuffer.GetActiveSize() && _writeQueue.empty())) + return true; + + for (; WriteHandler(guard);) + ; +#endif + + return true; } - uint16 GetRemotePort() const + boost::asio::ip::address GetRemoteIpAddress() const { - boost::system::error_code error; - auto ep = _socket.remote_endpoint(error); - - if (error) - { - TC_LOG_DEBUG("network", "Socket::GetRemotePort: errored with: %i (%s)", error.value(), error.message().c_str()); - return 0; - } - else - return ep.port(); + return _remoteAddress; } - void AsyncReadHeader() + uint16 GetRemotePort() const { - _socket.async_read_some(boost::asio::buffer(_readBuffer, _headerSize), std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); + return _remotePort; } - void AsyncReadData(std::size_t size, std::size_t bufferOffset) + void AsyncRead() { - _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffset], size), std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); + if (!IsOpen()) + return; + + _readBuffer.Normalize(); + _socket.async_read_some(boost::asio::buffer(_readBuffer.GetWritePointer(), READ_BLOCK_SIZE), + std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } - void ReadData(std::size_t size, std::size_t bufferOffset) + void ReadData(std::size_t size) { + if (!IsOpen()) + return; + boost::system::error_code error; - _socket.read_some(boost::asio::buffer(&_readBuffer[bufferOffset], size), error); + std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readBuffer.GetWritePointer(), size), error); - if (error) + _readBuffer.WriteCompleted(bytesRead); + + if (error || bytesRead != size) { - TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(), error.message().c_str()); + TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(), + error.message().c_str()); CloseSocket(); } } - void AsyncWrite(WritePacketType data) + void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard) { - boost::asio::async_write(_socket, boost::asio::buffer(data), std::bind(&Socket<T, PacketType>::WriteHandler, this->shared_from_this(), std::placeholders::_1, - std::placeholders::_2)); + _writeQueue.push(std::move(buffer)); + +#ifdef TC_SOCKET_USE_IOCP + AsyncProcessQueue(guard); +#else + (void)guard; +#endif } - bool IsOpen() const { return _socket.is_open(); } + bool IsOpen() const { return !_closed && !_closing; } + void CloseSocket() { - boost::system::error_code error; - _socket.close(error); - if (error) - TC_LOG_DEBUG("network", "Socket::CloseSocket: %s errored when closing socket: %i (%s)", GetRemoteIpAddress().to_string().c_str(), - error.value(), error.message().c_str()); + if (_closed.exchange(true)) + return; + + boost::system::error_code shutdownError; + _socket.shutdown(boost::asio::socket_base::shutdown_send, shutdownError); + if (shutdownError) + TC_LOG_DEBUG("network", "Socket::CloseSocket: %s errored when shutting down socket: %i (%s)", GetRemoteIpAddress().to_string().c_str(), + shutdownError.value(), shutdownError.message().c_str()); } - uint8* GetReadBuffer() { return _readBuffer; } + /// Marks the socket for closing after write buffer becomes empty + void DelayedCloseSocket() { _closing = true; } + + MessageBuffer& GetReadBuffer() { return _readBuffer; } protected: - virtual void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) = 0; - virtual void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) = 0; + virtual void ReadHandler() = 0; + + bool AsyncProcessQueue(std::unique_lock<std::mutex>&) + { + if (_isWritingAsync) + return false; + + _isWritingAsync = true; + +#ifdef TC_SOCKET_USE_IOCP + MessageBuffer& buffer = _writeQueue.front(); + _socket.async_write_some(boost::asio::buffer(buffer.GetReadPointer(), buffer.GetActiveSize()), std::bind(&Socket<T>::WriteHandler, + this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); +#else + _socket.async_write_some(boost::asio::null_buffers(), std::bind(&Socket<T>::WriteHandlerWrapper, + this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); +#endif + + return false; + } std::mutex _writeLock; - std::queue<PacketType> _writeQueue; + std::queue<MessageBuffer> _writeQueue; +#ifndef TC_SOCKET_USE_IOCP + MessageBuffer _writeBuffer; +#endif private: - void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferedBytes) { ReadHeaderHandler(error, transferedBytes); } - void ReadDataHandlerInternal(boost::system::error_code error, size_t transferedBytes) { ReadDataHandler(error, transferedBytes); } + void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes) + { + if (error) + { + CloseSocket(); + return; + } + + _readBuffer.WriteCompleted(transferredBytes); + ReadHandler(); + } + +#ifdef TC_SOCKET_USE_IOCP - void WriteHandler(boost::system::error_code error, size_t /*transferedBytes*/) + void WriteHandler(boost::system::error_code error, std::size_t transferedBytes) { if (!error) { - std::lock_guard<std::mutex> deleteGuard(_writeLock); + std::unique_lock<std::mutex> deleteGuard(_writeLock); - DeletePacket(_writeQueue.front()); - _writeQueue.pop(); + _isWritingAsync = false; + _writeQueue.front().ReadCompleted(transferedBytes); + if (!_writeQueue.front().GetActiveSize()) + _writeQueue.pop(); if (!_writeQueue.empty()) - AsyncWrite(_writeQueue.front()); + AsyncProcessQueue(deleteGuard); + else if (_closing) + CloseSocket(); } else CloseSocket(); } - template<typename Q = PacketType> - typename std::enable_if<std::is_pointer<Q>::value>::type DeletePacket(PacketType& packet) { delete packet; } +#else + + void WriteHandlerWrapper(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/) + { + std::unique_lock<std::mutex> guard(_writeLock); + _isWritingAsync = false; + WriteHandler(guard); + } + + bool WriteHandler(std::unique_lock<std::mutex>& guard) + { + if (!IsOpen()) + return false; + + std::size_t bytesToSend = _writeBuffer.GetActiveSize(); + + if (bytesToSend == 0) + return HandleQueue(guard); + + boost::system::error_code error; + std::size_t bytesWritten = _socket.write_some(boost::asio::buffer(_writeBuffer.GetReadPointer(), bytesToSend), error); + + if (error) + { + if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) + return AsyncProcessQueue(guard); + + return false; + } + else if (bytesWritten == 0) + return false; + else if (bytesWritten < bytesToSend) + { + _writeBuffer.ReadCompleted(bytesWritten); + _writeBuffer.Normalize(); + return AsyncProcessQueue(guard); + } + + // now bytesWritten == bytesToSend + _writeBuffer.Reset(); + + return HandleQueue(guard); + } + + bool HandleQueue(std::unique_lock<std::mutex>& guard) + { + if (_writeQueue.empty()) + return false; + + MessageBuffer& queuedMessage = _writeQueue.front(); + + std::size_t bytesToSend = queuedMessage.GetActiveSize(); - template<typename Q = PacketType> - typename std::enable_if<!std::is_pointer<Q>::value>::type DeletePacket(PacketType const& /*packet*/) { } + boost::system::error_code error; + std::size_t bytesSent = _socket.write_some(boost::asio::buffer(queuedMessage.GetReadPointer(), bytesToSend), error); + + if (error) + { + if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) + return AsyncProcessQueue(guard); + + _writeQueue.pop(); + return false; + } + else if (bytesSent == 0) + { + _writeQueue.pop(); + return false; + } + else if (bytesSent < bytesToSend) // now n > 0 + { + queuedMessage.ReadCompleted(bytesSent); + return AsyncProcessQueue(guard); + } + + _writeQueue.pop(); + return !_writeQueue.empty(); + } + +#endif tcp::socket _socket; - uint8 _readBuffer[4096]; + boost::asio::ip::address _remoteAddress; + uint16 _remotePort; + + MessageBuffer _readBuffer; + + std::atomic<bool> _closed; + std::atomic<bool> _closing; - std::size_t _headerSize; + bool _isWritingAsync; }; #endif // __SOCKET_H__ diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h new file mode 100644 index 00000000000..dbe2b8ec902 --- /dev/null +++ b/src/server/shared/Networking/SocketMgr.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SocketMgr_h__ +#define SocketMgr_h__ + +#include "AsyncAcceptor.h" +#include "Config.h" +#include "Errors.h" +#include "NetworkThread.h" +#include <boost/asio/ip/tcp.hpp> +#include <memory> + +using boost::asio::ip::tcp; + +template<class SocketType> +class SocketMgr +{ +public: + virtual ~SocketMgr() + { + delete[] _threads; + } + + virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) + { + _threadCount = sConfigMgr->GetIntDefault("Network.Threads", 1); + + if (_threadCount <= 0) + { + TC_LOG_ERROR("misc", "Network.Threads is wrong in your config file"); + return false; + } + + _acceptor = new AsyncAcceptor(service, bindIp, port); + _threads = CreateThreads(); + + ASSERT(_threads); + + for (int32 i = 0; i < _threadCount; ++i) + _threads[i].Start(); + + return true; + } + + virtual void StopNetwork() + { + if (_threadCount != 0) + for (int32 i = 0; i < _threadCount; ++i) + _threads[i].Stop(); + + Wait(); + } + + void Wait() + { + if (_threadCount != 0) + for (int32 i = 0; i < _threadCount; ++i) + _threads[i].Wait(); + } + + virtual void OnSocketOpen(tcp::socket&& sock) + { + size_t min = 0; + + for (int32 i = 1; i < _threadCount; ++i) + if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount()) + min = i; + + try + { + std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock)); + newSocket->Start(); + + _threads[min].AddSocket(newSocket); + } + catch (boost::system::system_error const& err) + { + TC_LOG_INFO("network", "Failed to retrieve client's remote address %s", err.what()); + } + } + + int32 GetNetworkThreadCount() const { return _threadCount; } + +protected: + SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(1) + { + } + + virtual NetworkThread<SocketType>* CreateThreads() const = 0; + + AsyncAcceptor* _acceptor; + NetworkThread<SocketType>* _threads; + int32 _threadCount; +}; + +#endif // SocketMgr_h__ diff --git a/src/server/shared/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp index 0a911492f85..02713a30cc6 100644 --- a/src/server/shared/Packets/ByteBuffer.cpp +++ b/src/server/shared/Packets/ByteBuffer.cpp @@ -17,11 +17,15 @@ */ #include "ByteBuffer.h" +#include "MessageBuffer.h" #include "Common.h" #include "Log.h" - #include <sstream> +ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0), _storage(buffer.Move()) +{ +} + ByteBufferPositionException::ByteBufferPositionException(bool add, size_t pos, size_t size, size_t valueSize) { @@ -69,8 +73,8 @@ void ByteBuffer::textlike() const o << "STORAGE_SIZE: " << size(); for (uint32 i = 0; i < size(); ++i) { - char buf[1]; - snprintf(buf, 1, "%c", read<uint8>(i)); + char buf[2]; + snprintf(buf, 2, "%c", read<uint8>(i)); o << buf; } o << " "; @@ -90,7 +94,7 @@ void ByteBuffer::hexlike() const for (uint32 i = 0; i < size(); ++i) { char buf[3]; - snprintf(buf, 1, "%2X ", read<uint8>(i)); + snprintf(buf, 3, "%2X ", read<uint8>(i)); if ((i == (j * 8)) && ((i != (k * 16)))) { o << "| "; diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 520c1a85fc2..d65b6c58a51 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -31,16 +31,19 @@ #include <vector> #include <cstring> #include <time.h> -#include <math.h> +#include <cmath> +#include <type_traits> #include <boost/asio/buffer.hpp> +class MessageBuffer; + // Root of ByteBuffer exception hierarchy class ByteBufferException : public std::exception { public: ~ByteBufferException() throw() { } - char const* what() const throw() { return msg_.c_str(); } + char const* what() const throw() override { return msg_.c_str(); } protected: std::string & message() throw() { return msg_; } @@ -68,28 +71,27 @@ public: class ByteBuffer { public: - const static size_t DEFAULT_SIZE = 0x1000; + static size_t const DEFAULT_SIZE = 0x1000; + static uint8 const InitialBitPos = 8; // constructor - ByteBuffer() : _rpos(0), _wpos(0), _bitpos(8), _curbitval(0) + ByteBuffer() : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0) { _storage.reserve(DEFAULT_SIZE); } - ByteBuffer(size_t reserve) : _rpos(0), _wpos(0), _bitpos(8), _curbitval(0) + ByteBuffer(size_t reserve) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0) { _storage.reserve(reserve); } ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos), - _bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf._storage)) - { - } + _bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf._storage)) { } ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos), - _bitpos(right._bitpos), _curbitval(right._curbitval), _storage(right._storage) - { - } + _bitpos(right._bitpos), _curbitval(right._curbitval), _storage(right._storage) { } + + ByteBuffer(MessageBuffer&& buffer); ByteBuffer& operator=(ByteBuffer const& right) { @@ -115,7 +117,7 @@ class ByteBuffer template <typename T> void append(T value) { - FlushBits(); + static_assert(std::is_fundamental<T>::value, "append(compound)"); EndianConvert(value); append((uint8 *)&value, sizeof(value)); } @@ -125,9 +127,10 @@ class ByteBuffer if (_bitpos == 8) return; + _bitpos = 8; + append((uint8 *)&_curbitval, sizeof(uint8)); _curbitval = 0; - _bitpos = 8; } bool WriteBit(uint32 bit) @@ -189,6 +192,7 @@ class ByteBuffer template <typename T> void put(size_t pos, T value) { + static_assert(std::is_fundamental<T>::value, "append(compound)"); EndianConvert(value); put(pos, (uint8 *)&value, sizeof(value)); } @@ -579,6 +583,8 @@ class ByteBuffer ASSERT(size() < 10000000); + FlushBits(); + if (_storage.size() < _wpos + cnt) _storage.resize(_wpos + cnt); std::memcpy(&_storage[_wpos], src, cnt); diff --git a/src/server/shared/Threading/ProcessPriority.h b/src/server/shared/Threading/ProcessPriority.h index 06a5622fb9d..6446820e32d 100644 --- a/src/server/shared/Threading/ProcessPriority.h +++ b/src/server/shared/Threading/ProcessPriority.h @@ -26,13 +26,13 @@ #define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 #endif -void SetProcessPriority(const std::string logChannel) +void SetProcessPriority(const std::string& logChannel) { // Suppresses Mac OS X Warning since logChannel isn't used. #if PLATFORM_APPLE (void)logChannel; #endif - + #if defined(_WIN32) || defined(__linux__) ///- Handle affinity for multiple processors and process priority diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h index 1fee1d0685f..d0b3631a9dd 100644 --- a/src/server/shared/Threading/ProducerConsumerQueue.h +++ b/src/server/shared/Threading/ProducerConsumerQueue.h @@ -39,10 +39,8 @@ public: void Push(const T& value) { - { - std::lock_guard<std::mutex> lock(_queueLock); - _queue.push(std::move(value)); - } + std::lock_guard<std::mutex> lock(_queueLock); + _queue.push(std::move(value)); _condition.notify_one(); } @@ -58,7 +56,7 @@ public: { std::lock_guard<std::mutex> lock(_queueLock); - if (_queue.empty()) + if (_queue.empty() || _shutdown) return false; value = _queue.front(); @@ -72,12 +70,9 @@ public: { std::unique_lock<std::mutex> lock(_queueLock); - while (_queue.empty() && !_shutdown) - { - _condition.wait(lock); - } + _condition.wait(lock, [this]() { return !_queue.empty() || _shutdown; }); - if (_queue.empty()) + if (_queue.empty() || _shutdown) return; value = _queue.front(); @@ -87,7 +82,7 @@ public: void Cancel() { - _queueLock.lock(); + std::unique_lock<std::mutex> lock(_queueLock); while (!_queue.empty()) { @@ -100,8 +95,6 @@ public: _shutdown = true; - _queueLock.unlock(); - _condition.notify_all(); } diff --git a/src/server/shared/Utilities/ServiceWin32.cpp b/src/server/shared/Utilities/ServiceWin32.cpp index ecf403423f7..6e5309d70d7 100644 --- a/src/server/shared/Utilities/ServiceWin32.cpp +++ b/src/server/shared/Utilities/ServiceWin32.cpp @@ -204,7 +204,8 @@ void WINAPI ServiceMain(DWORD argc, char *argv[]) GetModuleFileName(0, path, sizeof(path)/sizeof(path[0])); - for (i = 0; i < std::strlen(path); i++) + size_t pathLen = std::strlen(path); + for (i = 0; i < pathLen; i++) { if (path[i] == '\\') last_slash = i; } diff --git a/src/server/shared/Utilities/Timer.h b/src/server/shared/Utilities/Timer.h index 7c62de5f5ed..0e2d6ddbff5 100644 --- a/src/server/shared/Utilities/Timer.h +++ b/src/server/shared/Utilities/Timer.h @@ -27,7 +27,7 @@ inline uint32 getMSTime() { static const system_clock::time_point ApplicationStartTime = system_clock::now(); - return duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count(); + return uint32(duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count()); } inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index a5279eae03f..c4049ae6315 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -18,13 +18,14 @@ #include "Util.h" #include "Common.h" +#include "CompilerDefs.h" #include "utf8.h" #include "SFMT.h" #include "Errors.h" // for ASSERT #include <stdarg.h> #include <boost/thread/tss.hpp> -#if PLATFORM == PLATFORM_UNIX +#if COMPILER == COMPILER_GNU #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -293,7 +294,7 @@ size_t utf8length(std::string& utf8str) } catch(std::exception) { - utf8str = ""; + utf8str.clear(); return 0; } } @@ -315,7 +316,7 @@ void utf8truncate(std::string& utf8str, size_t len) } catch(std::exception) { - utf8str = ""; + utf8str.clear(); } } @@ -359,7 +360,7 @@ bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr) } catch(std::exception) { - wstr = L""; + wstr.clear(); return false; } @@ -382,14 +383,14 @@ bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str) } catch(std::exception) { - utf8str = ""; + utf8str.clear(); return false; } return true; } -bool WStrToUtf8(std::wstring wstr, std::string& utf8str) +bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str) { try { @@ -405,7 +406,7 @@ bool WStrToUtf8(std::wstring wstr, std::string& utf8str) } catch(std::exception) { - utf8str = ""; + utf8str.clear(); return false; } @@ -414,7 +415,7 @@ bool WStrToUtf8(std::wstring wstr, std::string& utf8str) typedef wchar_t const* const* wstrlist; -std::wstring GetMainPartOfName(std::wstring wname, uint32 declension) +std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension) { // supported only Cyrillic cases if (wname.size() < 1 || !isCyrillicCharacter(wname[0]) || declension > 5) @@ -491,7 +492,7 @@ bool consoleToUtf8(const std::string& conStr, std::string& utf8str) #endif } -bool Utf8FitTo(const std::string& str, std::wstring search) +bool Utf8FitTo(const std::string& str, std::wstring const& search) { std::wstring temp; diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index c8883773eed..73ee37eb079 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -147,7 +147,7 @@ inline bool Utf8toWStr(const std::string& utf8str, wchar_t* wstr, size_t& wsize) return Utf8toWStr(utf8str.c_str(), utf8str.size(), wstr, wsize); } -bool WStrToUtf8(std::wstring wstr, std::string& utf8str); +bool WStrToUtf8(std::wstring const& wstr, std::string& utf8str); // size==real string size bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str); @@ -331,11 +331,11 @@ inline void wstrToLower(std::wstring& str) std::transform( str.begin(), str.end(), str.begin(), wcharToLower ); } -std::wstring GetMainPartOfName(std::wstring wname, uint32 declension); +std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension); bool utf8ToConsole(const std::string& utf8str, std::string& conStr); bool consoleToUtf8(const std::string& conStr, std::string& utf8str); -bool Utf8FitTo(const std::string& str, std::wstring search); +bool Utf8FitTo(const std::string& str, std::wstring const& search); void utf8printf(FILE* out, const char *str, ...); void vutf8printf(FILE* out, const char *str, va_list* ap); bool Utf8ToUpperOnlyLatin(std::string& utf8String); @@ -620,7 +620,7 @@ class EventMap if (!phase) _phase = 0; else if (phase <= 8) - _phase = (1 << (phase - 1)); + _phase = uint8(1 << (phase - 1)); } /** @@ -631,7 +631,7 @@ class EventMap void AddPhase(uint8 phase) { if (phase && phase <= 8) - _phase |= (1 << (phase - 1)); + _phase |= uint8(1 << (phase - 1)); } /** @@ -642,7 +642,7 @@ class EventMap void RemovePhase(uint8 phase) { if (phase && phase <= 8) - _phase &= ~(1 << (phase - 1)); + _phase &= uint8(~(1 << (phase - 1))); } /** @@ -878,7 +878,6 @@ class EventMap */ EventStore _eventMap; - /** * @name _lastEvent * @brief Stores information on the most recently executed event |
