aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/shared')
-rw-r--r--src/server/shared/CMakeLists.txt1
-rw-r--r--src/server/shared/Common.h51
-rw-r--r--src/server/shared/Configuration/Config.cpp2
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.cpp6
-rw-r--r--src/server/shared/Database/DatabaseWorker.cpp2
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h100
-rw-r--r--src/server/shared/Database/Field.h16
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp13
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h8
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp12
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h6
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.cpp8
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.h5
-rw-r--r--src/server/shared/Database/MySQLConnection.cpp7
-rw-r--r--src/server/shared/Database/PreparedStatement.h2
-rw-r--r--src/server/shared/Database/QueryHolder.cpp8
-rw-r--r--src/server/shared/Database/QueryHolder.h10
-rw-r--r--src/server/shared/Database/QueryResult.cpp2
-rw-r--r--src/server/shared/Database/Transaction.h2
-rw-r--r--src/server/shared/Debugging/Errors.cpp16
-rw-r--r--src/server/shared/Debugging/Errors.h4
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp2
-rw-r--r--src/server/shared/Define.h11
-rw-r--r--src/server/shared/Dynamic/LinkedList.h2
-rw-r--r--src/server/shared/Logging/AppenderConsole.h2
-rw-r--r--src/server/shared/Logging/AppenderDB.h2
-rw-r--r--src/server/shared/Logging/AppenderFile.h2
-rw-r--r--src/server/shared/Logging/Log.cpp2
-rw-r--r--src/server/shared/Logging/Log.h2
-rw-r--r--src/server/shared/Networking/AsyncAcceptor.h61
-rw-r--r--src/server/shared/Networking/MessageBuffer.h130
-rw-r--r--src/server/shared/Networking/NetworkThread.h166
-rw-r--r--src/server/shared/Networking/Socket.h272
-rw-r--r--src/server/shared/Networking/SocketMgr.h111
-rw-r--r--src/server/shared/Packets/ByteBuffer.cpp12
-rw-r--r--src/server/shared/Packets/ByteBuffer.h32
-rw-r--r--src/server/shared/Threading/ProcessPriority.h4
-rw-r--r--src/server/shared/Threading/ProducerConsumerQueue.h19
-rw-r--r--src/server/shared/Utilities/ServiceWin32.cpp3
-rw-r--r--src/server/shared/Utilities/Timer.h2
-rw-r--r--src/server/shared/Utilities/Util.cpp19
-rw-r--r--src/server/shared/Utilities/Util.h13
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