aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
authorSubv <subv2112@gmail.com>2014-06-23 16:35:54 -0500
committerSubv <subv2112@gmail.com>2014-06-23 16:35:54 -0500
commit0db743c4ff2885ae51319c897158cc8774b41a88 (patch)
tree06b1e7950dac31b879ae7802d40b7493b0c61ec4 /src/server/shared
parent28b61812cf0d87b84aefaa0889844b6288f93b93 (diff)
parentaa93a975469cca56e35adc1b5b501f4536be61f1 (diff)
Merge branch 'master' of github.com:TrinityCore/TrinityCore into boost
Conflicts: src/server/authserver/Server/AuthSession.cpp src/server/game/Server/WorldSession.h src/server/shared/Packets/ByteBuffer.cpp src/server/shared/Utilities/Util.h
Diffstat (limited to 'src/server/shared')
-rw-r--r--src/server/shared/Containers.h28
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h8
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp12
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h7
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp378
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.h137
-rw-r--r--src/server/shared/Logging/Log.cpp15
-rw-r--r--src/server/shared/Logging/Log.h52
-rw-r--r--src/server/shared/Packets/ByteBuffer.cpp4
-rw-r--r--src/server/shared/Packets/ByteBuffer.h19
-rw-r--r--src/server/shared/Utilities/Util.cpp9
-rw-r--r--src/server/shared/Utilities/Util.h343
12 files changed, 819 insertions, 193 deletions
diff --git a/src/server/shared/Containers.h b/src/server/shared/Containers.h
index d6ba98e4ed4..9121fbe2a97 100644
--- a/src/server/shared/Containers.h
+++ b/src/server/shared/Containers.h
@@ -64,6 +64,34 @@ namespace Trinity
std::advance(it, urand(0, container.size() - 1));
return *it;
}
+
+ /**
+ * @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2)
+ *
+ * @brief Checks if two SORTED containers have a common element
+ *
+ * @param first1 Iterator pointing to start of the first container
+ * @param last1 Iterator pointing to end of the first container
+ * @param first2 Iterator pointing to start of the second container
+ * @param last2 Iterator pointing to end of the second container
+ *
+ * @return true if containers have a common element, false otherwise.
+ */
+ template<class Iterator1, class Iterator2>
+ bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2)
+ {
+ while (first1 != last1 && first2 != last2)
+ {
+ if (*first1 < *first2)
+ ++first1;
+ else if (*first2 < *first1)
+ ++first2;
+ else
+ return true;
+ }
+
+ return false;
+ }
}
//! namespace Containers
}
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index c60458323f7..9c56c75bf71 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -49,8 +49,10 @@ class DatabaseWorkerPool
{
public:
/* Activity state */
- DatabaseWorkerPool() : _queue(new ACE_Activation_Queue()), _connectionInfo(NULL)
+ DatabaseWorkerPool() : _connectionInfo(NULL)
{
+ _messageQueue = new ACE_Message_Queue<ACE_SYNCH>(8 * 1024 * 1024, 8 * 1024 * 1024);
+ _queue = new ACE_Activation_Queue(_messageQueue);
memset(_connectionCount, 0, sizeof(_connectionCount));
_connections.resize(IDX_SIZE);
@@ -97,7 +99,7 @@ class DatabaseWorkerPool
(_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.", GetDatabaseName());
+ "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", GetDatabaseName());
return res;
}
@@ -131,6 +133,7 @@ class DatabaseWorkerPool
//! Deletes the ACE_Activation_Queue object and its underlying ACE_Message_Queue
delete _queue;
+ delete _messageQueue;
TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
@@ -520,6 +523,7 @@ class DatabaseWorkerPool
IDX_SIZE
};
+ ACE_Message_Queue<ACE_SYNCH>* _messageQueue; //! Message Queue used by ACE_Activation_Queue
ACE_Activation_Queue* _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/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index de1e5b992e6..488ff18dca4 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -69,6 +69,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_UPD_LAST_ATTEMPT_IP, "UPDATE account SET last_attempt_ip = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_OLD_LOGS, "DELETE FROM logs WHERE (time + ?) < ?", CONNECTION_ASYNC);
@@ -90,12 +91,21 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH);
-
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_AccountLoginDeLete_IP_Logging"
+ PrepareStatement(LOGIN_INS_ALDL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_FailedAccountLogin_IP_Logging"
+ PrepareStatement(LOGIN_INS_FACL_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, (SELECT last_attempt_ip FROM account WHERE id = ?), ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: uint32, 1: uint32, 2: uint8, 3: string, 4: string // Complete name: "Login_Insert_CharacterDelete_IP_Logging"
+ PrepareStatement(LOGIN_INS_CHAR_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES (?, ?, ?, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
+ // 0: string, 1: string, 2: string // Complete name: "Login_Insert_Failed_Account_Login_due_password_IP_Logging"
+ PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 01f9fd973b6..604e9d39551 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -89,6 +89,7 @@ enum LoginDatabaseStatements
LOGIN_UPD_MUTE_TIME,
LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP,
+ LOGIN_UPD_LAST_ATTEMPT_IP,
LOGIN_UPD_ACCOUNT_ONLINE,
LOGIN_UPD_UPTIME_PLAYERS,
LOGIN_DEL_OLD_LOGS,
@@ -114,7 +115,13 @@ enum LoginDatabaseStatements
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_IP2NATION_COUNTRY,
LOGIN_SEL_AUTOBROADCAST,
+ LOGIN_SEL_LAST_ATTEMPT_IP,
+ LOGIN_SEL_LAST_IP,
LOGIN_GET_EMAIL_BY_ID,
+ LOGIN_INS_ALDL_IP_LOGGING,
+ LOGIN_INS_FACL_IP_LOGGING,
+ LOGIN_INS_CHAR_IP_LOGGING,
+ LOGIN_INS_FALP_IP_LOGGING,
LOGIN_SEL_ACCOUNT_ACCESS_BY_ID,
LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS,
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index 3b6bd3d2cc8..d5ad7f15a04 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -45,7 +45,7 @@ inline LPTSTR ErrorMessage(DWORD dw)
sprintf(msgBuf, "Unknown error: %u", dw);
return msgBuf;
}
-
+
}
//============================== Global Variables =============================
@@ -60,6 +60,7 @@ HANDLE WheatyExceptionReport::m_hReportFile;
HANDLE WheatyExceptionReport::m_hDumpFile;
HANDLE WheatyExceptionReport::m_hProcess;
SymbolPairs WheatyExceptionReport::symbols;
+std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails;
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -767,18 +768,21 @@ ULONG /*SymbolSize*/,
PVOID UserContext)
{
- char szBuffer[1024 * 64];
+ char szBuffer[WER_LARGE_BUFFER_SIZE];
+ memset(szBuffer, 0, sizeof(szBuffer));
__try
{
ClearSymbols();
if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext,
szBuffer, sizeof(szBuffer)))
- _tprintf(_T("\t%s\r\n"), szBuffer);
+ _tprintf(_T("%s"), szBuffer);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
- _tprintf(_T("punting on symbol %s\r\n"), pSymInfo->Name);
+ _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name);
+ if (szBuffer[0] != '\0')
+ _tprintf(_T("%s"), szBuffer);
}
return TRUE;
@@ -797,12 +801,6 @@ unsigned /*cbBuffer*/)
{
char * pszCurrBuffer = pszBuffer;
- // Indicate if the variable is a local or parameter
- if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Parameter ");
- else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
- pszCurrBuffer += sprintf(pszCurrBuffer, "Local ");
-
// If it's a function, don't do anything.
if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
return false;
@@ -824,19 +822,25 @@ unsigned /*cbBuffer*/)
// return false;
}
else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
- {
return false; // Don't try to report register variable
- }
else
{
pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
}
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+
+ // Indicate if the variable is a local or parameter
+ if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
+ symbolDetails.top().Prefix = "Parameter ";
+ else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
+ symbolDetails.top().Prefix = "Local ";
+
// Determine if the variable is a user defined type (UDT). IF so, bHandled
// will return true.
bool bHandled;
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
- 0, pVariable, bHandled, pSym->Name, "");
+ 0, pVariable, bHandled, pSym->Name, "", false, true);
if (!bHandled)
{
@@ -844,15 +848,19 @@ unsigned /*cbBuffer*/)
// variable. Based on the size, we're assuming it's a char, WORD, or
// DWORD.
BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
// Emit the variable name
- pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", pSym->Name);
+ if (pSym->Name[0] != '\0')
+ symbolDetails.top().Name = pSym->Name;
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, pSym->Size,
- (PVOID)pVariable);
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
return true;
}
@@ -868,13 +876,15 @@ DWORD dwTypeIndex,
unsigned nestingLevel,
DWORD_PTR offset,
bool & bHandled,
-char* Name,
-char* suffix)
+const char* Name,
+char* suffix,
+bool newSymbol,
+bool logChildren)
{
bHandled = false;
- if (!StoreSymbol(dwTypeIndex, offset))
- return pszCurrBuffer;
+ if (newSymbol)
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
DWORD typeTag;
if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
@@ -890,19 +900,39 @@ char* suffix)
if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
{
LocalFree(pwszTypeName);
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", "std::string");
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, btStdString, 0, (PVOID)offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ symbolDetails.top().Type = "std::string";
+ char buffer[50];
+ FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
bHandled = true;
return pszCurrBuffer;
}
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
+ char buffer[200];
+ wcstombs(buffer, pwszTypeName, sizeof(buffer));
+ buffer[199] = '\0';
+ if (Name != NULL && Name[0] != '\0')
+ {
+ symbolDetails.top().Type = buffer;
+ symbolDetails.top().Name = Name;
+ }
+ else if (buffer[0] != '\0')
+ symbolDetails.top().Name = buffer;
+
LocalFree(pwszTypeName);
}
+ else if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- if (strlen(suffix) > 0)
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s", suffix);
+ if (!StoreSymbol(dwTypeIndex, offset))
+ {
+ // Skip printing address and base class if it has been printed already
+ if (typeTag == SymTagBaseClass)
+ bHandled = true;
+ return pszCurrBuffer;
+ }
DWORD innerTypeID;
switch (typeTag)
@@ -910,11 +940,9 @@ char* suffix)
case SymTagPointerType:
if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
{
-#define MAX_NESTING_LEVEL 5
- if (nestingLevel >= MAX_NESTING_LEVEL)
- break;
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
BOOL isReference;
SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
@@ -922,44 +950,56 @@ char* suffix)
memset(addressStr, 0, sizeof(addressStr));
if (isReference)
- addressStr[0] = '&';
+ symbolDetails.top().Suffix += "&";
else
- addressStr[0] = '*';
+ symbolDetails.top().Suffix += "*";
- DWORD_PTR address = *(PDWORD_PTR)offset;
- if (address == NULL)
- {
- pwszTypeName;
- if (SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMNAME,
- &pwszTypeName))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName);
- LocalFree(pwszTypeName);
- }
+ // Try to dereference the pointer in a try/except block since it might be invalid
+ DWORD_PTR address = DereferenceUnsafePointer(offset);
- pszCurrBuffer += sprintf(pszCurrBuffer, "%s = NULL\r\n", addressStr);
+ char buffer[50];
+ FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
- bHandled = true;
- return pszCurrBuffer;
- }
- else
- {
- FormatOutputValue(&addressStr[1], btVoid, sizeof(PVOID), (PVOID)offset);
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- address, bHandled, "", addressStr);
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+
+ // no need to log any children since the address is invalid anyway
+ if (address == NULL || address == DWORD_PTR(-1))
+ logChildren = false;
- if (!bHandled)
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ address, bHandled, Name, addressStr, false, logChildren);
+
+ if (!bHandled)
+ {
+ BasicType basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
+ if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ symbolDetails.top().Value = "<Unable to read memory>";
+ else
{
- BasicType basicType = GetBasicType(dwTypeIndex, modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the size of the child member
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType, length, (PVOID)address);
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
- bHandled = true;
- return pszCurrBuffer;
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)address, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+ bHandled = true;
+ return pszCurrBuffer;
+ }
+ else if (address == NULL)
+ symbolDetails.top().Value = "NULL";
+ else if (address == DWORD_PTR(-1))
+ {
+ symbolDetails.top().Value = "<Unable to read memory>";
+ bHandled = true;
+ return pszCurrBuffer;
}
}
break;
@@ -970,13 +1010,80 @@ char* suffix)
if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
break;
- if (innerTypeTag == SymTagPointerType)
+ switch (innerTypeTag)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " %s", Name);
+ case SymTagUDT:
+ if (nestingLevel >= WER_MAX_NESTING_LEVEL)
+ logChildren = false;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagPointerType:
+ if (Name != NULL && Name[0] != '\0')
+ symbolDetails.top().Name = Name;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ case SymTagArrayType:
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case SymTagArrayType:
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
+ {
+ symbolDetails.top().HasChildren = true;
+
+ BasicType basicType = btNoType;
+ pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
+ 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 = "";
+
+ DWORD elementsCount;
+ if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
+ symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
+ else
+ symbolDetails.top().Suffix += "[<unknown count>]";
- pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
- offset, bHandled, "", "");
+ if (!bHandled)
+ {
+ basicType = GetBasicType(dwTypeIndex, modBase);
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+ bHandled = true;
}
+
+ // Get the size of the child member
+ ULONG64 length;
+ SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
+
+ char buffer[50];
+ switch (basicType)
+ {
+ case btChar:
+ case btStdString:
+ FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ break;
+ default:
+ for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++)
+ {
+ pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
+ symbolDetails.top().Suffix += "[" + std::to_string(index) + "]";
+ FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer));
+ symbolDetails.top().Value = buffer;
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
+ }
+ break;
+ }
+
+ return pszCurrBuffer;
}
break;
case SymTagBaseType:
@@ -1013,26 +1120,37 @@ char* suffix)
return pszCurrBuffer;
}
- // Append a line feed
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
-
// Iterate through each of the children
for (unsigned i = 0; i < dwChildrenCount; i++)
{
DWORD symTag;
SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);
- if (symTag == SymTagFunction || symTag == SymTagTypedef)
+ if (symTag == SymTagFunction ||
+ symTag == SymTagEnum ||
+ symTag == SymTagTypedef ||
+ symTag == SymTagVTable)
continue;
- // Add appropriate indentation level (since this routine is recursive)
- for (unsigned j = 0; j <= nestingLevel+1; j++)
- pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+ // Ignore static fields
+ DWORD dataKind;
+ SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);
+ if (dataKind == DataIsStaticLocal ||
+ dataKind == DataIsGlobal ||
+ dataKind == DataIsStaticMember)
+ continue;
+
+
+ symbolDetails.top().HasChildren = true;
+ if (!logChildren)
+ {
+ bHandled = false;
+ return pszCurrBuffer;
+ }
// Recurse for each of the child types
bool bHandled2;
BasicType basicType = GetBasicType(children.ChildId[i], modBase);
- pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]);
// Get the offset of the child member, relative to its parent
DWORD dwMemberOffset;
@@ -1044,11 +1162,14 @@ char* suffix)
pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
children.ChildId[i], nestingLevel+1,
- dwFinalOffset, bHandled2, ""/*Name */, "");
+ dwFinalOffset, bHandled2, ""/*Name */, "", true, true);
// If the child wasn't a UDT, format it appropriately
if (!bHandled2)
{
+ if (symbolDetails.top().Type.empty())
+ symbolDetails.top().Type = rgBaseType[basicType];
+
// Get the real "TypeId" of the child. We need this for the
// SymGetTypeInfo(TI_GET_TYPEID) call below.
DWORD typeId;
@@ -1059,75 +1180,75 @@ char* suffix)
ULONG64 length;
SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
- pszCurrBuffer = FormatOutputValue(pszCurrBuffer, basicType,
- length, (PVOID)dwFinalOffset);
-
- pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n");
+ char buffer[50];
+ FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer));
+ symbolDetails.top().Value = buffer;
}
+
+ pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
}
bHandled = true;
return pszCurrBuffer;
}
-char * WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
+void WheatyExceptionReport::FormatOutputValue(char * pszCurrBuffer,
BasicType basicType,
DWORD64 length,
-PVOID pAddress)
+PVOID pAddress,
+size_t bufferSize)
{
__try
{
switch (basicType)
{
case btChar:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress);
+ {
+ if (strlen((char*)pAddress) > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress);
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress);
break;
+ }
case btStdString:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str());
+ {
+ std::string* value = static_cast<std::string*>(pAddress);
+ if (value->length() > bufferSize - 6)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, value->c_str());
+ else
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
break;
+ }
default:
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
if (length == 1)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
else if (length == 2)
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
else if (length == 4)
{
if (basicType == btFloat)
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress);
- }
- else if (basicType == btChar)
- {
- if (!IsBadStringPtr(*(PSTR*)pAddress, 32))
- {
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"",
- *(PSTR*)pAddress);
- }
- else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X",
- *(PDWORD)pAddress);
- }
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
}
else if (length == 8)
{
if (basicType == btFloat)
{
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%lf",
*(double *)pAddress);
}
else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X",
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X",
*(DWORD64*)pAddress);
}
else
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress);
#endif
}
break;
@@ -1136,13 +1257,11 @@ PVOID pAddress)
__except (EXCEPTION_EXECUTE_HANDLER)
{
#if _WIN64
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %I64X", (DWORD64*)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress);
#else
- pszCurrBuffer += sprintf(pszCurrBuffer, " <Unable to read memory> = %X", (PDWORD)pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress);
#endif
}
-
- return pszCurrBuffer;
}
BasicType
@@ -1170,13 +1289,25 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)
return btNoType;
}
+DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)
+{
+ __try
+ {
+ return *(PDWORD_PTR)address;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return DWORD_PTR(-1);
+ }
+}
+
//============================================================================
// Helper function that writes to the report file, and allows the user to use
// printf style formating
//============================================================================
int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...)
{
- TCHAR szBuff[1024 * 64];
+ TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
int retValue;
DWORD cbWritten;
va_list argptr;
@@ -1198,6 +1329,41 @@ bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset)
void WheatyExceptionReport::ClearSymbols()
{
symbols.clear();
+ while (!symbolDetails.empty())
+ symbolDetails.pop();
+}
+
+char* WheatyExceptionReport::PushSymbolDetail(char* pszCurrBuffer)
+{
+ // Log current symbol and then add another to the stack to keep the hierarchy format
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.emplace();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PopSymbolDetail(char* pszCurrBuffer)
+{
+ pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
+ symbolDetails.pop();
+ return pszCurrBuffer;
+}
+
+char* WheatyExceptionReport::PrintSymbolDetail(char* pszCurrBuffer)
+{
+ if (symbolDetails.empty())
+ return pszCurrBuffer;
+
+ // Don't log anything if has been logged already or if it's empty
+ if (symbolDetails.top().Logged || symbolDetails.top().empty())
+ return pszCurrBuffer;
+
+ // Add appropriate indentation level (since this routine is recursive)
+ for (size_t i = 0; i < symbolDetails.size(); i++)
+ pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
+
+ pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str());
+
+ return pszCurrBuffer;
}
#endif // _WIN32
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h
index f6d6b7f4b9e..9137b91aac9 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.h
+++ b/src/server/shared/Debugging/WheatyExceptionReport.h
@@ -5,12 +5,13 @@
#include <dbghelp.h>
#include <set>
-#if _MSC_VER < 1400
-# define countof(array) (sizeof(array) / sizeof(array[0]))
-#else
-# include <stdlib.h>
-# define countof _countof
-#endif // _MSC_VER < 1400
+#include <stdlib.h>
+#include <stack>
+#define countof _countof
+
+#define WER_MAX_ARRAY_ELEMENTS_COUNT 10
+#define WER_MAX_NESTING_LEVEL 5
+#define WER_LARGE_BUFFER_SIZE 1024 * 128
enum BasicType // Stolen from CVCONST.H in the DIA 2.0 SDK
{
@@ -37,40 +38,54 @@ enum BasicType // Stolen from CVCON
btStdString = 101
};
+enum DataKind // Stolen from CVCONST.H in the DIA 2.0 SDK
+{
+ DataIsUnknown,
+ DataIsLocal,
+ DataIsStaticLocal,
+ DataIsParam,
+ DataIsObjectPtr,
+ DataIsFileStatic,
+ DataIsGlobal,
+ DataIsMember,
+ DataIsStaticMember,
+ DataIsConstant
+};
+
const char* const rgBaseType[] =
{
- " <user defined> ", // btNoType = 0,
- " void ", // btVoid = 1,
- " char* ", // btChar = 2,
- " wchar_t* ", // btWChar = 3,
- " signed char ",
- " unsigned char ",
- " int ", // btInt = 6,
- " unsigned int ", // btUInt = 7,
- " float ", // btFloat = 8,
- " <BCD> ", // btBCD = 9,
- " bool ", // btBool = 10,
- " short ",
- " unsigned short ",
- " long ", // btLong = 13,
- " unsigned long ", // btULong = 14,
- " __int8 ",
- " __int16 ",
- " __int32 ",
- " __int64 ",
- " __int128 ",
- " unsigned __int8 ",
- " unsigned __int16 ",
- " unsigned __int32 ",
- " unsigned __int64 ",
- " unsigned __int128 ",
- " <currency> ", // btCurrency = 25,
- " <date> ", // btDate = 26,
- " VARIANT ", // btVariant = 27,
- " <complex> ", // btComplex = 28,
- " <bit> ", // btBit = 29,
- " BSTR ", // btBSTR = 30,
- " HRESULT " // btHresult = 31
+ "<user defined>", // btNoType = 0,
+ "void", // btVoid = 1,
+ "char",//char* // btChar = 2,
+ "wchar_t*", // btWChar = 3,
+ "signed char",
+ "unsigned char",
+ "int", // btInt = 6,
+ "unsigned int", // btUInt = 7,
+ "float", // btFloat = 8,
+ "<BCD>", // btBCD = 9,
+ "bool", // btBool = 10,
+ "short",
+ "unsigned short",
+ "long", // btLong = 13,
+ "unsigned long", // btULong = 14,
+ "int8",
+ "int16",
+ "int32",
+ "int64",
+ "int128",
+ "uint8",
+ "uint16",
+ "uint32",
+ "uint64",
+ "uint128",
+ "<currency>", // btCurrency = 25,
+ "<date>", // btDate = 26,
+ "VARIANT", // btVariant = 27,
+ "<complex>", // btComplex = 28,
+ "<bit>", // btBit = 29,
+ "BSTR", // btBSTR = 30,
+ "HRESULT" // btHresult = 31
};
struct SymbolPair
@@ -83,7 +98,7 @@ struct SymbolPair
bool operator<(const SymbolPair& other) const
{
- return _offset < other._offset ||
+ return _offset < other._offset ||
(_offset == other._offset && _type < other._type);
}
@@ -92,6 +107,39 @@ struct SymbolPair
};
typedef std::set<SymbolPair> SymbolPairs;
+struct SymbolDetail
+{
+ SymbolDetail() : Prefix(), Type(), Suffix(), Name(), Value(), Logged(false), HasChildren(false) {}
+
+ std::string ToString()
+ {
+ Logged = true;
+ std::string formatted = Prefix + Type + Suffix;
+ if (!Name.empty())
+ {
+ if (!formatted.empty())
+ formatted += " ";
+ formatted += Name;
+ }
+ if (!Value.empty())
+ formatted += " = " + Value;
+ return formatted;
+ }
+
+ bool empty() const
+ {
+ return Value.empty() && !HasChildren;
+ }
+
+ std::string Prefix;
+ std::string Type;
+ std::string Suffix;
+ std::string Name;
+ std::string Value;
+ bool Logged;
+ bool HasChildren;
+};
+
class WheatyExceptionReport
{
public:
@@ -122,11 +170,12 @@ class WheatyExceptionReport
static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer);
- static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, char*, char*);
+ static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char*, char*, bool, bool);
- static char * FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress);
+ static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize);
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase);
+ static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address);
static int __cdecl _tprintf(const TCHAR * format, ...);
@@ -141,6 +190,12 @@ class WheatyExceptionReport
static HANDLE m_hDumpFile;
static HANDLE m_hProcess;
static SymbolPairs symbols;
+ static std::stack<SymbolDetail> symbolDetails;
+
+ static char* PushSymbolDetail(char* pszCurrBuffer);
+ static char* PopSymbolDetail(char* pszCurrBuffer);
+ static char* PrintSymbolDetail(char* pszCurrBuffer);
+
};
extern WheatyExceptionReport g_WheatyExceptionReport; // global instance of class
diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp
index 5f1c284d80d..fd7aa84c0e9 100644
--- a/src/server/shared/Logging/Log.cpp
+++ b/src/server/shared/Logging/Log.cpp
@@ -250,13 +250,13 @@ void Log::ReadLoggersFromConfig()
AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE);
appenders[appender->getId()] = appender;
- Logger& rootLogger = loggers[LOGGER_ROOT];
- rootLogger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR);
- rootLogger.addAppender(appender->getId(), appender);
+ Logger& logger = loggers[LOGGER_ROOT];
+ logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR);
+ logger.addAppender(appender->getId(), appender);
- Logger& serverLogger = loggers["server"];
- serverLogger.Create("server", LOG_LEVEL_INFO);
- serverLogger.addAppender(appender->getId(), appender);
+ logger = loggers["server"];
+ logger.Create("server", LOG_LEVEL_ERROR);
+ logger.addAppender(appender->getId(), appender);
}
}
@@ -267,7 +267,7 @@ void Log::vlog(std::string const& filter, LogLevel level, char const* str, va_li
write(new LogMessage(level, filter, text));
}
-void Log::write(LogMessage* msg)
+void Log::write(LogMessage* msg) const
{
Logger const* logger = GetLoggerByType(msg->type);
msg->text.append("\n");
@@ -378,7 +378,6 @@ void Log::Close()
delete worker;
worker = NULL;
loggers.clear();
- cachedLoggers.clear();
for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it)
{
delete it->second;
diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h
index 5f404fcfe70..c3a47d14e9e 100644
--- a/src/server/shared/Logging/Log.h
+++ b/src/server/shared/Logging/Log.h
@@ -32,7 +32,6 @@
class Log
{
typedef std::unordered_map<std::string, Logger> LoggerMap;
- typedef std::unordered_map<std::string, Logger const*> CachedLoggerContainer;
private:
Log();
@@ -47,7 +46,7 @@ class Log
void LoadFromConfig();
void Close();
- bool ShouldLog(std::string const& type, LogLevel level);
+ bool ShouldLog(std::string const& type, LogLevel level) const;
bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true);
void outMessage(std::string const& f, LogLevel level, char const* str, ...) ATTR_PRINTF(4, 5);
@@ -60,9 +59,9 @@ class Log
private:
static std::string GetTimestampStr();
void vlog(std::string const& f, LogLevel level, char const* str, va_list argptr);
- void write(LogMessage* msg);
+ void write(LogMessage* msg) const;
- Logger const* GetLoggerByType(std::string const& type);
+ Logger const* GetLoggerByType(std::string const& type) const;
Appender* GetAppenderByName(std::string const& name);
uint8 NextAppenderId();
void CreateAppenderFromConfig(std::string const& name);
@@ -72,7 +71,6 @@ class Log
AppenderMap appenders;
LoggerMap loggers;
- CachedLoggerContainer cachedLoggers;
uint8 AppenderId;
std::string m_logsDir;
@@ -81,37 +79,29 @@ class Log
LogWorker* worker;
};
-inline Logger const* Log::GetLoggerByType(std::string const& originalType)
+inline Logger const* Log::GetLoggerByType(std::string const& type) const
{
- // Check if already cached
- CachedLoggerContainer::const_iterator itCached = cachedLoggers.find(originalType);
- if (itCached != cachedLoggers.end())
- return itCached->second;
-
- Logger const* logger = NULL;
- std::string type(originalType);
-
- do
- {
- // Search for the logger "type.subtype"
- LoggerMap::const_iterator it = loggers.find(type);
- if (it == loggers.end())
- {
- // Search for the logger "type", if our logger contains '.', otherwise search for LOGGER_ROOT
- size_t found = type.find_last_of(".");
- type = found != std::string::npos ? type.substr(0, found) : LOGGER_ROOT;
- }
- else
- logger = &(it->second);
- }
- while (!logger);
+ LoggerMap::const_iterator it = loggers.find(type);
+ if (it != loggers.end())
+ return &(it->second);
+
+ if (type == LOGGER_ROOT)
+ return NULL;
- cachedLoggers[originalType] = logger;
- return logger;
+ std::string parentLogger = LOGGER_ROOT;
+ size_t found = type.find_last_of(".");
+ if (found != std::string::npos)
+ parentLogger = type.substr(0,found);
+
+ return GetLoggerByType(parentLogger);
}
-inline bool Log::ShouldLog(std::string const& type, LogLevel level)
+inline bool Log::ShouldLog(std::string const& type, LogLevel level) const
{
+ // TODO: Use cache to store "Type.sub1.sub2": "Type" equivalence, should
+ // Speed up in cases where requesting "Type.sub1.sub2" but only configured
+ // Logger "Type"
+
Logger const* logger = GetLoggerByType(type);
if (!logger)
return false;
diff --git a/src/server/shared/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp
index 450c9a4fa6c..0a911492f85 100644
--- a/src/server/shared/Packets/ByteBuffer.cpp
+++ b/src/server/shared/Packets/ByteBuffer.cpp
@@ -29,7 +29,7 @@ ByteBufferPositionException::ByteBufferPositionException(bool add, size_t pos,
ss << "Attempted to " << (add ? "put" : "get") << " value with size: "
<< valueSize << " in ByteBuffer (pos: " << pos << " size: " << size
- << ")\n\n";
+ << ")";
message().assign(ss.str());
}
@@ -41,7 +41,7 @@ ByteBufferSourceException::ByteBufferSourceException(size_t pos, size_t size,
ss << "Attempted to put a "
<< (valueSize > 0 ? "NULL-pointer" : "zero-sized value")
- << " in ByteBuffer (pos: " << pos << " size: " << size << ")\n\n";
+ << " in ByteBuffer (pos: " << pos << " size: " << size << ")";
message().assign(ss.str());
}
diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h
index c375a3ffa75..81c6bcd977c 100644
--- a/src/server/shared/Packets/ByteBuffer.h
+++ b/src/server/shared/Packets/ByteBuffer.h
@@ -31,6 +31,7 @@
#include <vector>
#include <cstring>
#include <time.h>
+#include <math.h>
// Root of ByteBuffer exception hierarchy
class ByteBufferException : public std::exception
@@ -241,12 +242,16 @@ class ByteBuffer
ByteBuffer &operator>>(float &value)
{
value = read<float>();
+ if (!std::isfinite(value))
+ throw ByteBufferException();
return *this;
}
ByteBuffer &operator>>(double &value)
{
value = read<double>();
+ if (!std::isfinite(value))
+ throw ByteBufferException();
return *this;
}
@@ -377,9 +382,19 @@ class ByteBuffer
return *this;
}
- uint8 * contents() { return &_storage[0]; }
+ uint8 * contents()
+ {
+ if (_storage.empty())
+ throw ByteBufferException();
+ return &_storage[0];
+ }
- const uint8 *contents() const { return &_storage[0]; }
+ const uint8 *contents() const
+ {
+ if (_storage.empty())
+ throw ByteBufferException();
+ return &_storage[0];
+ }
size_t size() const { return _storage.size(); }
bool empty() const { return _storage.empty(); }
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index 4489367a7ea..a65f54f87fc 100644
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -552,3 +552,12 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str();
}
+
+uint32 EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first - _time;
+
+ return std::numeric_limits<uint32>::max();
+}
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index 34d76bbc71b..c384a6eeaed 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -26,6 +26,7 @@
#include <string>
#include <vector>
#include <list>
+#include <map>
// Searcher for map of structs
template<typename T, class S> struct Finder
@@ -560,4 +561,346 @@ bool CompareValues(ComparisionType type, T val1, T val2)
}
}
+class EventMap
+{
+ /**
+ * Internal storage type.
+ * Key: Time as uint32 when the event should occur.
+ * Value: The event data as uint32.
+ *
+ * Structure of event data:
+ * - Bit 0 - 15: Event Id.
+ * - Bit 16 - 23: Group
+ * - Bit 24 - 31: Phase
+ * - Pattern: 0xPPGGEEEE
+ */
+ typedef std::multimap<uint32, uint32> EventStore;
+
+ public:
+ EventMap() : _time(0), _phase(0), _lastEvent(0) { }
+
+ /**
+ * @name Reset
+ * @brief Removes all scheduled events and resets time and phase.
+ */
+ void Reset()
+ {
+ _eventMap.clear();
+ _time = 0;
+ _phase = 0;
+ }
+
+ /**
+ * @name Update
+ * @brief Updates the timer of the event map.
+ * @param time Value to be added to time.
+ */
+ void Update(uint32 time)
+ {
+ _time += time;
+ }
+
+ /**
+ * @name GetTimer
+ * @return Current timer value.
+ */
+ uint32 GetTimer() const
+ {
+ return _time;
+ }
+
+ /**
+ * @name GetPhaseMask
+ * @return Active phases as mask.
+ */
+ uint8 GetPhaseMask() const
+ {
+ return _phase;
+ }
+
+ /**
+ * @name Empty
+ * @return True, if there are no events scheduled.
+ */
+ bool Empty() const
+ {
+ return _eventMap.empty();
+ }
+
+ /**
+ * @name SetPhase
+ * @brief Sets the phase of the map (absolute).
+ * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase.
+ */
+ void SetPhase(uint8 phase)
+ {
+ if (!phase)
+ _phase = 0;
+ else if (phase <= 8)
+ _phase = (1 << (phase - 1));
+ }
+
+ /**
+ * @name AddPhase
+ * @brief Activates the given phase (bitwise).
+ * @param phase Phase which should be activated. Values: 1 - 8
+ */
+ void AddPhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase |= (1 << (phase - 1));
+ }
+
+ /**
+ * @name RemovePhase
+ * @brief Deactivates the given phase (bitwise).
+ * @param phase Phase which should be deactivated. Values: 1 - 8.
+ */
+ void RemovePhase(uint8 phase)
+ {
+ if (phase && phase <= 8)
+ _phase &= ~(1 << (phase - 1));
+ }
+
+ /**
+ * @name ScheduleEvent
+ * @brief Creates new event entry in map.
+ * @param eventId The id of the new event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
+ {
+ if (group && group <= 8)
+ eventId |= (1 << (group + 15));
+
+ if (phase && phase <= 8)
+ eventId |= (1 << (phase + 23));
+
+ _eventMap.insert(EventStore::value_type(_time + time, eventId));
+ }
+
+ /**
+ * @name RescheduleEvent
+ * @brief Cancels the given event and reschedules it.
+ * @param eventId The id of the event.
+ * @param time The time in milliseconds until the event occurs.
+ * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
+ * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
+ */
+ void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0)
+ {
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, time, group, phase);
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until the event occurs.
+ */
+ void Repeat(uint32 time)
+ {
+ _eventMap.insert(EventStore::value_type(_time + time, _lastEvent));
+ }
+
+ /**
+ * @name RepeatEvent
+ * @brief Repeats the mostly recently executed event.
+ * @param time Time until the event occurs. Equivalent to Repeat(urand(minTime, maxTime).
+ */
+ void Repeat(uint32 minTime, uint32 maxTime)
+ {
+ Repeat(urand(minTime, maxTime));
+ }
+
+ /**
+ * @name ExecuteEvent
+ * @brief Returns the next event to execute and removes it from map.
+ * @return Id of the event to execute.
+ */
+ uint32 ExecuteEvent()
+ {
+ while (!Empty())
+ {
+ EventStore::iterator itr = _eventMap.begin();
+
+ if (itr->first > _time)
+ return 0;
+ else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
+ _eventMap.erase(itr);
+ else
+ {
+ uint32 eventId = (itr->second & 0x0000FFFF);
+ _lastEvent = itr->second; // include phase/group
+ _eventMap.erase(itr);
+ return eventId;
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
+ * @param delay Amount of delay.
+ */
+ void DelayEvents(uint32 delay)
+ {
+ _time = delay < _time ? _time - delay : 0;
+ }
+
+ /**
+ * @name DelayEvents
+ * @brief Delay all events of the same group.
+ * @param delay Amount of delay.
+ * @param group Group of the events.
+ */
+ void DelayEvents(uint32 delay, uint32 group)
+ {
+ if (!group || group > 8 || Empty())
+ return;
+
+ EventStore delayed;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & (1 << (group + 15)))
+ {
+ delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
+ _eventMap.erase(itr++);
+ }
+ else
+ ++itr;
+ }
+
+ _eventMap.insert(delayed.begin(), delayed.end());
+ }
+
+ /**
+ * @name CancelEvent
+ * @brief Cancels all events of the specified id.
+ * @param eventId Event id to cancel.
+ */
+ void CancelEvent(uint32 eventId)
+ {
+ if (Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (eventId == (itr->second & 0x0000FFFF))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+ }
+
+ /**
+ * @name CancelEventGroup
+ * @brief Cancel events belonging to specified group.
+ * @param group Group to cancel.
+ */
+ void CancelEventGroup(uint32 group)
+ {
+ if (!group || group > 8 || Empty())
+ return;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & (1 << (group + 15)))
+ _eventMap.erase(itr++);
+ else
+ ++itr;
+ }
+ }
+
+ /**
+ * @name GetNextEventTime
+ * @brief Returns closest occurence of specified event.
+ * @param eventId Wanted event id.
+ * @return Time of found event.
+ */
+ uint32 GetNextEventTime(uint32 eventId) const
+ {
+ if (Empty())
+ return 0;
+
+ for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr)
+ if (eventId == (itr->second & 0x0000FFFF))
+ return itr->first;
+
+ return 0;
+ }
+
+ /**
+ * @name GetNextEventTime
+ * @return Time of next event.
+ */
+ uint32 GetNextEventTime() const
+ {
+ return Empty() ? 0 : _eventMap.begin()->first;
+ }
+
+ /**
+ * @name IsInPhase
+ * @brief Returns wether event map is in specified phase or not.
+ * @param phase Wanted phase.
+ * @return True, if phase of event map contains specified phase.
+ */
+ bool IsInPhase(uint8 phase)
+ {
+ return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
+ }
+
+ /**
+ * @name GetTimeUntilEvent
+ * @brief Returns time in milliseconds until next event.
+ * @param Id of the event.
+ * @return Time of next event.
+ */
+ uint32 GetTimeUntilEvent(uint32 eventId) const;
+
+ private:
+ /**
+ * @name _time
+ * @brief Internal timer.
+ *
+ * This does not represent the real date/time value.
+ * It's more like a stopwatch: It can run, it can be stopped,
+ * it can be resetted and so on. Events occur when this timer
+ * has reached their time value. Its value is changed in the
+ * Update method.
+ */
+ uint32 _time;
+
+ /**
+ * @name _phase
+ * @brief Phase mask of the event map.
+ *
+ * Contains the phases the event map is in. Multiple
+ * phases from 1 to 8 can be set with SetPhase or
+ * AddPhase. RemovePhase deactives a phase.
+ */
+ uint8 _phase;
+
+ /**
+ * @name _eventMap
+ * @brief Internal event storage map. Contains the scheduled events.
+ *
+ * See typedef at the beginning of the class for more
+ * details.
+ */
+ EventStore _eventMap;
+
+
+ /**
+ * @name _lastEvent
+ * @brief Stores information on the most recently executed event
+ */
+ uint32 _lastEvent;
+};
+
#endif