diff options
Diffstat (limited to 'src/server/shared')
107 files changed, 2680 insertions, 2142 deletions
diff --git a/src/server/shared/AutoPtr.h b/src/server/shared/AutoPtr.h deleted file mode 100644 index 621e0007f64..00000000000 --- a/src/server/shared/AutoPtr.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008-2013 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 _TRINITY_AUTO_PTR_H -#define _TRINITY_AUTO_PTR_H - -#include <ace/Bound_Ptr.h> - -namespace Trinity -{ - -template <class Pointer, class Lock> -class AutoPtr : public ACE_Strong_Bound_Ptr<Pointer, Lock> -{ - typedef ACE_Strong_Bound_Ptr<Pointer, Lock> Base; - -public: - AutoPtr() - : Base() - { } - - AutoPtr(Pointer* x) - : Base(x) - { } - - operator bool() const - { - return !Base::null(); - } - - bool operator !() const - { - return Base::null(); - } -}; - -} // namespace Trinity - -#endif diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index 4fc318f57eb..a61248f01ea 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> +# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -18,6 +18,7 @@ file(GLOB_RECURSE sources_Database Database/*.cpp Database/*.h) file(GLOB_RECURSE sources_DataStores DataStores/*.cpp DataStores/*.h) file(GLOB_RECURSE sources_Dynamic Dynamic/*.cpp Dynamic/*.h) file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h) +file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h) file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h) file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h) file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h) @@ -47,6 +48,7 @@ set(shared_STAT_SRCS ${sources_Debugging} ${sources_Dynamic} ${sources_Logging} + ${sources_Networking} ${sources_Packets} ${sources_Threading} ${sources_Utilities} @@ -68,11 +70,11 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Debugging ${CMAKE_CURRENT_SOURCE_DIR}/Dynamic ${CMAKE_CURRENT_SOURCE_DIR}/Logging + ${CMAKE_CURRENT_SOURCE_DIR}/Networking ${CMAKE_CURRENT_SOURCE_DIR}/Packets ${CMAKE_CURRENT_SOURCE_DIR}/Threading ${CMAKE_CURRENT_SOURCE_DIR}/Utilities ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) @@ -82,10 +84,6 @@ add_library(shared STATIC ${shared_STAT_PCH_SRC} ) -target_link_libraries(shared - ${ACE_LIBRARY} -) - # Generate precompiled header if (USE_COREPCH) add_cxx_pch(shared ${shared_STAT_PCH_HDR} ${shared_STAT_PCH_SRC}) diff --git a/src/server/shared/Common.cpp b/src/server/shared/Common.cpp index 28f987cf0b7..e45813b9d50 100644 --- a/src/server/shared/Common.cpp +++ b/src/server/shared/Common.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index e3074ef45b9..27e6cb63514 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,64 +19,18 @@ #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 "Dynamic/UnorderedMap.h" +#include <unordered_map> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include <math.h> +#include <cmath> #include <errno.h> #include <signal.h> #include <assert.h> -#if PLATFORM == PLATFORM_WINDOWS -#define STRCASECMP stricmp -#else -#define STRCASECMP strcasecmp -#endif - #include <set> #include <list> #include <string> @@ -85,22 +39,19 @@ #include <sstream> #include <algorithm> -#include "Threading/LockedQueue.h" -#include "Threading/Threading.h" +#include "Debugging/Errors.h" -#include <ace/Basic_Types.h> -#include <ace/Guard_T.h> -#include <ace/RW_Thread_Mutex.h> -#include <ace/Thread_Mutex.h> -#include <ace/OS_NS_time.h> +#include "Threading/LockedQueue.h" #if PLATFORM == PLATFORM_WINDOWS -# include <ace/config-all.h> -// XP winver - needed to compile with standard leak check in MemoryLeaks.h -// uncomment later if needed -//#define _WIN32_WINNT 0x0501 # include <ws2tcpip.h> -//#undef WIN32_WINNT + +# 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> @@ -114,26 +65,19 @@ #include <float.h> -#define I32FMT "%08I32X" -#define I64FMT "%016I64X" #define snprintf _snprintf #define atoll _atoi64 #define vsnprintf _vsnprintf -#define finite(X) _finite(X) #define llabs _abs64 #else #define stricmp strcasecmp #define strnicmp strncasecmp -#define I32FMT "%08X" -#define I64FMT "%016llX" #endif -inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; } - -#define atol(a) strtoul( a, NULL, 10) +inline float finiteAlways(float f) { return std::isfinite(f) ? f : 0.0f; } #define STRINGIZE(a) #a @@ -192,25 +136,9 @@ typedef std::vector<std::string> StringVector; #endif #ifndef M_PI -#define M_PI 3.14159265358979323846f +#define M_PI 3.14159265358979323846 #endif #define MAX_QUERY_LEN 32*1024 -#define TRINITY_GUARD(MUTEX, LOCK) \ - ACE_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \ - if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false); - -//! For proper implementation of multiple-read, single-write pattern, use -//! ACE_RW_Mutex as underlying @MUTEX -# define TRINITY_WRITE_GUARD(MUTEX, LOCK) \ - ACE_Write_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \ - if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false); - -//! For proper implementation of multiple-read, single-write pattern, use -//! ACE_RW_Mutex as underlying @MUTEX -# define TRINITY_READ_GUARD(MUTEX, LOCK) \ - ACE_Read_Guard< MUTEX > TRINITY_GUARD_OBJECT (LOCK); \ - if (TRINITY_GUARD_OBJECT.locked() == 0) ASSERT(false); - #endif diff --git a/src/server/shared/CompilerDefs.h b/src/server/shared/CompilerDefs.h index 909dcd1707b..2c2d7ea861d 100644 --- a/src/server/shared/CompilerDefs.h +++ b/src/server/shared/CompilerDefs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -55,10 +55,4 @@ # error "FATAL ERROR: Unknown compiler." #endif -#if defined(__cplusplus) && __cplusplus == 201103L -# define COMPILER_HAS_CPP11_SUPPORT 1 -#else -# define COMPILER_HAS_CPP11_SUPPORT 0 -#endif - #endif diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index 055c33b40ee..6b83f562520 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -16,136 +16,100 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <algorithm> +#include <mutex> +#include <boost/property_tree/ptree.hpp> +#include <boost/property_tree/ini_parser.hpp> #include "Config.h" #include "Errors.h" -// Defined here as it must not be exposed to end-users. -bool ConfigMgr::GetValueHelper(const char* name, ACE_TString &result) -{ - GuardType guard(_configLock); - - if (_config.get() == 0) - return false; - - ACE_TString section_name; - ACE_Configuration_Section_Key section_key; - const ACE_Configuration_Section_Key &root_key = _config->root_section(); - - int i = 0; - while (_config->enumerate_sections(root_key, i, section_name) == 0) - { - _config->open_section(root_key, section_name.c_str(), 0, section_key); - if (_config->get_string_value(section_key, name, result) == 0) - return true; - ++i; - } - - return false; -} +using namespace boost::property_tree; -bool ConfigMgr::LoadInitial(char const* file) +bool ConfigMgr::LoadInitial(std::string const& file, std::string& error) { - ASSERT(file); - - GuardType guard(_configLock); + std::lock_guard<std::mutex> lock(_configLock); _filename = file; - _config.reset(new ACE_Configuration_Heap()); - if (_config->open() == 0) - if (LoadData(_filename.c_str())) - return true; - _config.reset(); - return false; -} + try + { + ptree fullTree; + ini_parser::read_ini(file, fullTree); -bool ConfigMgr::LoadMore(char const* file) -{ - ASSERT(file); - ASSERT(_config); + if (fullTree.empty()) + { + error = "empty file (" + file + ")"; + return false; + } - GuardType guard(_configLock); + // Since we're using only one section per config file, we skip the section and have direct property access + _config = fullTree.begin()->second; + } + catch (ini_parser::ini_parser_error const& e) + { + if (e.line() == 0) + error = e.message() + " (" + e.filename() + ")"; + else + error = e.message() + " (" + e.filename() + ":" + std::to_string(e.line()) + ")"; + return false; + } - return LoadData(file); + return true; } -bool ConfigMgr::Reload() +bool ConfigMgr::Reload(std::string& error) { - return LoadInitial(_filename.c_str()); + return LoadInitial(_filename.c_str(), error); } -bool ConfigMgr::LoadData(char const* file) +std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) { - ACE_Ini_ImpExp config_importer(*_config.get()); - if (config_importer.import_config(file) == 0) - return true; + std::string value = _config.get<std::string>(ptree::path_type(name, '/'), def); - return false; -} + value.erase(std::remove(value.begin(), value.end(), '"'), value.end()); -std::string ConfigMgr::GetStringDefault(const char* name, const std::string &def) -{ - ACE_TString val; - return GetValueHelper(name, val) ? val.c_str() : def; + return value; } -bool ConfigMgr::GetBoolDefault(const char* name, bool def) +bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) { - ACE_TString val; - - if (!GetValueHelper(name, val)) + try + { + std::string val = _config.get<std::string>(ptree::path_type(name, '/')); + val.erase(std::remove(val.begin(), val.end(), '"'), val.end()); + return (val == "true" || val == "TRUE" || val == "yes" || val == "YES" || val == "1"); + } + catch (std::exception const& /*ex*/) + { return def; - - return (val == "true" || val == "TRUE" || val == "yes" || val == "YES" || - val == "1"); + } } -int ConfigMgr::GetIntDefault(const char* name, int def) +int ConfigMgr::GetIntDefault(std::string const& name, int def) { - ACE_TString val; - return GetValueHelper(name, val) ? atoi(val.c_str()) : def; + return _config.get<int>(ptree::path_type(name, '/'), def); } -float ConfigMgr::GetFloatDefault(const char* name, float def) +float ConfigMgr::GetFloatDefault(std::string const& name, float def) { - ACE_TString val; - return GetValueHelper(name, val) ? (float)atof(val.c_str()) : def; + return _config.get<float>(ptree::path_type(name, '/'), def); } std::string const& ConfigMgr::GetFilename() { - GuardType guard(_configLock); + std::lock_guard<std::mutex> lock(_configLock); return _filename; } std::list<std::string> ConfigMgr::GetKeysByString(std::string const& name) { - GuardType guard(_configLock); + std::lock_guard<std::mutex> lock(_configLock); std::list<std::string> keys; - if (_config.get() == 0) - return keys; - - ACE_TString section_name; - ACE_Configuration_Section_Key section_key; - const ACE_Configuration_Section_Key &root_key = _config->root_section(); - - int i = 0; - while (_config->enumerate_sections(root_key, i++, section_name) == 0) - { - _config->open_section(root_key, section_name.c_str(), 0, section_key); - ACE_TString key_name; - ACE_Configuration::VALUETYPE type; - int j = 0; - while (_config->enumerate_values(section_key, j++, key_name, type) == 0) - { - std::string temp = key_name.c_str(); - - if (!temp.find(name)) - keys.push_back(temp); - } - } + for (const ptree::value_type& child : _config) + if (child.first.compare(0, name.length(), name) == 0) + keys.push_back(child.first); return keys; } diff --git a/src/server/shared/Configuration/Config.h b/src/server/shared/Configuration/Config.h index 49f5c5e07fb..ff0233b5669 100644 --- a/src/server/shared/Configuration/Config.h +++ b/src/server/shared/Configuration/Config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -21,58 +21,43 @@ #include <string> #include <list> -#include <ace/Singleton.h> -#include <ace/Configuration_Import_Export.h> -#include <ace/Thread_Mutex.h> -#include <AutoPtr.h> - -typedef Trinity::AutoPtr<ACE_Configuration_Heap, ACE_Null_Mutex> Config; +#include <mutex> +#include <boost/property_tree/ptree.hpp> class ConfigMgr { - friend class ACE_Singleton<ConfigMgr, ACE_Null_Mutex>; - friend class ConfigLoader; - ConfigMgr() { } ~ConfigMgr() { } public: /// Method used only for loading main configuration files (authserver.conf and worldserver.conf) - bool LoadInitial(char const* file); + bool LoadInitial(std::string const& file, std::string& error); - /** - * This method loads additional configuration files - * It is recommended to use this method in WorldScript::OnConfigLoad hooks - * - * @return true if loading was successful - */ - bool LoadMore(char const* file); + static ConfigMgr* instance() + { + static ConfigMgr instance; + return &instance; + } - bool Reload(); + bool Reload(std::string& error); - std::string GetStringDefault(const char* name, const std::string& def); - bool GetBoolDefault(const char* name, bool def); - int GetIntDefault(const char* name, int def); - float GetFloatDefault(const char* name, float def); + std::string GetStringDefault(std::string const& name, const std::string& def); + bool GetBoolDefault(std::string const& name, bool def); + int GetIntDefault(std::string const& name, int def); + float GetFloatDefault(std::string const& name, float def); std::string const& GetFilename(); std::list<std::string> GetKeysByString(std::string const& name); private: - bool GetValueHelper(const char* name, ACE_TString &result); - bool LoadData(char const* file); - - typedef ACE_Thread_Mutex LockType; - typedef ACE_Guard<LockType> GuardType; - std::string _filename; - Config _config; - LockType _configLock; + boost::property_tree::ptree _config; + std::mutex _configLock; ConfigMgr(ConfigMgr const&); ConfigMgr& operator=(ConfigMgr const&); }; -#define sConfigMgr ACE_Singleton<ConfigMgr, ACE_Null_Mutex>::instance() +#define sConfigMgr ConfigMgr::instance() #endif diff --git a/src/server/shared/Containers.h b/src/server/shared/Containers.h index b33954d7ea4..9121fbe2a97 100644 --- a/src/server/shared/Containers.h +++ b/src/server/shared/Containers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -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/Cryptography/ARC4.cpp b/src/server/shared/Cryptography/ARC4.cpp index 6395ff99bfa..90f38d98d51 100644 --- a/src/server/shared/Cryptography/ARC4.cpp +++ b/src/server/shared/Cryptography/ARC4.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Cryptography/ARC4.h b/src/server/shared/Cryptography/ARC4.h index 0804971f696..11d3d4ba87b 100644 --- a/src/server/shared/Cryptography/ARC4.h +++ b/src/server/shared/Cryptography/ARC4.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,8 +19,8 @@ #ifndef _AUTH_SARC4_H #define _AUTH_SARC4_H -#include "Define.h" #include <openssl/evp.h> +#include "Define.h" class ARC4 { diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp b/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp index 003c09e4589..ec8913ba1bc 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/AuthCrypt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -20,6 +20,8 @@ #include "Cryptography/HMACSHA1.h" #include "Cryptography/BigNumber.h" +#include <cstring> + AuthCrypt::AuthCrypt() : _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH), _initialized(false) diff --git a/src/server/shared/Cryptography/Authentication/AuthCrypt.h b/src/server/shared/Cryptography/Authentication/AuthCrypt.h index 95e773b586e..8fa150068a2 100644 --- a/src/server/shared/Cryptography/Authentication/AuthCrypt.h +++ b/src/server/shared/Cryptography/Authentication/AuthCrypt.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Cryptography/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp index bfe92cd6051..1319e116159 100644 --- a/src/server/shared/Cryptography/BigNumber.cpp +++ b/src/server/shared/Cryptography/BigNumber.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -16,13 +16,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <ace/Guard_T.h> - #include "Cryptography/BigNumber.h" #include <openssl/bn.h> #include <openssl/crypto.h> +#include <cstring> #include <algorithm> -#include <ace/Auto_Ptr.h> +#include <memory> BigNumber::BigNumber() : _bn(BN_new()) @@ -170,7 +169,7 @@ bool BigNumber::isZero() const return BN_is_zero(_bn); } -ACE_Auto_Array_Ptr<uint8> BigNumber::AsByteArray(int32 minSize, bool littleEndian) +std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian) { int length = (minSize >= GetNumBytes()) ? minSize : GetNumBytes(); @@ -186,7 +185,7 @@ ACE_Auto_Array_Ptr<uint8> BigNumber::AsByteArray(int32 minSize, bool littleEndia if (littleEndian) std::reverse(array, array + length); - ACE_Auto_Array_Ptr<uint8> ret(array); + std::unique_ptr<uint8[]> ret(array); return ret; } diff --git a/src/server/shared/Cryptography/BigNumber.h b/src/server/shared/Cryptography/BigNumber.h index 6129a24d1bc..684a25e8801 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,8 +19,8 @@ #ifndef _AUTH_BIGNUMBER_H #define _AUTH_BIGNUMBER_H +#include <memory> #include "Define.h" -#include <ace/Auto_Ptr.h> struct bignum_st; @@ -87,7 +87,7 @@ class BigNumber uint32 AsDword(); - ACE_Auto_Array_Ptr<uint8> AsByteArray(int32 minSize = 0, bool littleEndian = true); + std::unique_ptr<uint8[]> AsByteArray(int32 minSize = 0, bool littleEndian = true); char * AsHexStr() const; char * AsDecStr() const; diff --git a/src/server/shared/Cryptography/HMACSHA1.cpp b/src/server/shared/Cryptography/HMACSHA1.cpp index 2585fa64ea1..2148a3b8a7b 100644 --- a/src/server/shared/Cryptography/HMACSHA1.cpp +++ b/src/server/shared/Cryptography/HMACSHA1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Cryptography/HMACSHA1.h b/src/server/shared/Cryptography/HMACSHA1.h index 04b8f7d0277..de1556d3c98 100644 --- a/src/server/shared/Cryptography/HMACSHA1.h +++ b/src/server/shared/Cryptography/HMACSHA1.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Cryptography/OpenSSLCrypto.cpp b/src/server/shared/Cryptography/OpenSSLCrypto.cpp index 417be813347..6d8d6584e6c 100644 --- a/src/server/shared/Cryptography/OpenSSLCrypto.cpp +++ b/src/server/shared/Cryptography/OpenSSLCrypto.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -17,23 +17,23 @@ #include <OpenSSLCrypto.h> #include <openssl/crypto.h> -#include <ace/Thread_Mutex.h> #include <vector> -#include <ace/Thread.h> +#include <thread> +#include <mutex> -std::vector<ACE_Thread_Mutex*> cryptoLocks; +std::vector<std::mutex*> cryptoLocks; static void lockingCallback(int mode, int type, const char* /*file*/, int /*line*/) { if (mode & CRYPTO_LOCK) - cryptoLocks[type]->acquire(); + cryptoLocks[type]->lock(); else - cryptoLocks[type]->release(); + cryptoLocks[type]->unlock(); } static void threadIdCallback(CRYPTO_THREADID * id) { - CRYPTO_THREADID_set_numeric(id, ACE_Thread::self()); + CRYPTO_THREADID_set_numeric(id, std::hash<std::thread::id>()(std::this_thread::get_id())); } void OpenSSLCrypto::threadsSetup() @@ -41,7 +41,7 @@ void OpenSSLCrypto::threadsSetup() cryptoLocks.resize(CRYPTO_num_locks()); for(int i = 0 ; i < CRYPTO_num_locks(); ++i) { - cryptoLocks[i] = new ACE_Thread_Mutex(); + cryptoLocks[i] = new std::mutex; } CRYPTO_THREADID_set_callback(threadIdCallback); CRYPTO_set_locking_callback(lockingCallback); @@ -56,4 +56,4 @@ void OpenSSLCrypto::threadsCleanup() delete cryptoLocks[i]; } cryptoLocks.resize(0); -}
\ No newline at end of file +} diff --git a/src/server/shared/Cryptography/OpenSSLCrypto.h b/src/server/shared/Cryptography/OpenSSLCrypto.h index 70071007c5f..26bd1357d39 100644 --- a/src/server/shared/Cryptography/OpenSSLCrypto.h +++ b/src/server/shared/Cryptography/OpenSSLCrypto.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Cryptography/SHA1.cpp b/src/server/shared/Cryptography/SHA1.cpp index 1f65c88a6f3..d47b13067cd 100644 --- a/src/server/shared/Cryptography/SHA1.cpp +++ b/src/server/shared/Cryptography/SHA1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,7 @@ #include "SHA1.h" #include "BigNumber.h" +#include <cstring> #include <stdarg.h> SHA1Hash::SHA1Hash() diff --git a/src/server/shared/Cryptography/SHA1.h b/src/server/shared/Cryptography/SHA1.h index a4232f4e75f..2738d48931e 100644 --- a/src/server/shared/Cryptography/SHA1.h +++ b/src/server/shared/Cryptography/SHA1.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Cryptography/WardenKeyGeneration.h b/src/server/shared/Cryptography/WardenKeyGeneration.h index 6d5fd563ba3..9832d5a9c72 100644 --- a/src/server/shared/Cryptography/WardenKeyGeneration.h +++ b/src/server/shared/Cryptography/WardenKeyGeneration.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +18,8 @@ #include "SHA1.h" +#include <cstring> + #ifndef _WARDEN_KEY_GENERATION_H #define _WARDEN_KEY_GENERATION_H diff --git a/src/server/shared/DataStores/DBCFileLoader.cpp b/src/server/shared/DataStores/DBCFileLoader.cpp index 3c02d5f533d..d027d7539ad 100644 --- a/src/server/shared/DataStores/DBCFileLoader.cpp +++ b/src/server/shared/DataStores/DBCFileLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/DataStores/DBCFileLoader.h b/src/server/shared/DataStores/DBCFileLoader.h index 1f8768e5da4..a665bc49c9c 100644 --- a/src/server/shared/DataStores/DBCFileLoader.h +++ b/src/server/shared/DataStores/DBCFileLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -106,5 +106,8 @@ class DBCFileLoader uint32 *fieldsOffset; unsigned char *data; unsigned char *stringTable; + + DBCFileLoader(DBCFileLoader const& right) = delete; + DBCFileLoader& operator=(DBCFileLoader const& right) = delete; }; #endif diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h index ad13b2a02af..08b8d810b8b 100644 --- a/src/server/shared/DataStores/DBCStore.h +++ b/src/server/shared/DataStores/DBCStore.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -63,6 +63,10 @@ struct SqlDbc } } } + +private: + SqlDbc(SqlDbc const& right) = delete; + SqlDbc& operator=(SqlDbc const& right) = delete; }; template<class T> @@ -291,6 +295,9 @@ class DBCStorage T* dataTable; StringPoolList stringPoolList; + + DBCStorage(DBCStorage const& right) = delete; + DBCStorage& operator=(DBCStorage const& right) = delete; }; #endif diff --git a/src/server/shared/Database/AdhocStatement.cpp b/src/server/shared/Database/AdhocStatement.cpp index 23175cd2273..7fae9173d20 100644 --- a/src/server/shared/Database/AdhocStatement.cpp +++ b/src/server/shared/Database/AdhocStatement.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -19,22 +19,20 @@ #include "MySQLConnection.h" /*! Basic, ad-hoc queries. */ -BasicStatementTask::BasicStatementTask(const char* sql) : -m_has_result(false) -{ - m_sql = strdup(sql); -} - -BasicStatementTask::BasicStatementTask(const char* sql, QueryResultFuture result) : -m_has_result(true), -m_result(result) +BasicStatementTask::BasicStatementTask(const char* sql, bool async) : +m_result(nullptr) { m_sql = strdup(sql); + m_has_result = async; // If the operation is async, then there's a result + if (async) + m_result = new QueryResultPromise(); } BasicStatementTask::~BasicStatementTask() { free((void*)m_sql); + if (m_has_result && m_result != nullptr) + delete m_result; } bool BasicStatementTask::Execute() @@ -42,14 +40,14 @@ bool BasicStatementTask::Execute() if (m_has_result) { ResultSet* result = m_conn->Query(m_sql); - if (!result || !result->GetRowCount()) + if (!result || !result->GetRowCount() || !result->NextRow()) { delete result; - m_result.set(QueryResult(NULL)); + m_result->set_value(QueryResult(NULL)); return false; } - result->NextRow(); - m_result.set(QueryResult(result)); + + m_result->set_value(QueryResult(result)); return true; } diff --git a/src/server/shared/Database/AdhocStatement.h b/src/server/shared/Database/AdhocStatement.h index 7b41b43725c..40c1dbb7098 100644 --- a/src/server/shared/Database/AdhocStatement.h +++ b/src/server/shared/Database/AdhocStatement.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,24 +18,26 @@ #ifndef _ADHOCSTATEMENT_H #define _ADHOCSTATEMENT_H -#include <ace/Future.h> +#include <future> #include "SQLOperation.h" -typedef ACE_Future<QueryResult> QueryResultFuture; +typedef std::future<QueryResult> QueryResultFuture; +typedef std::promise<QueryResult> QueryResultPromise; + /*! Raw, ad-hoc query. */ class BasicStatementTask : public SQLOperation { public: - BasicStatementTask(const char* sql); - BasicStatementTask(const char* sql, QueryResultFuture result); + BasicStatementTask(const char* sql, bool async = false); ~BasicStatementTask(); - bool Execute(); + bool Execute() override; + QueryResultFuture GetFuture() { return m_result->get_future(); } private: const char* m_sql; //- Raw query to be executed bool m_has_result; - QueryResultFuture m_result; + QueryResultPromise* m_result; }; #endif
\ No newline at end of file diff --git a/src/server/shared/Database/DatabaseEnv.h b/src/server/shared/Database/DatabaseEnv.h index f45a468f617..d58fa81d608 100644 --- a/src/server/shared/Database/DatabaseEnv.h +++ b/src/server/shared/Database/DatabaseEnv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Database/DatabaseWorker.cpp b/src/server/shared/Database/DatabaseWorker.cpp index 1333ba14632..e130429c8d0 100644 --- a/src/server/shared/Database/DatabaseWorker.cpp +++ b/src/server/shared/Database/DatabaseWorker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -20,32 +20,42 @@ #include "SQLOperation.h" #include "MySQLConnection.h" #include "MySQLThreading.h" +#include "ProducerConsumerQueue.h" -DatabaseWorker::DatabaseWorker(ACE_Activation_Queue* new_queue, MySQLConnection* con) : -m_queue(new_queue), -m_conn(con) +DatabaseWorker::DatabaseWorker(ProducerConsumerQueue<SQLOperation*>* newQueue, MySQLConnection* connection) { - /// Assign thread to task - activate(); + _connection = connection; + _queue = newQueue; + _cancelationToken = false; + _workerThread = std::thread(&DatabaseWorker::WorkerThread, this); } -int DatabaseWorker::svc() +DatabaseWorker::~DatabaseWorker() { - if (!m_queue) - return -1; + _cancelationToken = true; - SQLOperation *request = NULL; - while (1) + _queue->Cancel(); + + _workerThread.join(); +} + +void DatabaseWorker::WorkerThread() +{ + if (!_queue) + return; + + for (;;) { - request = (SQLOperation*)(m_queue->dequeue()); - if (!request) - break; + SQLOperation* operation = nullptr; - request->SetConnection(m_conn); - request->call(); + _queue->WaitAndPop(operation); - delete request; - } + if (_cancelationToken || !operation) + return; - return 0; + operation->SetConnection(_connection); + operation->call(); + + delete operation; + } } diff --git a/src/server/shared/Database/DatabaseWorker.h b/src/server/shared/Database/DatabaseWorker.h index 179806d29cb..6f452c767f6 100644 --- a/src/server/shared/Database/DatabaseWorker.h +++ b/src/server/shared/Database/DatabaseWorker.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,24 +18,29 @@ #ifndef _WORKERTHREAD_H #define _WORKERTHREAD_H -#include <ace/Task.h> -#include <ace/Activation_Queue.h> +#include <thread> +#include "ProducerConsumerQueue.h" class MySQLConnection; +class SQLOperation; -class DatabaseWorker : protected ACE_Task_Base +class DatabaseWorker { public: - DatabaseWorker(ACE_Activation_Queue* new_queue, MySQLConnection* con); - - ///- Inherited from ACE_Task_Base - int svc(); - int wait() { return ACE_Task_Base::wait(); } + DatabaseWorker(ProducerConsumerQueue<SQLOperation*>* newQueue, MySQLConnection* connection); + ~DatabaseWorker(); private: - DatabaseWorker() : ACE_Task_Base() { } - ACE_Activation_Queue* m_queue; - MySQLConnection* m_conn; + ProducerConsumerQueue<SQLOperation*>* _queue; + MySQLConnection* _connection; + + void WorkerThread(); + std::thread _workerThread; + + std::atomic_bool _cancelationToken; + + DatabaseWorker(DatabaseWorker const& right) = delete; + DatabaseWorker& operator=(DatabaseWorker const& right) = delete; }; #endif diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 33075accc04..5548e44c925 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,8 +18,6 @@ #ifndef _DATABASEWORKERPOOL_H #define _DATABASEWORKERPOOL_H -#include <ace/Thread_Mutex.h> - #include "Common.h" #include "Callback.h" #include "MySQLConnection.h" @@ -37,7 +35,7 @@ class PingOperation : public SQLOperation { //! Operation for idle delaythreads - bool Execute() + bool Execute() override { m_conn->Ping(); return true; @@ -47,11 +45,19 @@ class PingOperation : public SQLOperation template <class T> class DatabaseWorkerPool { + private: + enum InternalIndex + { + IDX_ASYNC, + IDX_SYNCH, + IDX_SIZE + }; + public: /* Activity state */ - DatabaseWorkerPool() : - _queue(new ACE_Activation_Queue()) + DatabaseWorkerPool() : _connectionInfo(NULL) { + _queue = new ProducerConsumerQueue<SQLOperation*>(); memset(_connectionCount, 0, sizeof(_connectionCount)); _connections.resize(IDX_SIZE); @@ -61,44 +67,32 @@ class DatabaseWorkerPool ~DatabaseWorkerPool() { + _queue->Cancel(); + + delete _queue; + + delete _connectionInfo; } bool Open(const std::string& infoString, uint8 async_threads, uint8 synch_threads) { bool res = true; - _connectionInfo = MySQLConnectionInfo(infoString); + _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]; - } + 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.", GetDatabaseName()); + return res; } @@ -106,17 +100,9 @@ class DatabaseWorkerPool { TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); - //! Shuts down delaythreads for this connection pool by underlying deactivate(). - //! The next dequeue attempt in the worker thread tasks will result in an error, - //! ultimately ending the worker thread task. - _queue->queue()->close(); - for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) { T* t = _connections[IDX_ASYNC][i]; - DatabaseWorker* worker = t->m_worker; - worker->wait(); //! Block until no more threads are running this task. - delete worker; t->Close(); //! Closes the actualy MySQL connection. } @@ -130,9 +116,6 @@ class DatabaseWorkerPool for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i) _connections[IDX_SYNCH][i]->Close(); - //! Deletes the ACE_Activation_Queue object and its underlying ACE_Message_Queue - delete _queue; - TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); } @@ -232,13 +215,12 @@ class DatabaseWorkerPool ResultSet* result = conn->Query(sql); conn->Unlock(); - if (!result || !result->GetRowCount()) + if (!result || !result->GetRowCount() || !result->NextRow()) { delete result; return QueryResult(NULL); } - result->NextRow(); return QueryResult(result); } @@ -303,10 +285,11 @@ class DatabaseWorkerPool //! The return value is then processed in ProcessQueryCallback methods. QueryResultFuture AsyncQuery(const char* sql) { - QueryResultFuture res; - BasicStatementTask* task = new BasicStatementTask(sql, res); + BasicStatementTask* task = new BasicStatementTask(sql, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultFuture result = task->GetFuture(); Enqueue(task); - return res; //! Actual return value has no use yet + return result; } //! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed. @@ -327,10 +310,11 @@ class DatabaseWorkerPool //! Statement must be prepared with CONNECTION_ASYNC flag. PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt) { - PreparedQueryResultFuture res; - PreparedStatementTask* task = new PreparedStatementTask(stmt, res); + PreparedStatementTask* task = new PreparedStatementTask(stmt, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + PreparedQueryResultFuture result = task->GetFuture(); Enqueue(task); - return res; + return result; } //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture @@ -339,10 +323,11 @@ class DatabaseWorkerPool //! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag. QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder) { - QueryResultHolderFuture res; - SQLQueryHolderTask* task = new SQLQueryHolderTask(holder, res); + SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultHolderFuture result = task->GetFuture(); Enqueue(task); - return res; //! Fool compiler, has no use yet + return result; } /** @@ -412,7 +397,7 @@ class DatabaseWorkerPool //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) { - if (trans.null()) + if (!trans) Execute(stmt); else trans->Append(stmt); @@ -422,7 +407,7 @@ class DatabaseWorkerPool //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. void ExecuteOrAppend(SQLTransaction& trans, const char* sql) { - if (trans.null()) + if (!trans) Execute(sql); else trans->Append(sql); @@ -446,7 +431,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; @@ -474,6 +459,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) @@ -484,7 +517,7 @@ class DatabaseWorkerPool void Enqueue(SQLOperation* op) { - _queue->enqueue(op); + _queue->Push(op); } //! Gets a free connection in the synchronous connection pool. @@ -508,21 +541,13 @@ class DatabaseWorkerPool char const* GetDatabaseName() const { - return _connectionInfo.database.c_str(); + return _connectionInfo->database.c_str(); } - private: - enum _internalIndex - { - IDX_ASYNC, - IDX_SYNCH, - IDX_SIZE - }; - - ACE_Activation_Queue* _queue; //! Queue shared by async worker threads. - std::vector< std::vector<T*> > _connections; - uint32 _connectionCount[2]; //! Counter of MySQL connections; - MySQLConnectionInfo _connectionInfo; + ProducerConsumerQueue<SQLOperation*>* _queue; //! Queue shared by async worker threads. + std::vector< std::vector<T*> > _connections; + uint32 _connectionCount[2]; //! Counter of MySQL connections; + MySQLConnectionInfo* _connectionInfo; }; #endif diff --git a/src/server/shared/Database/Field.cpp b/src/server/shared/Database/Field.cpp index 51d918e716e..866a96b58b6 100644 --- a/src/server/shared/Database/Field.cpp +++ b/src/server/shared/Database/Field.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -35,7 +35,7 @@ void Field::SetByteValue(const void* newValue, const size_t newSize, enum_field_ if (data.value) CleanUp(); - // This value stores raw bytes that have to be explicitly casted later + // This value stores raw bytes that have to be explicitly cast later if (newValue) { data.value = new char[newSize]; diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index 5460f5cc4f6..5f427a5871b 100644 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index da99d6c3537..24e61e7399a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -59,18 +59,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_NAME_DATA, "SELECT race, class, gender, level FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_DEL_QUEST_STATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_DAILY_CHAR, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC); - // Start LoginQueryHolder content PrepareStatement(CHAR_SEL_CHARACTER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " @@ -85,14 +77,24 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, " "itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC); + + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC); @@ -120,7 +122,6 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ? AND active = 1", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); - // End LoginQueryHolder content PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); @@ -375,7 +376,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petitionguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petitionguid, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_GROUP, "INSERT INTO groups (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_GROUP, "INSERT INTO groups (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty, masterLooterGuid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_GROUP_MEMBER, "INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_MEMBER, "DELETE FROM group_member WHERE memberGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING, "DELETE FROM group_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); @@ -389,7 +390,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_INVALID_SPELL_TALENTS, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ZONE, "UPDATE characters SET zone = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_LEVEL, "UPDATE characters SET level = ?, xp = 0 WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA, "DELETE FROM character_achievement_progress WHERE criteria = ?", CONNECTION_ASYNC); @@ -463,7 +464,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_REPUTATION_BY_FACTION, "DELETE FROM character_reputation WHERE guid = ? AND faction = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_REPUTATION_BY_FACTION, "INSERT INTO character_reputation (guid, faction, standing, flags) VALUES (?, ?, ? , ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = (arenaPoints + ?) WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ADD_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = (arenaPoints + ?) WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_REFUND_INSTANCE, "DELETE FROM item_refund_instance WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_REFUND_INSTANCE, "INSERT INTO item_refund_instance (item_guid, player_guid, paidMoney, paidExtendedCost) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP, "DELETE FROM groups WHERE guid = ?", CONNECTION_ASYNC); @@ -515,12 +516,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_DAILY, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_HONOR_POINTS, "UPDATE characters SET totalHonorPoints = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_HONOR_POINTS, "UPDATE characters SET totalHonorPoints = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_ARENA_POINTS, "UPDATE characters SET arenaPoints = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, button, action, type) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_ACTION, "UPDATE character_action SET action = ?, type = ? WHERE guid = ? AND button = ? AND spec = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC, "DELETE FROM character_action WHERE guid = ? and button = ? and spec = ?", CONNECTION_ASYNC); @@ -536,7 +536,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (guid, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_SPELL, "INSERT INTO character_spell (guid, spell, active, disabled) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_STATS, "DELETE FROM character_stats WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_STATS, "INSERT INTO character_stats (guid, maxhealth, maxpower1, maxpower2, maxpower3, maxpower4, maxpower5, maxpower6, maxpower7, strength, agility, stamina, intellect, spirit, " @@ -576,7 +576,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_PETS, "SELECT id FROM character_pet WHERE owner = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_ADD_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_PET_AURA, "SELECT caster_guid, spell, effect_mask, recalculate_mask, stackcount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_SYNCH); @@ -595,8 +595,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? AND slot = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ? AND id <> ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ? AND id <> ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?", CONNECTION_ASYNC); 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); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index aa47fb53097..c73f0df8d00 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -26,10 +26,10 @@ class CharacterDatabaseConnection : public MySQLConnection public: //- Constructors for sync and async connections CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - CharacterDatabaseConnection(ACE_Activation_Queue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } //- Loads database type specific prepared statements - void DoPrepareStatements(); + void DoPrepareStatements() override; }; typedef DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabaseWorkerPool; @@ -71,14 +71,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_NAME_DATA, CHAR_SEL_CHAR_POSITION_XYZ, CHAR_SEL_CHAR_POSITION, - CHAR_DEL_QUEST_STATUS_DAILY, - CHAR_DEL_QUEST_STATUS_WEEKLY, - CHAR_DEL_QUEST_STATUS_MONTHLY, - CHAR_DEL_QUEST_STATUS_SEASONAL, - CHAR_DEL_QUEST_STATUS_DAILY_CHAR, - CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR, - CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR, - CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR, + CHAR_DEL_BATTLEGROUND_RANDOM, CHAR_INS_BATTLEGROUND_RANDOM, @@ -88,14 +81,24 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_AURAS, CHAR_SEL_CHARACTER_SPELL, CHAR_SEL_CHARACTER_QUESTSTATUS, - CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, - CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, - CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS, - CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS, - CHAR_INS_CHARACTER_DAILYQUESTSTATUS, - CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, - CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS, - CHAR_INS_CHARACTER_SEASONALQUESTSTATUS, + + CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, + CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, + CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY, + CHAR_SEL_CHARACTER_QUESTSTATUS_SEASONAL, + CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY, + CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY, + CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY, + CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL, + CHAR_INS_CHARACTER_QUESTSTATUS_DAILY, + CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY, + CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY, + CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL, + CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY, + CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY, + CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, + CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, + CHAR_SEL_CHARACTER_REPUTATION, CHAR_SEL_CHARACTER_INVENTORY, CHAR_SEL_CHARACTER_ACTIONS, @@ -326,7 +329,7 @@ enum CharacterDatabaseStatements CHAR_DEL_INVALID_SPELL_SPELLS, CHAR_DEL_INVALID_SPELL_TALENTS, CHAR_UPD_DELETE_INFO, - CHAR_UDP_RESTORE_DELETE_INFO, + CHAR_UPD_RESTORE_DELETE_INFO, CHAR_UPD_ZONE, CHAR_UPD_LEVEL, CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA, @@ -399,7 +402,7 @@ enum CharacterDatabaseStatements CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS, CHAR_DEL_CHAR_REPUTATION_BY_FACTION, CHAR_INS_CHAR_REPUTATION_BY_FACTION, - CHAR_UPD_CHAR_ARENA_POINTS, + CHAR_UPD_ADD_CHAR_ARENA_POINTS, CHAR_DEL_ITEM_REFUND_INSTANCE, CHAR_INS_ITEM_REFUND_INSTANCE, CHAR_DEL_GROUP, @@ -451,12 +454,11 @@ enum CharacterDatabaseStatements CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, CHAR_DEL_CHAR_GLYPHS, - CHAR_DEL_CHAR_QUESTSTATUS_DAILY, CHAR_DEL_CHAR_TALENT, CHAR_DEL_CHAR_SKILLS, - CHAR_UDP_CHAR_HONOR_POINTS, - CHAR_UDP_CHAR_ARENA_POINTS, - CHAR_UDP_CHAR_MONEY, + CHAR_UPD_CHAR_HONOR_POINTS, + CHAR_UPD_CHAR_ARENA_POINTS, + CHAR_UPD_CHAR_MONEY, CHAR_INS_CHAR_ACTION, CHAR_UPD_CHAR_ACTION, CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC, @@ -472,7 +474,7 @@ enum CharacterDatabaseStatements CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, CHAR_DEL_CHAR_SKILL_BY_SKILL, CHAR_INS_CHAR_SKILLS, - CHAR_UDP_CHAR_SKILLS, + CHAR_UPD_CHAR_SKILLS, CHAR_INS_CHAR_SPELL, CHAR_DEL_CHAR_STATS, CHAR_INS_CHAR_STATS, @@ -516,10 +518,10 @@ enum CharacterDatabaseStatements CHAR_SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2, CHAR_SEL_CHAR_PET_BY_SLOT, CHAR_DEL_CHAR_PET_DECLINEDNAME, - CHAR_ADD_CHAR_PET_DECLINEDNAME, + CHAR_INS_CHAR_PET_DECLINEDNAME, CHAR_UPD_CHAR_PET_NAME, - CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, - CHAR_UDP_CHAR_PET_SLOT_BY_SLOT, + CHAR_UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, + CHAR_UPD_CHAR_PET_SLOT_BY_SLOT, CHAR_UPD_CHAR_PET_SLOT_BY_ID, CHAR_DEL_CHAR_PET_BY_ID, CHAR_DEL_CHAR_PET_BY_SLOT, diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index f6754629e38..a2b9091a8d5 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -24,15 +24,15 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban')", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban')", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP_BANNED_ALL, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED_BY_IP, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) AND ip LIKE CONCAT('%%', ?, '%%') ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED, "SELECT bandate, unbandate FROM account_banned WHERE id = ? AND active = 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_ALL, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH); - PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban', 1)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban', 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); @@ -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 c9d34a26617..d37149c6a76 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -26,10 +26,10 @@ class LoginDatabaseConnection : public MySQLConnection public: //- Constructors for sync and async connections LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - LoginDatabaseConnection(ACE_Activation_Queue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } //- Loads database type specific prepared statements - void DoPrepareStatements(); + void DoPrepareStatements() override; }; typedef DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabaseWorkerPool; @@ -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/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index f27ee2b72e0..f5d9913bc5b 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -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 FROM creature_text", CONNECTION_SYNCH); + 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_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); @@ -38,7 +38,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_DEL_NPC_VENDOR, "DELETE FROM npc_vendor WHERE entry = ? AND item = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_NPC_VENDOR_REF, "SELECT item, maxcount, incrtime, ExtendedCost FROM npc_vendor WHERE entry = ? ORDER BY slot ASC", CONNECTION_SYNCH); PrepareStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE, "UPDATE creature SET MovementType = ? WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(WORLD_UPD_CREATURE_FACTION, "UPDATE creature_template SET faction_A = ?, faction_H = ? WHERE entry = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_UPD_CREATURE_FACTION, "UPDATE creature_template SET faction = ? WHERE entry = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_NPCFLAG, "UPDATE creature_template SET npcflag = ? WHERE entry = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_POSITION, "UPDATE creature SET position_x = ?, position_y = ?, position_z = ?, orientation = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_SPAWN_DISTANCE, "UPDATE creature SET spawndist = ?, MovementType = ? WHERE guid = ?", CONNECTION_ASYNC); @@ -51,12 +51,12 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID, "UPDATE waypoint_data SET wpguid = ? WHERE id = ? and point = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_ID, "SELECT MAX(id) FROM waypoint_data", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_MAX_POINT, "SELECT MAX(point) FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID, "SELECT point, position_x, position_y, position_z, orientation, move_flag, delay, action, action_chance FROM waypoint_data WHERE id = ? ORDER BY point", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_ID, "SELECT point, position_x, position_y, position_z, orientation, move_type, delay, action, action_chance FROM waypoint_data WHERE id = ? ORDER BY point", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_BY_ID, "SELECT point, position_x, position_y, position_z FROM waypoint_data WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_FIRST_BY_ID, "SELECT position_x, position_y, position_z FROM waypoint_data WHERE point = 1 AND id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_POS_LAST_BY_ID, "SELECT position_x, position_y, position_z, orientation FROM waypoint_data WHERE id = ? ORDER BY point DESC LIMIT 1", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_WPGUID, "SELECT id, point FROM waypoint_data WHERE wpguid = ?", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ALL_BY_WPGUID, "SELECT id, point, delay, move_flag, action, action_chance FROM waypoint_data WHERE wpguid = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ALL_BY_WPGUID, "SELECT id, point, delay, move_type, action, action_chance FROM waypoint_data WHERE wpguid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_UPD_WAYPOINT_DATA_ALL_WPGUID, "UPDATE waypoint_data SET wpguid = 0", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_POS, "SELECT id, point FROM waypoint_data WHERE (abs(position_x - ?) <= ?) and (abs(position_y - ?) <= ?) and (abs(position_z - ?) <= ?)", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, "SELECT wpguid FROM waypoint_data WHERE id = ? and wpguid <> 0", CONNECTION_SYNCH); @@ -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, faction_A, faction_H, 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_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, 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, 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, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, 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, ManaModifier, 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,4 @@ 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); } diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index 0126cdc3a80..8a5bd206021 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -26,10 +26,10 @@ class WorldDatabaseConnection : public MySQLConnection public: //- Constructors for sync and async connections WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - WorldDatabaseConnection(ACE_Activation_Queue* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + 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,6 @@ enum WorldDatabaseStatements WORLD_SEL_DISABLES, WORLD_INS_DISABLES, WORLD_DEL_DISABLES, - WORLD_SEL_REQ_XP, MAX_WORLDDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index f569b8352d3..4e46ff0e3a1 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -33,6 +33,7 @@ #include "DatabaseWorker.h" #include "Timer.h" #include "Log.h" +#include "ProducerConsumerQueue.h" MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : m_reconnecting(false), @@ -43,7 +44,7 @@ m_Mysql(NULL), m_connectionInfo(connInfo), m_connectionFlags(CONNECTION_SYNCH) { } -MySQLConnection::MySQLConnection(ACE_Activation_Queue* queue, MySQLConnectionInfo& connInfo) : +MySQLConnection::MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, MySQLConnectionInfo& connInfo) : m_reconnecting(false), m_prepareError(false), m_queue(queue), @@ -56,12 +57,14 @@ m_connectionFlags(CONNECTION_ASYNC) MySQLConnection::~MySQLConnection() { - ASSERT (m_Mysql); /// MySQL context must be present at this point - 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); + + if (m_worker) + delete m_worker; } void MySQLConnection::Close() @@ -111,7 +114,7 @@ bool MySQLConnection::Open() else // generic case { port = atoi(m_connectionInfo.port_or_socket.c_str()); - unix_socket = 0; + unix_socket = nullptr; } #endif @@ -500,8 +503,8 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) } uint32 lErrno = mysql_errno(GetHandle()); // It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here. - ACE_OS::sleep(3); // Sleep 3 seconds - return _HandleMySQLErrno(lErrno); // Call self (recursive) + std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds + return _HandleMySQLErrno(lErrno); // Call self (recursive) } case ER_LOCK_DEADLOCK: @@ -515,12 +518,12 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) case ER_BAD_FIELD_ERROR: case ER_NO_SUCH_TABLE: TC_LOG_ERROR("sql.sql", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); - ACE_OS::sleep(10); + std::this_thread::sleep_for(std::chrono::seconds(10)); std::abort(); return false; case ER_PARSE_ERROR: TC_LOG_ERROR("sql.sql", "Error while parsing SQL. Core fix required."); - ACE_OS::sleep(10); + std::this_thread::sleep_for(std::chrono::seconds(10)); std::abort(); return false; default: diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h index 656d7917315..61b3b37cbc2 100644 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -15,11 +15,10 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <ace/Activation_Queue.h> - #include "DatabaseWorkerPool.h" #include "Transaction.h" #include "Util.h" +#include "ProducerConsumerQueue.h" #ifndef _MYSQLCONNECTION_H #define _MYSQLCONNECTION_H @@ -38,8 +37,7 @@ enum ConnectionFlags struct MySQLConnectionInfo { - MySQLConnectionInfo() { } - MySQLConnectionInfo(const std::string& infoString) + explicit MySQLConnectionInfo(std::string const& infoString) { Tokenizer tokens(infoString, ';'); @@ -71,7 +69,7 @@ class MySQLConnection public: MySQLConnection(MySQLConnectionInfo& connInfo); //! Constructor for synchronous connections. - MySQLConnection(ACE_Activation_Queue* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections. + MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections. virtual ~MySQLConnection(); virtual bool Open(); @@ -100,13 +98,13 @@ class MySQLConnection { /// Tries to acquire lock. If lock is acquired by another thread /// the calling parent will just try another connection - return m_Mutex.tryacquire() != -1; + return m_Mutex.try_lock(); } void Unlock() { /// Called by parent databasepool. Will let other threads access this connection - m_Mutex.release(); + m_Mutex.unlock(); } MYSQL* GetHandle() { return m_Mysql; } @@ -126,12 +124,15 @@ class MySQLConnection bool _HandleMySQLErrno(uint32 errNo); private: - ACE_Activation_Queue* m_queue; //! Queue shared with other asynchronous connections. + ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections. DatabaseWorker* m_worker; //! Core worker task. MYSQL * m_Mysql; //! MySQL Handle. MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging) ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements) - ACE_Thread_Mutex m_Mutex; + std::mutex m_Mutex; + + MySQLConnection(MySQLConnection const& right) = delete; + MySQLConnection& operator=(MySQLConnection const& right) = delete; }; #endif diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h index 38c0d349a1c..da234138879 100644 --- a/src/server/shared/Database/MySQLThreading.h +++ b/src/server/shared/Database/MySQLThreading.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -23,31 +23,6 @@ class MySQL { public: - /*! Create a thread on the MySQL server to mirrior the calling thread, - initializes thread-specific variables and allows thread-specific - operations without concurrence from other threads. - This should only be called if multiple core threads are running - on the same MySQL connection. Seperate MySQL connections implicitly - create a mirror thread. - */ - static void Thread_Init() - { - mysql_thread_init(); - TC_LOG_WARN("sql.sql", "Core thread with ID [" UI64FMTD "] initializing MySQL thread.", - (uint64)ACE_Based::Thread::currentId()); - } - - /*! Shuts down MySQL thread and frees resources, should only be called - when we terminate. MySQL threads and connections are not configurable - during runtime. - */ - static void Thread_End() - { - mysql_thread_end(); - TC_LOG_WARN("sql.sql", "Core thread with ID [" UI64FMTD "] shutting down MySQL thread.", - (uint64)ACE_Based::Thread::currentId()); - } - static void Library_Init() { mysql_library_init(-1, NULL, NULL); @@ -59,4 +34,4 @@ class MySQL } }; -#endif
\ No newline at end of file +#endif diff --git a/src/server/shared/Database/PreparedStatement.cpp b/src/server/shared/Database/PreparedStatement.cpp index 30089cfb197..23c50ac2ef8 100644 --- a/src/server/shared/Database/PreparedStatement.cpp +++ b/src/server/shared/Database/PreparedStatement.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -445,19 +445,19 @@ std::string MySQLPreparedStatement::getQueryString(std::string const& sqlPattern } //- Execution -PreparedStatementTask::PreparedStatementTask(PreparedStatement* stmt) : -m_stmt(stmt), -m_has_result(false) { } - -PreparedStatementTask::PreparedStatementTask(PreparedStatement* stmt, PreparedQueryResultFuture result) : -m_stmt(stmt), -m_has_result(true), -m_result(result) { } - +PreparedStatementTask::PreparedStatementTask(PreparedStatement* stmt, bool async) : +m_stmt(stmt), m_result(nullptr) +{ + m_has_result = async; // If it's async, then there's a result + if (async) + m_result = new PreparedQueryResultPromise(); +} PreparedStatementTask::~PreparedStatementTask() { delete m_stmt; + if (m_has_result && m_result != nullptr) + delete m_result; } bool PreparedStatementTask::Execute() @@ -468,10 +468,10 @@ bool PreparedStatementTask::Execute() if (!result || !result->GetRowCount()) { delete result; - m_result.set(PreparedQueryResult(NULL)); + m_result->set_value(PreparedQueryResult(NULL)); return false; } - m_result.set(PreparedQueryResult(result)); + m_result->set_value(PreparedQueryResult(result)); return true; } diff --git a/src/server/shared/Database/PreparedStatement.h b/src/server/shared/Database/PreparedStatement.h index 2cab6e40de0..5af52cde016 100644 --- a/src/server/shared/Database/PreparedStatement.h +++ b/src/server/shared/Database/PreparedStatement.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,8 +18,8 @@ #ifndef _PREPAREDSTATEMENT_H #define _PREPAREDSTATEMENT_H +#include <future> #include "SQLOperation.h" -#include <ace/Future.h> #ifdef __APPLE__ #undef TYPE_BOOL @@ -101,6 +101,9 @@ class PreparedStatement MySQLPreparedStatement* m_stmt; uint32 m_index; std::vector<PreparedStatementData> statement_data; //- Buffer of parameters, not tied to MySQL in any way yet + + PreparedStatement(PreparedStatement const& right) = delete; + PreparedStatement& operator=(PreparedStatement const& right) = delete; }; //- Class of which the instances are unique per MySQLConnection @@ -145,23 +148,27 @@ class MySQLPreparedStatement uint32 m_paramCount; std::vector<bool> m_paramsSet; MYSQL_BIND* m_bind; + + MySQLPreparedStatement(MySQLPreparedStatement const& right) = delete; + MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete; }; -typedef ACE_Future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; //- Lower-level class, enqueuable operation class PreparedStatementTask : public SQLOperation { public: - PreparedStatementTask(PreparedStatement* stmt); - PreparedStatementTask(PreparedStatement* stmt, PreparedQueryResultFuture result); + PreparedStatementTask(PreparedStatement* stmt, bool async = false); ~PreparedStatementTask(); - bool Execute(); + bool Execute() override; + PreparedQueryResultFuture GetFuture() { return m_result->get_future(); } protected: PreparedStatement* m_stmt; bool m_has_result; - PreparedQueryResultFuture m_result; + PreparedQueryResultPromise* m_result; }; #endif diff --git a/src/server/shared/Database/QueryHolder.cpp b/src/server/shared/Database/QueryHolder.cpp index 77980c4f66e..f0dc3c96e4e 100644 --- a/src/server/shared/Database/QueryHolder.cpp +++ b/src/server/shared/Database/QueryHolder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -89,10 +89,9 @@ QueryResult SQLQueryHolder::GetResult(size_t index) if (index < m_queries.size()) { ResultSet* result = m_queries[index].second.qresult; - if (!result || !result->GetRowCount()) + if (!result || !result->GetRowCount() || !result->NextRow()) return QueryResult(NULL); - result->NextRow(); return QueryResult(result); } else @@ -167,10 +166,15 @@ void SQLQueryHolder::SetSize(size_t size) m_queries.resize(size); } +SQLQueryHolderTask::~SQLQueryHolderTask() +{ + if (!m_executed) + delete m_holder; +} + bool SQLQueryHolderTask::Execute() { - //the result can't be ready as we are processing it right now - ASSERT(!m_result.ready()); + m_executed = true; if (!m_holder) return false; @@ -203,6 +207,6 @@ bool SQLQueryHolderTask::Execute() } } - m_result.set(m_holder); + m_result.set_value(m_holder); return true; } diff --git a/src/server/shared/Database/QueryHolder.h b/src/server/shared/Database/QueryHolder.h index 05c9e869290..39e51b591c5 100644 --- a/src/server/shared/Database/QueryHolder.h +++ b/src/server/shared/Database/QueryHolder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,7 +18,7 @@ #ifndef _QUERYHOLDER_H #define _QUERYHOLDER_H -#include <ace/Future.h> +#include <future> class SQLQueryHolder { @@ -39,19 +39,24 @@ class SQLQueryHolder void SetPreparedResult(size_t index, PreparedResultSet* result); }; -typedef ACE_Future<SQLQueryHolder*> QueryResultHolderFuture; +typedef std::future<SQLQueryHolder*> QueryResultHolderFuture; +typedef std::promise<SQLQueryHolder*> QueryResultHolderPromise; class SQLQueryHolderTask : public SQLOperation { private: - SQLQueryHolder * m_holder; - QueryResultHolderFuture m_result; + SQLQueryHolder* m_holder; + QueryResultHolderPromise m_result; + bool m_executed; public: - SQLQueryHolderTask(SQLQueryHolder *holder, QueryResultHolderFuture res) - : m_holder(holder), m_result(res){ }; - bool Execute(); + SQLQueryHolderTask(SQLQueryHolder* holder) + : m_holder(holder), m_executed(false) { } + ~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 be81570318a..a7b8ec2b107 100644 --- a/src/server/shared/Database/QueryResult.cpp +++ b/src/server/shared/Database/QueryResult.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -105,10 +105,10 @@ m_length(NULL) for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex) { if (!*m_rBind[fIndex].is_null) - m_rows[uint32(m_rowPosition)][fIndex].SetByteValue( m_rBind[fIndex].buffer, + m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(m_rBind[fIndex].buffer, m_rBind[fIndex].buffer_length, m_rBind[fIndex].buffer_type, - *m_rBind[fIndex].length ); + *m_rBind[fIndex].length); else switch (m_rBind[fIndex].buffer_type) { @@ -118,16 +118,16 @@ m_length(NULL) case MYSQL_TYPE_BLOB: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: - m_rows[uint32(m_rowPosition)][fIndex].SetByteValue( "", + m_rows[uint32(m_rowPosition)][fIndex].SetByteValue("", m_rBind[fIndex].buffer_length, m_rBind[fIndex].buffer_type, - *m_rBind[fIndex].length ); + *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 ); + *m_rBind[fIndex].length); } } m_rowPosition++; @@ -186,15 +186,8 @@ bool PreparedResultSet::_NextRow() if (m_rowPosition >= m_rowCount) return false; - int retval = mysql_stmt_fetch( m_stmt ); - - if (!retval || retval == MYSQL_DATA_TRUNCATED) - retval = true; - - if (retval == MYSQL_NO_DATA) - retval = false; - - return retval; + int retval = mysql_stmt_fetch(m_stmt); + return retval == 0 || retval == MYSQL_DATA_TRUNCATED; } void ResultSet::CleanUp() diff --git a/src/server/shared/Database/QueryResult.h b/src/server/shared/Database/QueryResult.h index 1a721ce9e96..e8c277c03cf 100644 --- a/src/server/shared/Database/QueryResult.h +++ b/src/server/shared/Database/QueryResult.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,9 +19,7 @@ #ifndef QUERYRESULT_H #define QUERYRESULT_H -#include "AutoPtr.h" -#include <ace/Thread_Mutex.h> - +#include <memory> #include "Field.h" #ifdef _WIN32 @@ -55,9 +53,12 @@ class ResultSet void CleanUp(); MYSQL_RES* _result; MYSQL_FIELD* _fields; + + ResultSet(ResultSet const& right) = delete; + ResultSet& operator=(ResultSet const& right) = delete; }; -typedef Trinity::AutoPtr<ResultSet, ACE_Thread_Mutex> QueryResult; +typedef std::shared_ptr<ResultSet> QueryResult; class PreparedResultSet { @@ -100,9 +101,11 @@ class PreparedResultSet void CleanUp(); bool _NextRow(); + PreparedResultSet(PreparedResultSet const& right) = delete; + PreparedResultSet& operator=(PreparedResultSet const& right) = delete; }; -typedef Trinity::AutoPtr<PreparedResultSet, ACE_Thread_Mutex> PreparedQueryResult; +typedef std::shared_ptr<PreparedResultSet> PreparedQueryResult; #endif diff --git a/src/server/shared/Database/SQLOperation.h b/src/server/shared/Database/SQLOperation.h index d7870a7d22e..4d6e349449d 100644 --- a/src/server/shared/Database/SQLOperation.h +++ b/src/server/shared/Database/SQLOperation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,9 +18,6 @@ #ifndef _SQLOPERATION_H #define _SQLOPERATION_H -#include <ace/Method_Request.h> -#include <ace/Activation_Queue.h> - #include "QueryResult.h" //- Forward declare (don't include header to prevent circular includes) @@ -56,10 +53,12 @@ union SQLResultSetUnion class MySQLConnection; -class SQLOperation : public ACE_Method_Request +class SQLOperation { public: SQLOperation(): m_conn(NULL) { } + virtual ~SQLOperation() { } + virtual int call() { Execute(); @@ -69,6 +68,10 @@ class SQLOperation : public ACE_Method_Request virtual void SetConnection(MySQLConnection* con) { m_conn = con; } MySQLConnection* m_conn; + + private: + SQLOperation(SQLOperation const& right) = delete; + SQLOperation& operator=(SQLOperation const& right) = delete; }; #endif diff --git a/src/server/shared/Database/Transaction.cpp b/src/server/shared/Database/Transaction.cpp index a1c900a51b9..2aadafa8f5d 100644 --- a/src/server/shared/Database/Transaction.cpp +++ b/src/server/shared/Database/Transaction.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h index e8e5a743a63..3822c2c82c1 100644 --- a/src/server/shared/Database/Transaction.h +++ b/src/server/shared/Database/Transaction.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -50,7 +50,7 @@ class Transaction bool _cleanedUp; }; -typedef Trinity::AutoPtr<Transaction, ACE_Thread_Mutex> SQLTransaction; +typedef std::shared_ptr<Transaction> SQLTransaction; /*! Low level class*/ class TransactionTask : public SQLOperation @@ -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 1bfe8c8e949..0621cfa5b6d 100644 --- a/src/server/shared/Debugging/Errors.cpp +++ b/src/server/shared/Debugging/Errors.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -18,17 +18,16 @@ #include "Errors.h" -#include <ace/Stack_Trace.h> -#include <ace/OS_NS_unistd.h> +#include <cstdio> #include <cstdlib> +#include <thread> namespace Trinity { void Assert(char const* file, int line, char const* function, char const* message) { - ACE_Stack_Trace st; - fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", - file, line, function, message, st.c_str()); + fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n", + file, line, function, message); *((volatile int*)NULL) = 0; exit(1); } @@ -37,7 +36,8 @@ 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", file, line, function, message); - ACE_OS::sleep(10); + + std::this_thread::sleep_for(std::chrono::seconds(10)); *((volatile int*)NULL) = 0; exit(1); } diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index 2821ca504e7..218acfa453e 100644 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -34,10 +34,18 @@ namespace Trinity } // namespace Trinity -#define WPAssert(cond) do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond); } while (0) -#define WPFatal(cond, msg) do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) -#define WPError(cond, msg) do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) -#define WPWarning(cond, msg) do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while (0) +#if COMPILER == COMPILER_MICROSOFT +#define ASSERT_BEGIN __pragma(warning(push)) __pragma(warning(disable: 4127)) +#define ASSERT_END __pragma(warning(pop)) +#else +#define ASSERT_BEGIN +#define ASSERT_END +#endif + +#define WPAssert(cond) ASSERT_BEGIN do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond); } 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 #define ASSERT WPAssert diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index f4da4093dfa..2eb456ddd02 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -29,15 +29,23 @@ inline LPTSTR ErrorMessage(DWORD dw) { LPVOID lpMsgBuf; - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, - 0, NULL); - return (LPTSTR)lpMsgBuf; + DWORD formatResult = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL); + if (formatResult != 0) + return (LPTSTR)lpMsgBuf; + else + { + LPTSTR msgBuf = (LPTSTR)LocalAlloc(LPTR, 30); + sprintf(msgBuf, "Unknown error: %u", dw); + return msgBuf; + } + } //============================== Global Variables ============================= @@ -51,6 +59,8 @@ LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter; 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; @@ -62,6 +72,13 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor // Install the unhandled exception filter function m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); m_hProcess = GetCurrentProcess(); + if (!IsDebuggerPresent()) + { + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + } } //============ @@ -71,6 +88,7 @@ WheatyExceptionReport::~WheatyExceptionReport() { if (m_previousFilter) SetUnhandledExceptionFilter(m_previousFilter); + ClearSymbols(); } //=========================================================== @@ -348,7 +366,7 @@ void WheatyExceptionReport::PrintSystemInfo() } //=========================================================================== -void WheatyExceptionReport::printTracesForAllThreads() +void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables) { THREADENTRY32 te32; @@ -384,7 +402,7 @@ void WheatyExceptionReport::printTracesForAllThreads() if (threadHandle) { if (GetThreadContext(threadHandle, &context)) - WriteStackDetails(&context, false, threadHandle); + WriteStackDetails(&context, bWriteVariables, threadHandle); CloseHandle(threadHandle); } } @@ -480,7 +498,7 @@ PEXCEPTION_POINTERS pExceptionInfo) CONTEXT trashableContext = *pCtx; WriteStackDetails(&trashableContext, false, NULL); - printTracesForAllThreads(); + printTracesForAllThreads(false); // #ifdef _M_IX86 // X86 Only! @@ -489,13 +507,14 @@ PEXCEPTION_POINTERS pExceptionInfo) trashableContext = *pCtx; WriteStackDetails(&trashableContext, true, NULL); + printTracesForAllThreads(true); - _tprintf(_T("========================\r\n")); + /*_tprintf(_T("========================\r\n")); _tprintf(_T("Global Variables\r\n")); SymEnumSymbols(GetCurrentProcess(), (UINT_PTR)GetModuleHandle(szFaultingModule), - 0, EnumerateSymbolsCallback, 0); + 0, EnumerateSymbolsCallback, 0);*/ // #endif // X86 Only! SymCleanup(GetCurrentProcess()); @@ -566,6 +585,9 @@ PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD_PTR& offset) DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase; + if (!hMod) + return FALSE; + if (!GetModuleFileName((HMODULE)hMod, szModule, len)) return FALSE; @@ -655,7 +677,7 @@ bool bWriteVariables, HANDLE pThreadHandle) dwMachineType = IMAGE_FILE_MACHINE_AMD64; #endif - while (1) + for (;;) { // Get the next stack frame if (! StackWalk64(dwMachineType, @@ -708,7 +730,7 @@ bool bWriteVariables, HANDLE pThreadHandle) } // Get the source line for this stack frame entry - IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE) }; + IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) }; DWORD dwLineDisplacement; if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo)) @@ -746,17 +768,21 @@ ULONG /*SymbolSize*/, PVOID UserContext) { - char szBuffer[2048]; + char szBuffer[WER_LARGE_BUFFER_SIZE]; + memset(szBuffer, 0, sizeof(szBuffer)); __try { - if (FormatSymbolValue(pSymInfo, (STACKFRAME*)UserContext, + ClearSymbols(); + if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext, szBuffer, sizeof(szBuffer))) - _tprintf(_T("\t%s\r\n"), szBuffer); + _tprintf(_T("%s"), szBuffer); } - __except(1) + __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; @@ -769,20 +795,14 @@ PVOID UserContext) ////////////////////////////////////////////////////////////////////////////// bool WheatyExceptionReport::FormatSymbolValue( PSYMBOL_INFO pSym, -STACKFRAME * sf, +STACKFRAME64 * sf, char * pszBuffer, 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 == 5) // SymTagFunction from CVCONST.H from the DIA SDK + if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK return false; DWORD_PTR pVariable = 0; // Will point to the variable's data in memory @@ -791,26 +811,36 @@ unsigned /*cbBuffer*/) { // if (pSym->Register == 8) // EBP is the value 8 (in DBGHELP 5.1) { // This may change!!! +#ifdef _M_IX86 pVariable = sf->AddrFrame.Offset; +#elif _M_X64 + pVariable = sf->AddrStack.Offset; +#endif pVariable += (DWORD_PTR)pSym->Address; } // else // 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) { @@ -818,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; } @@ -842,24 +876,227 @@ DWORD dwTypeIndex, unsigned nestingLevel, DWORD_PTR offset, bool & bHandled, -char* /*Name*/) +const char* Name, +char* /*suffix*/, +bool newSymbol, +bool logChildren) { bHandled = false; + if (newSymbol) + pszCurrBuffer = PushSymbolDetail(pszCurrBuffer); + + DWORD typeTag; + if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) + return pszCurrBuffer; + // Get the name of the symbol. This will either be a Type name (if a UDT), // or the structure member name. WCHAR * pwszTypeName; if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME, &pwszTypeName)) { - pszCurrBuffer += sprintf(pszCurrBuffer, " %ls", pwszTypeName); + // handle special cases + if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0) + { + LocalFree(pwszTypeName); + 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; + } + + 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 (!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) + { + case SymTagPointerType: + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) + { + if (Name != NULL && Name[0] != '\0') + symbolDetails.top().Name = Name; + + BOOL isReference; + SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); + + char addressStr[40]; + memset(addressStr, 0, sizeof(addressStr)); + + if (isReference) + symbolDetails.top().Suffix += "&"; + else + symbolDetails.top().Suffix += "*"; + + // Try to dereference the pointer in a try/except block since it might be invalid + DWORD_PTR address = DereferenceUnsafePointer(offset); + + char buffer[50]; + FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); + symbolDetails.top().Value = buffer; + + 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; + + 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 + { + // Get the size of the child member + ULONG64 length; + SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); + 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; + case SymTagData: + if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) + { + DWORD innerTypeTag; + if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) + break; + + switch (innerTypeTag) + { + 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>]"; + + 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: + break; + case SymTagEnum: + return pszCurrBuffer; + default: + break; + } // Determine how many children this type has. DWORD dwChildrenCount = 0; - SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, - &dwChildrenCount); + SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount); if (!dwChildrenCount) // If no children, we're done return pszCurrBuffer; @@ -869,7 +1106,7 @@ char* /*Name*/) // TI_FINDCHILDREN_PARAMS struct has. Use derivation to accomplish this. struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS { - ULONG MoreChildIds[1024]; + ULONG MoreChildIds[1024*2]; FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);} } children; @@ -883,32 +1120,55 @@ char* /*Name*/) return pszCurrBuffer; } - // Append a line feed - pszCurrBuffer += sprintf(pszCurrBuffer, "\r\n"); - // Iterate through each of the children for (unsigned i = 0; i < dwChildrenCount; i++) { - // Add appropriate indentation level (since this routine is recursive) - for (unsigned j = 0; j <= nestingLevel+1; j++) - pszCurrBuffer += sprintf(pszCurrBuffer, "\t"); + DWORD symTag; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); + + if (symTag == SymTagFunction || + symTag == SymTagEnum || + symTag == SymTagTypedef || + symTag == SymTagVTable) + continue; + + // 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; + SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], + TI_GET_OFFSET, &dwMemberOffset); + + // Calculate the address of the member + DWORD_PTR dwFinalOffset = offset + dwMemberOffset; pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, children.ChildId[i], nestingLevel+1, - offset, bHandled2, ""/*Name */); + dwFinalOffset, bHandled2, ""/*Name */, "", true, true); // If the child wasn't a UDT, format it appropriately if (!bHandled2) { - // Get the offset of the child member, relative to its parent - DWORD dwMemberOffset; - SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], - TI_GET_OFFSET, &dwMemberOffset); + 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. @@ -920,70 +1180,88 @@ char* /*Name*/) ULONG64 length; SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length); - // Calculate the address of the member - DWORD_PTR dwFinalOffset = offset + dwMemberOffset; - - // BasicType basicType = GetBasicType(children.ChildId[i], modBase); - // - // pszCurrBuffer += sprintf(pszCurrBuffer, rgBaseType[basicType]); - // - // Emit the variable name - // pszCurrBuffer += sprintf(pszCurrBuffer, "\'%s\'", Name); - - 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) { - // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!) - if (length == 1) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PBYTE)pAddress); - else if (length == 2) - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PWORD)pAddress); - else if (length == 4) + __try { - if (basicType == btFloat) + switch (basicType) { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %f", *(PFLOAT)pAddress); - } - else if (basicType == btChar) - { - if (!IsBadStringPtr(*(PSTR*)pAddress, 32)) + case btChar: { - pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%.31s\"", - *(PSTR*)pAddress); + if (strlen((char*)pAddress) > bufferSize - 6) + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", bufferSize - 6, (char*)pAddress); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", (char*)pAddress); + break; } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", - *(PDWORD)pAddress); + case btStdString: + { + 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, "0x%X", *(PBYTE)pAddress); + else if (length == 2) + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress); + else if (length == 4) + { + if (basicType == btFloat) + pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress); + else + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress); + } + else if (length == 8) + { + if (basicType == btFloat) + { + pszCurrBuffer += sprintf(pszCurrBuffer, "%lf", + *(double *)pAddress); + } + else + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", + *(DWORD64*)pAddress); + } + else + { + #if _WIN64 + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64*)pAddress); + #else + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (PDWORD)pAddress); + #endif + } + break; } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %X", *(PDWORD)pAddress); } - else if (length == 8) + __except (EXCEPTION_EXECUTE_HANDLER) { - if (basicType == btFloat) - { - pszCurrBuffer += sprintf(pszCurrBuffer, " = %lf", - *(double *)pAddress); - } - else - pszCurrBuffer += sprintf(pszCurrBuffer, " = %I64X", - *(DWORD64*)pAddress); +#if _WIN64 + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64*)pAddress); +#else + pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (PDWORD)pAddress); +#endif } - - return pszCurrBuffer; } BasicType @@ -1011,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]; + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; DWORD cbWritten; va_list argptr; @@ -1031,4 +1321,49 @@ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) return retValue; } +bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset) +{ + return symbols.insert(SymbolPair(type, offset)).second; +} + +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 582f1f157b8..9137b91aac9 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -4,13 +4,14 @@ #if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__) #include <dbghelp.h> +#include <set> +#include <stdlib.h> +#include <stack> +#define countof _countof -#if _MSC_VER < 1400 -# define countof(array) (sizeof(array) / sizeof(array[0])) -#else -# include <stdlib.h> -# define countof _countof -#endif // _MSC_VER < 1400 +#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 { @@ -31,43 +32,112 @@ enum BasicType // Stolen from CVCON btComplex = 28, btBit = 29, btBSTR = 30, - btHresult = 31 + btHresult = 31, + + // Custom types + 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 +{ + SymbolPair(DWORD type, DWORD_PTR offset) + { + _type = type; + _offset = offset; + } + + bool operator<(const SymbolPair& other) const + { + return _offset < other._offset || + (_offset == other._offset && _type < other._type); + } + + DWORD _type; + DWORD_PTR _offset; +}; +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 @@ -81,7 +151,7 @@ class WheatyExceptionReport static LONG WINAPI WheatyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptionInfo); - static void printTracesForAllThreads(); + static void printTracesForAllThreads(bool); private: // where report info is extracted and generated static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo); @@ -98,16 +168,20 @@ class WheatyExceptionReport static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID); - static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME *, char * pszBuffer, unsigned cbBuffer); + static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char * pszBuffer, unsigned cbBuffer); - static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, 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, ...); + static bool StoreSymbol(DWORD type , DWORD_PTR offset); + static void ClearSymbols(); + // Variables used by the class static TCHAR m_szLogFileName[MAX_PATH]; static TCHAR m_szDumpFileName[MAX_PATH]; @@ -115,6 +189,13 @@ class WheatyExceptionReport static HANDLE m_hReportFile; 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/Define.h b/src/server/shared/Define.h index d18f160aeaf..c33c8222ebb 100644 --- a/src/server/shared/Define.h +++ b/src/server/shared/Define.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -21,24 +21,36 @@ #include "CompilerDefs.h" -#include <ace/Basic_Types.h> -#include <ace/ACE_export.h> +#if COMPILER == COMPILER_GNU +# if !defined(__STDC_FORMAT_MACROS) +# define __STDC_FORMAT_MACROS +# endif +# if !defined(__STDC_CONSTANT_MACROS) +# define __STDC_CONSTANT_MACROS +# endif +# if !defined(_GLIBCXX_USE_NANOSLEEP) +# define _GLIBCXX_USE_NANOSLEEP +# endif +#endif #include <cstddef> +#include <cinttypes> +#include <climits> #define TRINITY_LITTLEENDIAN 0 #define TRINITY_BIGENDIAN 1 #if !defined(TRINITY_ENDIAN) -# if defined (ACE_BIG_ENDIAN) +# if defined (BOOST_BIG_ENDIAN) # define TRINITY_ENDIAN TRINITY_BIGENDIAN -# else //ACE_BYTE_ORDER != ACE_BIG_ENDIAN +# else # define TRINITY_ENDIAN TRINITY_LITTLEENDIAN -# endif //ACE_BYTE_ORDER -#endif //TRINITY_ENDIAN +# endif +#endif #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 @@ -70,29 +82,19 @@ # define ATTR_DEPRECATED #endif //COMPILER == COMPILER_GNU -#if COMPILER_HAS_CPP11_SUPPORT -# define OVERRIDE override -# define FINAL final -#else -# define OVERRIDE -# define FINAL -#endif //COMPILER_HAS_CPP11_SUPPORT - -#define UI64FMTD ACE_UINT64_FORMAT_SPECIFIER -#define UI64LIT(N) ACE_UINT64_LITERAL(N) - -#define SI64FMTD ACE_INT64_FORMAT_SPECIFIER -#define SI64LIT(N) ACE_INT64_LITERAL(N) +#define UI64FMTD "%" PRIu64 +#define UI64LIT(N) UINT64_C(N) -#define SIZEFMTD ACE_SIZE_T_FORMAT_SPECIFIER +#define SI64FMTD "%" PRId64 +#define SI64LIT(N) INT64_C(N) -typedef ACE_INT64 int64; -typedef ACE_INT32 int32; -typedef ACE_INT16 int16; -typedef ACE_INT8 int8; -typedef ACE_UINT64 uint64; -typedef ACE_UINT32 uint32; -typedef ACE_UINT16 uint16; -typedef ACE_UINT8 uint8; +typedef int64_t int64; +typedef int32_t int32; +typedef int16_t int16; +typedef int8_t int8; +typedef uint64_t uint64; +typedef uint32_t uint32; +typedef uint16_t uint16; +typedef uint8_t uint8; #endif //TRINITY_DEFINE_H diff --git a/src/server/shared/Dynamic/FactoryHolder.h b/src/server/shared/Dynamic/FactoryHolder.h index cea8cb9c0bb..a009fd37a7e 100644 --- a/src/server/shared/Dynamic/FactoryHolder.h +++ b/src/server/shared/Dynamic/FactoryHolder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -30,15 +30,13 @@ class FactoryHolder { public: typedef ObjectRegistry<FactoryHolder<T, Key >, Key > FactoryHolderRegistry; - friend class ACE_Singleton<FactoryHolderRegistry, ACE_Null_Mutex>; - typedef ACE_Singleton<FactoryHolderRegistry, ACE_Null_Mutex> FactoryHolderRepository; FactoryHolder(Key k) : i_key(k) { } virtual ~FactoryHolder() { } inline Key key() const { return i_key; } - void RegisterSelf(void) { FactoryHolderRepository::instance()->InsertItem(this, i_key); } - void DeregisterSelf(void) { FactoryHolderRepository::instance()->RemoveItem(this, false); } + void RegisterSelf(void) { FactoryHolderRegistry::instance()->InsertItem(this, i_key); } + void DeregisterSelf(void) { FactoryHolderRegistry::instance()->RemoveItem(this, false); } /// Abstract Factory create method virtual T* Create(void *data = NULL) const = 0; diff --git a/src/server/shared/Dynamic/HashNamespace.h b/src/server/shared/Dynamic/HashNamespace.h deleted file mode 100644 index 88fa8c6f00e..00000000000 --- a/src/server/shared/Dynamic/HashNamespace.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * 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 TRINITY_HASH_NAMESPACE_H -#define TRINITY_HASH_NAMESPACE_H - -#include "Define.h" - -#if COMPILER_HAS_CPP11_SUPPORT -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#elif defined(_STLPORT_VERSION) -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1600 // VS100 -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1500 && _HAS_TR1 -# define HASH_NAMESPACE_START namespace std { namespace tr1 { -# define HASH_NAMESPACE_END } } -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1300 -# define HASH_NAMESPACE_START namespace stdext { -# define HASH_NAMESPACE_END } - -#if !_HAS_TRADITIONAL_STL -#ifndef HASH_NAMESPACE -#define HASH_NAMESPACE -#else - -// can be not used by some platforms, so provide fake forward -HASH_NAMESPACE_START - -template<class K> -class hash -{ -public: - size_t operator() (K const&); -}; - -HASH_NAMESPACE_END - -#endif -#endif - -#elif COMPILER == COMPILER_INTEL -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#elif COMPILER == COMPILER_GNU && defined(__clang__) && defined(_LIBCPP_VERSION) -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#elif COMPILER == COMPILER_GNU && GCC_VERSION > 40200 -# define HASH_NAMESPACE_START namespace std { namespace tr1 { -# define HASH_NAMESPACE_END } } -#elif COMPILER == COMPILER_GNU && GCC_VERSION >= 30000 -# define HASH_NAMESPACE_START namespace __gnu_cxx { -# define HASH_NAMESPACE_END } - -#include <ext/hash_fun.h> -#include <string> - -HASH_NAMESPACE_START - -template<> -class hash<unsigned long long> -{ -public: - size_t operator()(const unsigned long long &__x) const { return (size_t)__x; } -}; - -template<typename T> -class hash<T *> -{ -public: - size_t operator()(T * const &__x) const { return (size_t)__x; } -}; - -template<> struct hash<std::string> -{ - size_t operator()(const std::string &__x) const - { - return hash<char const*>()(__x.c_str()); - } -}; - -HASH_NAMESPACE_END - -#else -# define HASH_NAMESPACE_START namespace std { -# define HASH_NAMESPACE_END } -#endif - -#if COMPILER != COMPILER_MICROSOFT - -// Visual Studio use non standard hash calculation function, so provide fake forward for other -HASH_NAMESPACE_START - -template<class K> -size_t hash_value(K const&); - -HASH_NAMESPACE_END - -#endif - -#endif diff --git a/src/server/shared/Dynamic/LinkedList.h b/src/server/shared/Dynamic/LinkedList.h index c8a6a88e473..87bbeaac380 100644 --- a/src/server/shared/Dynamic/LinkedList.h +++ b/src/server/shared/Dynamic/LinkedList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -33,8 +33,8 @@ class LinkedListElement LinkedListElement* iNext; LinkedListElement* iPrev; public: - LinkedListElement(): iNext(NULL), iPrev(NULL) { } - ~LinkedListElement() { delink(); } + LinkedListElement() : iNext(NULL), iPrev(NULL) { } + virtual ~LinkedListElement() { delink(); } bool hasNext() const { return(iNext && iNext->iNext != NULL); } bool hasPrev() const { return(iPrev && iPrev->iPrev != NULL); } @@ -73,6 +73,10 @@ class LinkedListElement iNext->iPrev = pElem; iNext = pElem; } + + private: + LinkedListElement(LinkedListElement const&); + LinkedListElement& operator=(LinkedListElement const&); }; //============================================ @@ -83,6 +87,7 @@ class LinkedListHead LinkedListElement iFirst; LinkedListElement iLast; uint32 iSize; + public: LinkedListHead(): iSize(0) { @@ -92,6 +97,8 @@ class LinkedListHead iLast.iPrev = &iFirst; } + virtual ~LinkedListHead() { } + bool isEmpty() const { return(!iFirst.iNext->isInList()); } LinkedListElement * getFirst() { return(isEmpty() ? NULL : iFirst.iNext); } @@ -143,7 +150,7 @@ class LinkedListHead typedef _Ty& reference; typedef _Ty const & const_reference; - Iterator() : _Ptr(0) + Iterator() : _Ptr(nullptr) { // construct with null node pointer } @@ -239,6 +246,10 @@ class LinkedListHead }; typedef Iterator<LinkedListElement> iterator; + + private: + LinkedListHead(LinkedListHead const&); + LinkedListHead& operator=(LinkedListHead const&); }; //============================================ diff --git a/src/server/shared/Dynamic/LinkedReference/RefManager.h b/src/server/shared/Dynamic/LinkedReference/RefManager.h index e3a42b4bdc9..584066dde5c 100644 --- a/src/server/shared/Dynamic/LinkedReference/RefManager.h +++ b/src/server/shared/Dynamic/LinkedReference/RefManager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Dynamic/LinkedReference/Reference.h b/src/server/shared/Dynamic/LinkedReference/Reference.h index 8604f3431e0..83a1dd155b1 100644 --- a/src/server/shared/Dynamic/LinkedReference/Reference.h +++ b/src/server/shared/Dynamic/LinkedReference/Reference.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -94,6 +94,10 @@ template <class TO, class FROM> class Reference : public LinkedListElement TO* getTarget() const { return iRefTo; } FROM* GetSource() const { return iRefFrom; } + + private: + Reference(Reference const&); + Reference& operator=(Reference const&); }; //===================================================== diff --git a/src/server/shared/Dynamic/ObjectRegistry.h b/src/server/shared/Dynamic/ObjectRegistry.h index 1b402eb3be1..fe55982f15f 100644 --- a/src/server/shared/Dynamic/ObjectRegistry.h +++ b/src/server/shared/Dynamic/ObjectRegistry.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -20,12 +20,10 @@ #define TRINITY_OBJECTREGISTRY_H #include "Define.h" -#include "Dynamic/UnorderedMap.h" -#include <ace/Singleton.h> #include <string> -#include <vector> #include <map> +#include <vector> /** ObjectRegistry holds all registry item of the same type */ @@ -33,7 +31,13 @@ template<class T, class Key = std::string> class ObjectRegistry { public: - typedef std::map<Key, T *> RegistryMapType; + typedef std::map<Key, T*> RegistryMapType; + + static ObjectRegistry<T, Key>* instance() + { + static ObjectRegistry<T, Key> instance; + return &instance; + } /// Returns a registry item const T* GetRegistryItem(Key key) const diff --git a/src/server/shared/Dynamic/TypeContainer.h b/src/server/shared/Dynamic/TypeContainer.h index a99a448e0b8..5fe5c947dfe 100644 --- a/src/server/shared/Dynamic/TypeContainer.h +++ b/src/server/shared/Dynamic/TypeContainer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Dynamic/TypeContainerFunctions.h b/src/server/shared/Dynamic/TypeContainerFunctions.h index 22f8be4ed5f..16701e1ab5a 100644 --- a/src/server/shared/Dynamic/TypeContainerFunctions.h +++ b/src/server/shared/Dynamic/TypeContainerFunctions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Dynamic/TypeContainerVisitor.h b/src/server/shared/Dynamic/TypeContainerVisitor.h index 8ca3ee8dbc4..120d9880f03 100644 --- a/src/server/shared/Dynamic/TypeContainerVisitor.h +++ b/src/server/shared/Dynamic/TypeContainerVisitor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Dynamic/TypeList.h b/src/server/shared/Dynamic/TypeList.h index f32a0ef1d64..c5dc1ee21a4 100644 --- a/src/server/shared/Dynamic/TypeList.h +++ b/src/server/shared/Dynamic/TypeList.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Dynamic/UnorderedMap.h b/src/server/shared/Dynamic/UnorderedMap.h deleted file mode 100644 index 701e7f339e2..00000000000 --- a/src/server/shared/Dynamic/UnorderedMap.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * 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 TRINITY_UNORDERED_MAP_H -#define TRINITY_UNORDERED_MAP_H - -#include "HashNamespace.h" - -#if COMPILER_HAS_CPP11_SUPPORT -# include <unordered_map> -#elif COMPILER == COMPILER_INTEL -# include <ext/hash_map> -#elif COMPILER == COMPILER_GNU && defined(__clang__) && defined(_LIBCPP_VERSION) -# include <unordered_map> -#elif COMPILER == COMPILER_GNU && GCC_VERSION > 40200 -# include <tr1/unordered_map> -#elif COMPILER == COMPILER_GNU && GCC_VERSION >= 30000 -# include <ext/hash_map> -#elif COMPILER == COMPILER_MICROSOFT && ((_MSC_VER >= 1500 && _HAS_TR1) || _MSC_VER >= 1700) // VC9.0 SP1 and later -# include <unordered_map> -#else -# include <hash_map> -#endif - -#ifdef _STLPORT_VERSION -# define UNORDERED_MAP std::hash_map -# define UNORDERED_MULTIMAP std::hash_multimap -#elif COMPILER_HAS_CPP11_SUPPORT -# define UNORDERED_MAP std::unordered_map -# define UNORDERED_MULTIMAP std::unordered_multimap -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1600 // VS100 -# define UNORDERED_MAP std::tr1::unordered_map -# define UNORDERED_MULTIMAP std::tr1::unordered_multimap -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1500 && _HAS_TR1 -# define UNORDERED_MAP std::tr1::unordered_map -# define UNORDERED_MULTIMAP std::tr1::unordered_multimap -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1300 -# define UNORDERED_MAP stdext::hash_map -# define UNORDERED_MULTIMAP stdext::hash_multimap -#elif COMPILER == COMPILER_INTEL -# define UNORDERED_MAP std::hash_map -# define UNORDERED_MULTIMAP std::hash_multimap -#elif COMPILER == COMPILER_GNU && defined(__clang__) && defined(_LIBCPP_VERSION) -# define UNORDERED_MAP std::unordered_map -# define UNORDERED_MULTIMAP std::unordered_multimap -#elif COMPILER == COMPILER_GNU && GCC_VERSION > 40200 -# define UNORDERED_MAP std::tr1::unordered_map -# define UNORDERED_MULTIMAP std::tr1::unordered_multimap -#elif COMPILER == COMPILER_GNU && GCC_VERSION >= 30000 -# define UNORDERED_MAP __gnu_cxx::hash_map -# define UNORDERED_MULTIMAP __gnu_cxx::hash_multimap -#else -# define UNORDERED_MAP std::hash_map -# define UNORDERED_MULTIMAP std::hash_multimap -#endif - -#endif diff --git a/src/server/shared/Dynamic/UnorderedSet.h b/src/server/shared/Dynamic/UnorderedSet.h deleted file mode 100644 index 862358e7fe7..00000000000 --- a/src/server/shared/Dynamic/UnorderedSet.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * 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 TRINITY_UNORDERED_SET_H -#define TRINITY_UNORDERED_SET_H - -#include "HashNamespace.h" - -#if COMPILER_HAS_CPP11_SUPPORT -# include <unordered_set> -#elif COMPILER == COMPILER_INTEL -# include <ext/hash_set> -#elif COMPILER == COMPILER_GNU && defined(__clang__) && defined(_LIBCPP_VERSION) -# include <unordered_set> -#elif COMPILER == COMPILER_GNU && GCC_VERSION > 40200 -# include <tr1/unordered_set> -#elif COMPILER == COMPILER_GNU && GCC_VERSION >= 30000 -# include <ext/hash_set> -#elif COMPILER == COMPILER_MICROSOFT && ((_MSC_VER >= 1500 && _HAS_TR1) || _MSC_VER >= 1700) // VC9.0 SP1 and later -# include <unordered_set> -#else -# include <hash_set> -#endif - -#ifdef _STLPORT_VERSION -# define UNORDERED_SET std::hash_set -using std::hash_set; -#elif COMPILER_HAS_CPP11_SUPPORT -# define UNORDERED_SET std::unordered_set -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1600 // VS100 -# define UNORDERED_SET std::tr1::unordered_set -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1500 && _HAS_TR1 -# define UNORDERED_SET std::tr1::unordered_set -#elif COMPILER == COMPILER_MICROSOFT && _MSC_VER >= 1300 -# define UNORDERED_SET stdext::hash_set -using stdext::hash_set; -#elif COMPILER == COMPILER_INTEL -# define UNORDERED_SET std::hash_set -using std::hash_set; -#elif COMPILER == COMPILER_GNU && defined(__clang__) && defined(_LIBCPP_VERSION) -# define UNORDERED_SET std::unordered_set -#elif COMPILER == COMPILER_GNU && GCC_VERSION > 40200 -# define UNORDERED_SET std::tr1::unordered_set -#elif COMPILER == COMPILER_GNU && GCC_VERSION >= 30000 -# define UNORDERED_SET __gnu_cxx::hash_set -#else -# define UNORDERED_SET std::hash_set -using std::hash_set; -#endif - -#endif diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp index 06aa6159014..2b38f9886c3 100644 --- a/src/server/shared/Logging/Appender.cpp +++ b/src/server/shared/Logging/Appender.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -17,11 +17,12 @@ #include "Appender.h" #include "Common.h" +#include "Util.h" std::string LogMessage::getTimeStr(time_t time) { tm aTm; - ACE_OS::localtime_r(&time, &aTm); + localtime_r(&time, &aTm); char buf[20]; snprintf(buf, 20, "%04d-%02d-%02d_%02d:%02d:%02d", aTm.tm_year+1900, aTm.tm_mon+1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec); return std::string(buf); diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h index 437c301ea6b..67213d0ddd0 100644 --- a/src/server/shared/Logging/Appender.h +++ b/src/server/shared/Logging/Appender.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,11 +18,10 @@ #ifndef APPENDER_H #define APPENDER_H -#include "Define.h" -#include <time.h> -#include "Dynamic/UnorderedMap.h" - +#include <unordered_map> #include <string> +#include <time.h> +#include "Define.h" // Values assigned have their equivalent in enum ACE_Log_Priority enum LogLevel @@ -105,6 +104,6 @@ class Appender AppenderFlags flags; }; -typedef UNORDERED_MAP<uint8, Appender*> AppenderMap; +typedef std::unordered_map<uint8, Appender*> AppenderMap; #endif diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp index 78350029205..20923162906 100644 --- a/src/server/shared/Logging/AppenderConsole.cpp +++ b/src/server/shared/Logging/AppenderConsole.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -15,11 +15,15 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <sstream> + #include "AppenderConsole.h" #include "Config.h" #include "Util.h" -#include <sstream> +#if PLATFORM == PLATFORM_WINDOWS + #include <Windows.h> +#endif AppenderConsole::AppenderConsole(uint8 id, std::string const& name, LogLevel level, AppenderFlags flags): Appender(id, name, APPENDER_CONSOLE, level, flags), _colored(false) diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h index 6f3fcca901c..5b66f86650d 100644 --- a/src/server/shared/Logging/AppenderConsole.h +++ b/src/server/shared/Logging/AppenderConsole.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,8 +18,8 @@ #ifndef APPENDERCONSOLE_H #define APPENDERCONSOLE_H -#include "Appender.h" #include <string> +#include "Appender.h" enum ColorTypes { @@ -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.cpp b/src/server/shared/Logging/AppenderDB.cpp index 204592720dc..d18a5ad8a50 100644 --- a/src/server/shared/Logging/AppenderDB.cpp +++ b/src/server/shared/Logging/AppenderDB.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h index f9dde0a1e82..b86252d0d67 100644 --- a/src/server/shared/Logging/AppenderDB.h +++ b/src/server/shared/Logging/AppenderDB.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -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.cpp b/src/server/shared/Logging/AppenderFile.cpp index d5410112b97..3e79ac40c6f 100644 --- a/src/server/shared/Logging/AppenderFile.cpp +++ b/src/server/shared/Logging/AppenderFile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -16,6 +16,7 @@ */ #include "AppenderFile.h" +#include "Common.h" #if PLATFORM == PLATFORM_WINDOWS # include <Windows.h> @@ -33,7 +34,8 @@ AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, co dynamicName = std::string::npos != filename.find("%s"); backup = (_flags & APPENDER_FLAGS_MAKE_FILE_BACKUP) != 0; - logfile = !dynamicName ? OpenFile(_filename, _mode, mode == "w" && backup) : NULL; + if (!dynamicName) + logfile = OpenFile(_filename, _mode, mode == "w" && backup); } AppenderFile::~AppenderFile() @@ -43,13 +45,21 @@ AppenderFile::~AppenderFile() void AppenderFile::_write(LogMessage const& message) { - bool exceedMaxSize = maxFileSize > 0 && (fileSize.value() + message.Size()) > maxFileSize; + bool exceedMaxSize = maxFileSize > 0 && (fileSize.load() + message.Size()) > maxFileSize; if (dynamicName) { char namebuf[TRINITY_PATH_MAX]; snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str()); - logfile = OpenFile(namebuf, mode, backup || exceedMaxSize); + // always use "a" with dynamic name otherwise it could delete the log we wrote in last _write() call + FILE* file = OpenFile(namebuf, "a", backup || exceedMaxSize); + if (!file) + return; + fprintf(file, "%s%s", message.prefix.c_str(), message.text.c_str()); + fflush(file); + fileSize += uint64(message.Size()); + fclose(file); + return; } else if (exceedMaxSize) logfile = OpenFile(filename, "w", true); @@ -60,9 +70,6 @@ void AppenderFile::_write(LogMessage const& message) fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str()); fflush(logfile); fileSize += uint64(message.Size()); - - if (dynamicName) - CloseFile(); } FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup) @@ -74,6 +81,7 @@ FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mod std::string newName(fullName); newName.push_back('.'); newName.append(LogMessage::getTimeStr(time(NULL))); + std::replace(newName.begin(), newName.end(), ':', '-'); rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore } diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index de94a46d692..37ba2769e19 100644 --- a/src/server/shared/Logging/AppenderFile.h +++ b/src/server/shared/Logging/AppenderFile.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,8 +18,8 @@ #ifndef APPENDERFILE_H #define APPENDERFILE_H +#include <atomic> #include "Appender.h" -#include "ace/Atomic_Op.h" class AppenderFile: public Appender { @@ -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; @@ -38,7 +38,7 @@ class AppenderFile: public Appender bool dynamicName; bool backup; uint64 maxFileSize; - ACE_Atomic_Op<ACE_Thread_Mutex, uint64> fileSize; + std::atomic<uint64> fileSize; }; #endif diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index bca150b7059..a7b6b418cc4 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ #include <cstdio> #include <sstream> -Log::Log() : worker(NULL) +Log::Log() : _ioService(nullptr), _strand(nullptr) { m_logsTimestamp = "_" + GetTimestampStr(); LoadFromConfig(); @@ -37,6 +37,7 @@ Log::Log() : worker(NULL) Log::~Log() { + delete _strand; Close(); } @@ -272,8 +273,13 @@ void Log::write(LogMessage* msg) const Logger const* logger = GetLoggerByType(msg->type); msg->text.append("\n"); - if (worker) - worker->enqueue(new LogOperation(logger, msg)); + if (_ioService) + { + auto logOperation = std::shared_ptr<LogOperation>(new LogOperation(logger, msg)); + + _ioService->post(_strand->wrap([logOperation](){ logOperation->call(); })); + + } else { logger->write(*msg); @@ -283,9 +289,11 @@ void Log::write(LogMessage* msg) const std::string Log::GetTimestampStr() { - time_t t = time(NULL); - tm aTm; - ACE_OS::localtime_r(&t, &aTm); + time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + + std::tm aTm; + localtime_r(&tt, &aTm); + // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) @@ -373,8 +381,6 @@ void Log::SetRealmId(uint32 id) void Log::Close() { - delete worker; - worker = NULL; loggers.clear(); for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) { @@ -388,9 +394,6 @@ void Log::LoadFromConfig() { Close(); - if (sConfigMgr->GetBoolDefault("Log.Async.Enable", false)) - worker = new LogWorker(); - AppenderId = 0; m_logsDir = sConfigMgr->GetStringDefault("LogsDir", ""); if (!m_logsDir.empty()) diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index af522a6745f..78e7e012bbe 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -22,25 +22,38 @@ #include "Define.h" #include "Appender.h" #include "Logger.h" -#include "LogWorker.h" -#include "Dynamic/UnorderedMap.h" +#include <stdarg.h> +#include <boost/asio/io_service.hpp> +#include <boost/asio/strand.hpp> +#include <unordered_map> #include <string> -#include <ace/Singleton.h> #define LOGGER_ROOT "root" class Log { - friend class ACE_Singleton<Log, ACE_Thread_Mutex>; - - typedef UNORDERED_MAP<std::string, Logger> LoggerMap; + typedef std::unordered_map<std::string, Logger> LoggerMap; private: Log(); ~Log(); public: + + static Log* instance(boost::asio::io_service* ioService = nullptr) + { + static Log instance; + + if (ioService != nullptr) + { + instance._ioService = ioService; + instance._strand = new boost::asio::strand(*ioService); + } + + return &instance; + } + void LoadFromConfig(); void Close(); bool ShouldLog(std::string const& type, LogLevel level) const; @@ -73,7 +86,8 @@ class Log std::string m_logsDir; std::string m_logsTimestamp; - LogWorker* worker; + boost::asio::io_service* _ioService; + boost::asio::strand* _strand; }; inline Logger const* Log::GetLoggerByType(std::string const& type) const @@ -117,9 +131,9 @@ inline void Log::outMessage(std::string const& filter, LogLevel level, const cha va_end(ap); } -#define sLog ACE_Singleton<Log, ACE_Thread_Mutex>::instance() +#define sLog Log::instance() -#if COMPILER != COMPILER_MICROSOFT +#if PLATFORM != PLATFORM_WINDOWS #define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \ do { \ if (sLog->ShouldLog(filterType__, level__)) \ diff --git a/src/server/shared/Logging/LogOperation.cpp b/src/server/shared/Logging/LogOperation.cpp index f3d3649aa97..5f241d89712 100644 --- a/src/server/shared/Logging/LogOperation.cpp +++ b/src/server/shared/Logging/LogOperation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Logging/LogOperation.h b/src/server/shared/Logging/LogOperation.h index 237f50de4ad..bd90da254a6 100644 --- a/src/server/shared/Logging/LogOperation.h +++ b/src/server/shared/Logging/LogOperation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Logging/LogWorker.cpp b/src/server/shared/Logging/LogWorker.cpp deleted file mode 100644 index 857deb926fe..00000000000 --- a/src/server/shared/Logging/LogWorker.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2008-2013 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/>. - */ - -#include "LogWorker.h" - -LogWorker::LogWorker() - : m_queue(HIGH_WATERMARK, LOW_WATERMARK) -{ - ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, 1); -} - -LogWorker::~LogWorker() -{ - m_queue.deactivate(); - wait(); -} - -int LogWorker::enqueue(LogOperation* op) -{ - return m_queue.enqueue(op); -} - -int LogWorker::svc() -{ - while (1) - { - LogOperation* request; - if (m_queue.dequeue(request) == -1) - break; - - request->call(); - delete request; - } - - return 0; -} diff --git a/src/server/shared/Logging/LogWorker.h b/src/server/shared/Logging/LogWorker.h deleted file mode 100644 index 78571b596d7..00000000000 --- a/src/server/shared/Logging/LogWorker.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2008-2013 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 LOGWORKER_H -#define LOGWORKER_H - -#include "LogOperation.h" - -#include <ace/Task.h> -#include <ace/Activation_Queue.h> - -class LogWorker: protected ACE_Task_Base -{ - public: - LogWorker(); - ~LogWorker(); - - typedef ACE_Message_Queue_Ex<LogOperation, ACE_MT_SYNCH> LogMessageQueueType; - - enum - { - HIGH_WATERMARK = 8 * 1024 * 1024, - LOW_WATERMARK = 8 * 1024 * 1024 - }; - - int enqueue(LogOperation *op); - - private: - virtual int svc(); - LogMessageQueueType m_queue; -}; - -#endif diff --git a/src/server/shared/Logging/Logger.cpp b/src/server/shared/Logging/Logger.cpp index 6fff993e2ae..dae8edc6ca9 100644 --- a/src/server/shared/Logging/Logger.cpp +++ b/src/server/shared/Logging/Logger.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Logging/Logger.h b/src/server/shared/Logging/Logger.h index 24727ce1016..c7826f0615c 100644 --- a/src/server/shared/Logging/Logger.h +++ b/src/server/shared/Logging/Logger.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h new file mode 100644 index 00000000000..64665c2b198 --- /dev/null +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -0,0 +1,73 @@ +/* +* 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 __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(); + }; + + AsyncAcceptor(boost::asio::io_service& ioService, std::string bindIp, int port, bool tcpNoDelay) : + _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(); + }; + +private: + void 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(); + }); + } + + tcp::acceptor _acceptor; + tcp::socket _socket; +}; + +#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..c7f8ba31a71 --- /dev/null +++ b/src/server/shared/Networking/MessageBuffer.h @@ -0,0 +1,95 @@ +/* +* 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), _storage() { } + + MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _storage(right._storage) { } + + MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _storage(right.Move()) { } + + void Reset() + { + _storage.clear(); + _wpos = 0; + } + + bool IsMessageReady() const { return _wpos == _storage.size(); } + + size_type GetSize() const { return _storage.size(); } + + size_type GetReadyDataSize() const { return _wpos; } + + size_type GetMissingSize() const { return _storage.size() - _wpos; } + + uint8* Data() { return _storage.data(); } + + void Grow(size_type bytes) + { + _storage.resize(_storage.size() + bytes); + } + + uint8* GetWritePointer() { return &_storage[_wpos]; } + + void WriteCompleted(size_type bytes) { _wpos += bytes; } + + void ResetWritePointer() { _wpos = 0; } + + std::vector<uint8>&& Move() + { + _wpos = 0; + return std::move(_storage); + } + + MessageBuffer& operator=(MessageBuffer& right) + { + if (this != &right) + { + _wpos = right._wpos; + _storage = right._storage; + } + + return *this; + } + + MessageBuffer& operator=(MessageBuffer&& right) + { + if (this != &right) + { + _wpos = right._wpos; + _storage = right.Move(); + } + + return *this; + } + +private: + size_type _wpos; + std::vector<uint8> _storage; +}; + +#endif /* __MESSAGEBUFFER_H_ */ diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h new file mode 100644 index 00000000000..3bd30bd731b --- /dev/null +++ b/src/server/shared/Networking/Socket.h @@ -0,0 +1,252 @@ +/* + * 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 __SOCKET_H__ +#define __SOCKET_H__ + +#include "MessageBuffer.h" +#include "Log.h" +#include <atomic> +#include <vector> +#include <mutex> +#include <queue> +#include <memory> +#include <functional> +#include <type_traits> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/write.hpp> +#include <boost/asio/read.hpp> + +using boost::asio::ip::tcp; + +#define READ_BLOCK_SIZE 4096 + +template<class T, class PacketType> +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)), _remoteAddress(_socket.remote_endpoint().address()), + _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false), _closing(false) + { + _readHeaderBuffer.Grow(headerSize); + } + + virtual ~Socket() + { + boost::system::error_code error; + _socket.close(error); + + while (!_writeQueue.empty()) + { + DeletePacket(_writeQueue.front()); + _writeQueue.pop(); + } + } + + virtual void Start() = 0; + + boost::asio::ip::address GetRemoteIpAddress() const + { + return _remoteAddress; + } + + uint16 GetRemotePort() const + { + return _remotePort; + } + + void AsyncReadHeader() + { + if (!IsOpen()) + return; + + _readHeaderBuffer.ResetWritePointer(); + _readDataBuffer.Reset(); + + AsyncReadMissingHeaderData(); + } + + void AsyncReadData(std::size_t size) + { + if (!IsOpen()) + return; + + if (!size) + { + // if this is a packet with 0 length body just invoke handler directly + ReadDataHandler(); + return; + } + + _readDataBuffer.Grow(size); + AsyncReadMissingData(); + } + + void ReadData(std::size_t size) + { + if (!IsOpen()) + return; + + boost::system::error_code error; + + _readDataBuffer.Grow(size); + + std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readDataBuffer.GetWritePointer(), size), error); + + _readDataBuffer.WriteCompleted(bytesRead); + + if (error || !_readDataBuffer.IsMessageReady()) + { + 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) + { + 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)); + } + + bool IsOpen() const { return !_closed && !_closing; } + + virtual void CloseSocket() + { + 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()); + } + + /// Marks the socket for closing after write buffer becomes empty + void DelayedCloseSocket() { _closing = true; } + + virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); } + virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); } + + uint8* GetHeaderBuffer() { return _readHeaderBuffer.Data(); } + uint8* GetDataBuffer() { return _readDataBuffer.Data(); } + + size_t GetHeaderSize() const { return _readHeaderBuffer.GetReadyDataSize(); } + size_t GetDataSize() const { return _readDataBuffer.GetReadyDataSize(); } + + MessageBuffer&& MoveHeader() { return std::move(_readHeaderBuffer); } + MessageBuffer&& MoveData() { return std::move(_readDataBuffer); } + +protected: + virtual void ReadHeaderHandler() = 0; + virtual void ReadDataHandler() = 0; + + std::mutex _writeLock; + std::queue<PacketType> _writeQueue; + +private: + void AsyncReadMissingHeaderData() + { + _socket.async_read_some(boost::asio::buffer(_readHeaderBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readHeaderBuffer.GetMissingSize())), + std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); + } + + void AsyncReadMissingData() + { + _socket.async_read_some(boost::asio::buffer(_readDataBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readDataBuffer.GetMissingSize())), + std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); + } + + void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferredBytes) + { + if (error) + { + CloseSocket(); + return; + } + + _readHeaderBuffer.WriteCompleted(transferredBytes); + if (!IsHeaderReady()) + { + // incomplete, read more + AsyncReadMissingHeaderData(); + return; + } + + ReadHeaderHandler(); + } + + void ReadDataHandlerInternal(boost::system::error_code error, size_t transferredBytes) + { + if (error) + { + CloseSocket(); + return; + } + + _readDataBuffer.WriteCompleted(transferredBytes); + if (!IsDataReady()) + { + // incomplete, read more + AsyncReadMissingData(); + return; + } + + ReadDataHandler(); + } + + void WriteHandler(boost::system::error_code error, size_t /*transferedBytes*/) + { + if (!error) + { + std::lock_guard<std::mutex> deleteGuard(_writeLock); + + DeletePacket(_writeQueue.front()); + _writeQueue.pop(); + + if (!_writeQueue.empty()) + AsyncWrite(_writeQueue.front()); + 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; } + + template<typename Q = PacketType> + typename std::enable_if<!std::is_pointer<Q>::value>::type DeletePacket(PacketType const& /*packet*/) { } + + tcp::socket _socket; + + boost::asio::ip::address _remoteAddress; + uint16 _remotePort; + + MessageBuffer _readHeaderBuffer; + MessageBuffer _readDataBuffer; + + std::atomic<bool> _closed; + std::atomic<bool> _closing; +}; + +#endif // __SOCKET_H__ diff --git a/src/server/shared/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp index 8fba0fc23a4..3785d1c29fa 100644 --- a/src/server/shared/Packets/ByteBuffer.cpp +++ b/src/server/shared/Packets/ByteBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -17,21 +17,24 @@ */ #include "ByteBuffer.h" +#include "MessageBuffer.h" #include "Common.h" #include "Log.h" -#include <ace/Stack_Trace.h> #include <sstream> +ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _storage(buffer.Move()) +{ +} + ByteBufferPositionException::ByteBufferPositionException(bool add, size_t pos, size_t size, size_t valueSize) { std::ostringstream ss; - ACE_Stack_Trace trace; ss << "Attempted to " << (add ? "put" : "get") << " value with size: " << valueSize << " in ByteBuffer (pos: " << pos << " size: " << size - << ")\n\n" << trace.c_str(); + << ")"; message().assign(ss.str()); } @@ -40,12 +43,10 @@ ByteBufferSourceException::ByteBufferSourceException(size_t pos, size_t size, size_t valueSize) { std::ostringstream ss; - ACE_Stack_Trace trace; ss << "Attempted to put a " << (valueSize > 0 ? "NULL-pointer" : "zero-sized value") - << " in ByteBuffer (pos: " << pos << " size: " << size << ")\n\n" - << trace.c_str(); + << " in ByteBuffer (pos: " << pos << " size: " << size << ")"; message().assign(ss.str()); } @@ -73,8 +74,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 << " "; @@ -94,7 +95,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 d2677538805..046fdc0c8e9 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -22,8 +22,8 @@ #include "Define.h" #include "Errors.h" #include "ByteConverter.h" +#include "Util.h" -#include <ace/OS_NS_time.h> #include <exception> #include <list> #include <map> @@ -31,6 +31,10 @@ #include <vector> #include <cstring> #include <time.h> +#include <cmath> +#include <boost/asio/buffer.hpp> + +class MessageBuffer; // Root of ByteBuffer exception hierarchy class ByteBufferException : public std::exception @@ -38,7 +42,7 @@ 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_; } @@ -79,12 +83,28 @@ class ByteBuffer _storage.reserve(reserve); } - // copy constructor - ByteBuffer(const ByteBuffer &buf) : _rpos(buf._rpos), _wpos(buf._wpos), - _storage(buf._storage) + ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos), + _storage(std::move(buf._storage)) { } + + ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos), + _storage(right._storage) { } + + ByteBuffer(MessageBuffer&& buffer); + + ByteBuffer& operator=(ByteBuffer const& right) { + if (this != &right) + { + _rpos = right._rpos; + _wpos = right._wpos; + _storage = right._storage; + } + + return *this; } + virtual ~ByteBuffer() { } + void clear() { _storage.clear(); @@ -239,12 +259,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; } @@ -375,9 +399,19 @@ class ByteBuffer return *this; } - uint8 * contents() { return &_storage[0]; } + uint8* contents() + { + if (_storage.empty()) + throw ByteBufferException(); + return _storage.data(); + } - const uint8 *contents() const { return &_storage[0]; } + uint8 const* contents() const + { + if (_storage.empty()) + throw ByteBufferException(); + return _storage.data(); + } size_t size() const { return _storage.size(); } bool empty() const { return _storage.empty(); } @@ -459,7 +493,7 @@ class ByteBuffer void AppendPackedTime(time_t time) { tm lt; - ACE_OS::localtime_r(&time, <); + localtime_r(&time, <); append<uint32>((lt.tm_year - 100) << 24 | lt.tm_mon << 20 | (lt.tm_mday - 1) << 14 | lt.tm_wday << 11 | lt.tm_hour << 6 | lt.tm_min); } @@ -591,5 +625,15 @@ inline void ByteBuffer::read_skip<std::string>() read_skip<char*>(); } -#endif +namespace boost +{ + namespace asio + { + inline const_buffers_1 buffer(ByteBuffer const& packet) + { + return buffer(packet.contents(), packet.size()); + } + } +} +#endif diff --git a/src/server/shared/Packets/WorldPacket.h b/src/server/shared/Packets/WorldPacket.h index 7ec2b5d1e1e..848a00739fe 100644 --- a/src/server/shared/Packets/WorldPacket.h +++ b/src/server/shared/Packets/WorldPacket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -29,12 +29,30 @@ class WorldPacket : public ByteBuffer WorldPacket() : ByteBuffer(0), m_opcode(0) { } + explicit WorldPacket(uint16 opcode, size_t res=200) : ByteBuffer(res), m_opcode(opcode) { } - // copy constructor - WorldPacket(const WorldPacket &packet) : ByteBuffer(packet), m_opcode(packet.m_opcode) + + WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode) + { + } + + WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode) + { + } + + WorldPacket& operator=(WorldPacket const& right) { + if (this != &right) + { + m_opcode = right.m_opcode; + ByteBuffer::operator =(right); + } + + return *this; } + WorldPacket(uint16 opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { } + void Initialize(uint16 opcode, size_t newres=200) { clear(); @@ -48,5 +66,5 @@ class WorldPacket : public ByteBuffer protected: uint16 m_opcode; }; -#endif +#endif diff --git a/src/server/shared/SystemConfig.h b/src/server/shared/SystemConfig.h index c3e54763ff0..dd5e9a2f90d 100644 --- a/src/server/shared/SystemConfig.h +++ b/src/server/shared/SystemConfig.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h index d4214cf0843..b462fce25d5 100644 --- a/src/server/shared/Threading/Callback.h +++ b/src/server/shared/Threading/Callback.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * 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 @@ -18,17 +18,14 @@ #ifndef _CALLBACK_H #define _CALLBACK_H -#include <ace/Future.h> -#include <ace/Future_Set.h> +#include <future> #include "QueryResult.h" -typedef ACE_Future<QueryResult> QueryResultFuture; -typedef ACE_Future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::future<QueryResult> QueryResultFuture; +typedef std::promise<QueryResult> QueryResultPromise; +typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; -/*! A simple template using ACE_Future to manage callbacks from the thread and object that - issued the request. <ParamType> is variable type of parameter that is used as parameter - for the callback function. -*/ #define CALLBACK_STAGE_INVALID uint8(-1) template <typename Result, typename ParamType, bool chain = false> @@ -38,29 +35,29 @@ class QueryCallback QueryCallback() : _param(), _stage(chain ? 0 : CALLBACK_STAGE_INVALID) { } //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery - void SetFutureResult(ACE_Future<Result> value) + void SetFutureResult(std::future<Result> value) { - _result = value; + _result = std::move(value); } - ACE_Future<Result> GetFutureResult() + std::future<Result>& GetFutureResult() { return _result; } int IsReady() { - return _result.ready(); + return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } void GetResult(Result& res) { - _result.get(res); + res = _result.get(); } void FreeResult() { - _result.cancel(); + // Nothing to do here, the constructor of std::future will take care of the cleanup } void SetParam(ParamType value) @@ -106,9 +103,12 @@ class QueryCallback } private: - ACE_Future<Result> _result; + std::future<Result> _result; ParamType _param; uint8 _stage; + + QueryCallback(QueryCallback const& right) = delete; + QueryCallback& operator=(QueryCallback const& right) = delete; }; template <typename Result, typename ParamType1, typename ParamType2, bool chain = false> @@ -118,29 +118,29 @@ class QueryCallback_2 QueryCallback_2() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) { } //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery - void SetFutureResult(ACE_Future<Result> value) + void SetFutureResult(std::future<Result> value) { - _result = value; + _result = std::move(value); } - ACE_Future<Result> GetFutureResult() + std::future<Result>& GetFutureResult() { return _result; } int IsReady() { - return _result.ready(); + return _result.valid() && _result.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } void GetResult(Result& res) { - _result.get(res); + res = _result.get(); } void FreeResult() { - _result.cancel(); + // Nothing to do here, the constructor of std::future will take care of the cleanup } void SetFirstParam(ParamType1 value) @@ -197,10 +197,13 @@ class QueryCallback_2 } private: - ACE_Future<Result> _result; + std::future<Result> _result; ParamType1 _param_1; ParamType2 _param_2; uint8 _stage; + + QueryCallback_2(QueryCallback_2 const& right) = delete; + QueryCallback_2& operator=(QueryCallback_2 const& right) = delete; }; -#endif
\ No newline at end of file +#endif diff --git a/src/server/shared/Threading/DelayExecutor.cpp b/src/server/shared/Threading/DelayExecutor.cpp deleted file mode 100644 index ba8a19429b2..00000000000 --- a/src/server/shared/Threading/DelayExecutor.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include <ace/Singleton.h> -#include <ace/Thread_Mutex.h> -#include <ace/Log_Msg.h> - -#include "DelayExecutor.h" - -DelayExecutor* DelayExecutor::instance() -{ - return ACE_Singleton<DelayExecutor, ACE_Thread_Mutex>::instance(); -} - -DelayExecutor::DelayExecutor() - : pre_svc_hook_(0), post_svc_hook_(0), activated_(false) { } - -DelayExecutor::~DelayExecutor() -{ - if (pre_svc_hook_) - delete pre_svc_hook_; - - if (post_svc_hook_) - delete post_svc_hook_; - - deactivate(); -} - -int DelayExecutor::deactivate() -{ - if (!activated()) - return -1; - - activated(false); - queue_.queue()->deactivate(); - wait(); - - return 0; -} - -int DelayExecutor::svc() -{ - if (pre_svc_hook_) - pre_svc_hook_->call(); - - for (;;) - { - ACE_Method_Request* rq = queue_.dequeue(); - - if (!rq) - break; - - rq->call(); - delete rq; - } - - if (post_svc_hook_) - post_svc_hook_->call(); - - return 0; -} - -int DelayExecutor::start(int num_threads, ACE_Method_Request* pre_svc_hook, ACE_Method_Request* post_svc_hook) -{ - if (activated()) - return -1; - - if (num_threads < 1) - return -1; - - if (pre_svc_hook_) - delete pre_svc_hook_; - - if (post_svc_hook_) - delete post_svc_hook_; - - pre_svc_hook_ = pre_svc_hook; - post_svc_hook_ = post_svc_hook; - - queue_.queue()->activate(); - - if (ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, num_threads) == -1) - return -1; - - activated(true); - - return true; -} - -int DelayExecutor::execute(ACE_Method_Request* new_req) -{ - if (new_req == NULL) - return -1; - - if (queue_.enqueue(new_req, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) - { - delete new_req; - ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%t) %p\n"), ACE_TEXT("DelayExecutor::execute enqueue")), -1); - } - - return 0; -} - -bool DelayExecutor::activated() -{ - return activated_; -} - -void DelayExecutor::activated(bool s) -{ - activated_ = s; -} diff --git a/src/server/shared/Threading/DelayExecutor.h b/src/server/shared/Threading/DelayExecutor.h deleted file mode 100644 index 5eaaacdb98b..00000000000 --- a/src/server/shared/Threading/DelayExecutor.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _M_DELAY_EXECUTOR_H -#define _M_DELAY_EXECUTOR_H - -#include <ace/Task.h> -#include <ace/Activation_Queue.h> -#include <ace/Method_Request.h> - -class DelayExecutor : protected ACE_Task_Base -{ - public: - - DelayExecutor(); - virtual ~DelayExecutor(); - - static DelayExecutor* instance(); - - int execute(ACE_Method_Request* new_req); - - int start(int num_threads = 1, ACE_Method_Request* pre_svc_hook = NULL, ACE_Method_Request* post_svc_hook = NULL); - - int deactivate(); - - bool activated(); - - virtual int svc(); - - private: - - ACE_Activation_Queue queue_; - ACE_Method_Request* pre_svc_hook_; - ACE_Method_Request* post_svc_hook_; - bool activated_; - - void activated(bool s); -}; - -#endif // _M_DELAY_EXECUTOR_H diff --git a/src/server/shared/Threading/LockedQueue.h b/src/server/shared/Threading/LockedQueue.h index d356d01606f..bbd60cb7760 100644 --- a/src/server/shared/Threading/LockedQueue.h +++ b/src/server/shared/Threading/LockedQueue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,140 +19,126 @@ #ifndef LOCKEDQUEUE_H #define LOCKEDQUEUE_H -#include <ace/Guard_T.h> -#include <ace/Thread_Mutex.h> #include <deque> -#include <assert.h> -#include "Debugging/Errors.h" +#include <mutex> -namespace ACE_Based +template <class T, typename StorageType = std::deque<T> > +class LockedQueue { - template <class T, class LockType, typename StorageType=std::deque<T> > - class LockedQueue + //! Lock access to the queue. + std::mutex _lock; + + //! Storage backing the queue. + StorageType _queue; + + //! Cancellation flag. + volatile bool _canceled; + +public: + + //! Create a LockedQueue. + LockedQueue() + : _canceled(false) { - //! Lock access to the queue. - LockType _lock; + } - //! Storage backing the queue. - StorageType _queue; + //! Destroy a LockedQueue. + virtual ~LockedQueue() + { + } - //! Cancellation flag. - volatile bool _canceled; + //! Adds an item to the queue. + void add(const T& item) + { + lock(); + + _queue.push_back(item); - public: + unlock(); + } + + //! Gets the next result in the queue, if any. + bool next(T& result) + { + std::lock_guard<std::mutex> lock(_lock); - //! Create a LockedQueue. - LockedQueue() - : _canceled(false) - { - } + if (_queue.empty()) + return false; - //! Destroy a LockedQueue. - virtual ~LockedQueue() - { - } - - //! Adds an item to the queue. - void add(const T& item) - { - lock(); - - //ASSERT(!this->_canceled); - // throw Cancellation_Exception(); - - _queue.push_back(item); - - unlock(); - } - - //! Gets the next result in the queue, if any. - bool next(T& result) - { - // ACE_Guard<LockType> g(this->_lock); - ACE_GUARD_RETURN (LockType, g, this->_lock, false); - - if (_queue.empty()) - return false; - - //ASSERT (!_queue.empty() || !this->_canceled); - // throw Cancellation_Exception(); - result = _queue.front(); - _queue.pop_front(); - - return true; - } - - template<class Checker> - bool next(T& result, Checker& check) - { - ACE_Guard<LockType> g(this->_lock); - - if (_queue.empty()) - return false; - - result = _queue.front(); - if (!check.Process(result)) - return false; - - _queue.pop_front(); - return true; - } - - //! Peeks at the top of the queue. Check if the queue is empty before calling! Remember to unlock after use if autoUnlock == false. - T& peek(bool autoUnlock = false) - { - lock(); - - T& result = _queue.front(); - - if (autoUnlock) - unlock(); - - return result; - } - - //! Cancels the queue. - void cancel() - { - lock(); - - _canceled = true; - - unlock(); - } - - //! Checks if the queue is cancelled. - bool cancelled() - { - ACE_Guard<LockType> g(this->_lock); - return _canceled; - } - - //! Locks the queue for access. - void lock() - { - this->_lock.acquire(); - } - - //! Unlocks the queue. - void unlock() - { - this->_lock.release(); - } - - ///! Calls pop_front of the queue - void pop_front() - { - ACE_GUARD (LockType, g, this->_lock); - _queue.pop_front(); - } - - ///! Checks if we're empty or not with locks held - bool empty() - { - ACE_GUARD_RETURN (LockType, g, this->_lock, false); - return _queue.empty(); - } - }; -} + result = _queue.front(); + _queue.pop_front(); + + return true; + } + + template<class Checker> + bool next(T& result, Checker& check) + { + std::lock_guard<std::mutex> lock(_lock); + + if (_queue.empty()) + return false; + + result = _queue.front(); + if (!check.Process(result)) + return false; + + _queue.pop_front(); + return true; + } + + //! Peeks at the top of the queue. Check if the queue is empty before calling! Remember to unlock after use if autoUnlock == false. + T& peek(bool autoUnlock = false) + { + lock(); + + T& result = _queue.front(); + + if (autoUnlock) + unlock(); + + return result; + } + + //! Cancels the queue. + void cancel() + { + std::lock_guard<std::mutex> lock(_lock); + + _canceled = true; + } + + //! Checks if the queue is cancelled. + bool cancelled() + { + std::lock_guard<std::mutex> lock(_lock); + return _canceled; + } + + //! Locks the queue for access. + void lock() + { + this->_lock.lock(); + } + + //! Unlocks the queue. + void unlock() + { + this->_lock.unlock(); + } + + ///! Calls pop_front of the queue + void pop_front() + { + std::lock_guard<std::mutex> lock(_lock); + _queue.pop_front(); + } + + ///! Checks if we're empty or not with locks held + bool empty() + { + std::lock_guard<std::mutex> lock(_lock); + return _queue.empty(); + } +}; #endif diff --git a/src/server/shared/Threading/ProcessPriority.h b/src/server/shared/Threading/ProcessPriority.h new file mode 100644 index 00000000000..23238c94ace --- /dev/null +++ b/src/server/shared/Threading/ProcessPriority.h @@ -0,0 +1,105 @@ +/* +* 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 _PROCESSPRIO_H +#define _PROCESSPRIO_H + +#include "Configuration/Config.h" + +#ifdef __linux__ +#include <sched.h> +#include <sys/resource.h> +#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 +#endif + +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 + uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0); + bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false); + +#ifdef _WIN32 // Windows + + HANDLE hProcess = GetCurrentProcess(); + if (affinity > 0) + { + ULONG_PTR appAff; + ULONG_PTR sysAff; + + if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) + { + // remove non accessible processors + ULONG_PTR currentAffinity = affinity & appAff; + + if (!currentAffinity) + TC_LOG_ERROR(logChannel, "Processors marked in UseProcessors bitmask (hex) %x are not accessible. Accessible processors bitmask (hex): %x", affinity, appAff); + else if (SetProcessAffinityMask(hProcess, currentAffinity)) + TC_LOG_INFO(logChannel, "Using processors (bitmask, hex): %x", currentAffinity); + else + TC_LOG_ERROR(logChannel, "Can't set used processors (hex): %x", currentAffinity); + } + } + + if (highPriority) + { + if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) + TC_LOG_INFO(logChannel, "Process priority class set to HIGH"); + else + TC_LOG_ERROR(logChannel, "Can't set process priority class."); + } + +#else // Linux + + if (affinity > 0) + { + cpu_set_t mask; + CPU_ZERO(&mask); + + for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) + if (affinity & (1 << i)) + CPU_SET(i, &mask); + + if (sched_setaffinity(0, sizeof(mask), &mask)) + TC_LOG_ERROR(logChannel, "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); + else + { + CPU_ZERO(&mask); + sched_getaffinity(0, sizeof(mask), &mask); + TC_LOG_INFO(logChannel, "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); + } + } + + if (highPriority) + { + if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) + TC_LOG_ERROR(logChannel, "Can't set process priority class, error: %s", strerror(errno)); + else + TC_LOG_INFO(logChannel, "Process priority class set to %i", getpriority(PRIO_PROCESS, 0)); + } + +#endif +#endif +} + +#endif diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h new file mode 100644 index 00000000000..a76b8b0b5c0 --- /dev/null +++ b/src/server/shared/Threading/ProducerConsumerQueue.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 _PCQ_H +#define _PCQ_H + +#include <condition_variable> +#include <mutex> +#include <queue> +#include <atomic> +#include <type_traits> + +template <typename T> +class ProducerConsumerQueue +{ +private: + std::mutex _queueLock; + std::queue<T> _queue; + std::condition_variable _condition; + std::atomic<bool> _shutdown; + +public: + + ProducerConsumerQueue<T>() : _shutdown(false) { } + + void Push(const T& value) + { + std::lock_guard<std::mutex> lock(_queueLock); + _queue.push(std::move(value)); + + _condition.notify_one(); + } + + bool Empty() + { + std::lock_guard<std::mutex> lock(_queueLock); + + return _queue.empty(); + } + + bool Pop(T& value) + { + std::lock_guard<std::mutex> lock(_queueLock); + + if (_queue.empty() || _shutdown) + return false; + + value = _queue.front(); + + _queue.pop(); + + return true; + } + + void WaitAndPop(T& value) + { + std::unique_lock<std::mutex> lock(_queueLock); + + _condition.wait(lock, [this]() { return !_queue.empty() || _shutdown; }); + + if (_queue.empty() || _shutdown) + return; + + value = _queue.front(); + + _queue.pop(); + } + + void Cancel() + { + _queueLock.lock(); + + while (!_queue.empty()) + { + T& value = _queue.front(); + + DeleteQueuedObject(value); + + _queue.pop(); + } + + _shutdown = true; + + _queueLock.unlock(); + + _condition.notify_all(); + } + +private: + template<typename E = T> + typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; } + + template<typename E = T> + typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { } +}; + +#endif diff --git a/src/server/shared/Threading/Threading.cpp b/src/server/shared/Threading/Threading.cpp deleted file mode 100644 index 1ed29d5106a..00000000000 --- a/src/server/shared/Threading/Threading.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> - * - * 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/>. - */ - -#include "Threading.h" -#include "Errors.h" -#include <ace/OS_NS_unistd.h> -#include <ace/Sched_Params.h> -#include <vector> - -using namespace ACE_Based; - -ThreadPriority::ThreadPriority() -{ - for (int i = Idle; i < MAXPRIORITYNUM; ++i) - m_priority[i] = ACE_THR_PRI_OTHER_DEF; - - m_priority[Idle] = ACE_Sched_Params::priority_min(ACE_SCHED_OTHER); - m_priority[Realtime] = ACE_Sched_Params::priority_max(ACE_SCHED_OTHER); - - std::vector<int> _tmp; - - ACE_Sched_Params::Policy _policy = ACE_SCHED_OTHER; - ACE_Sched_Priority_Iterator pr_iter(_policy); - - while (pr_iter.more()) - { - _tmp.push_back(pr_iter.priority()); - pr_iter.next(); - } - - ASSERT (!_tmp.empty()); - - if (_tmp.size() >= MAXPRIORITYNUM) - { - const size_t max_pos = _tmp.size(); - size_t min_pos = 1; - size_t norm_pos = 0; - for (size_t i = 0; i < max_pos; ++i) - { - if (_tmp[i] == ACE_THR_PRI_OTHER_DEF) - { - norm_pos = i + 1; - break; - } - } - - // since we have only 7(seven) values in enum Priority - // and 3 we know already (Idle, Normal, Realtime) so - // we need to split each list [Idle...Normal] and [Normal...Realtime] - // into pieces - const size_t _divider = 4; - size_t _div = (norm_pos - min_pos) / _divider; - if (_div == 0) - _div = 1; - - min_pos = (norm_pos - 1); - - m_priority[Low] = _tmp[min_pos -= _div]; - m_priority[Lowest] = _tmp[min_pos -= _div ]; - - _div = (max_pos - norm_pos) / _divider; - if (_div == 0) - _div = 1; - - min_pos = norm_pos - 1; - - m_priority[High] = _tmp[min_pos += _div]; - m_priority[Highest] = _tmp[min_pos += _div]; - } -} - -int ThreadPriority::getPriority(Priority p) const -{ - if (p < Idle) - p = Idle; - - if (p > Realtime) - p = Realtime; - - return m_priority[p]; -} - -#define THREADFLAG (THR_NEW_LWP | THR_SCHED_DEFAULT| THR_JOINABLE) - -Thread::Thread(): m_iThreadId(0), m_hThreadHandle(0), m_task(0) -{ - -} - -Thread::Thread(Runnable* instance): m_iThreadId(0), m_hThreadHandle(0), m_task(instance) -{ - // register reference to m_task to prevent it deeltion until destructor - if (m_task) - m_task->incReference(); - - bool _start = start(); - ASSERT (_start); -} - -Thread::~Thread() -{ - //Wait(); - - // deleted runnable object (if no other references) - if (m_task) - m_task->decReference(); -} - -//initialize Thread's class static member -Thread::ThreadStorage Thread::m_ThreadStorage; -ThreadPriority Thread::m_TpEnum; - -bool Thread::start() -{ - if (m_task == 0 || m_iThreadId != 0) - return false; - - // incRef before spawing the thread, otherwise Thread::ThreadTask() might call decRef and delete m_task - m_task->incReference(); - - bool res = (ACE_Thread::spawn(&Thread::ThreadTask, (void*)m_task, THREADFLAG, &m_iThreadId, &m_hThreadHandle) == 0); - - if (!res) - m_task->decReference(); - - return res; -} - -bool Thread::wait() -{ - if (!m_hThreadHandle || !m_task) - return false; - - ACE_THR_FUNC_RETURN _value = ACE_THR_FUNC_RETURN(-1); - int _res = ACE_Thread::join(m_hThreadHandle, &_value); - - m_iThreadId = 0; - m_hThreadHandle = 0; - - return (_res == 0); -} - -void Thread::destroy() -{ - if (!m_iThreadId || !m_task) - return; - - if (ACE_Thread::kill(m_iThreadId, -1) != 0) - return; - - m_iThreadId = 0; - m_hThreadHandle = 0; - - // reference set at ACE_Thread::spawn - m_task->decReference(); -} - -void Thread::suspend() -{ - ACE_Thread::suspend(m_hThreadHandle); -} - -void Thread::resume() -{ - ACE_Thread::resume(m_hThreadHandle); -} - -ACE_THR_FUNC_RETURN Thread::ThreadTask(void * param) -{ - Runnable* _task = (Runnable*)param; - _task->run(); - - // task execution complete, free referecne added at - _task->decReference(); - - return (ACE_THR_FUNC_RETURN)0; -} - -ACE_thread_t Thread::currentId() -{ - return ACE_Thread::self(); -} - -ACE_hthread_t Thread::currentHandle() -{ - ACE_hthread_t _handle; - ACE_Thread::self(_handle); - - return _handle; -} - -Thread * Thread::current() -{ - Thread * _thread = m_ThreadStorage.ts_object(); - if (!_thread) - { - _thread = new Thread(); - _thread->m_iThreadId = Thread::currentId(); - _thread->m_hThreadHandle = Thread::currentHandle(); - - Thread * _oldValue = m_ThreadStorage.ts_object(_thread); - if (_oldValue) - delete _oldValue; - } - - return _thread; -} - -void Thread::setPriority(Priority type) -{ - int _priority = m_TpEnum.getPriority(type); - int _ok = ACE_Thread::setprio(m_hThreadHandle, _priority); - //remove this ASSERT in case you don't want to know is thread priority change was successful or not - ASSERT (_ok == 0); -} - -void Thread::Sleep(unsigned long msecs) -{ - ACE_OS::sleep(ACE_Time_Value(0, 1000 * msecs)); -} diff --git a/src/server/shared/Threading/Threading.h b/src/server/shared/Threading/Threading.h deleted file mode 100644 index 00be82c6555..00000000000 --- a/src/server/shared/Threading/Threading.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> - * - * 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 THREADING_H -#define THREADING_H - -#include <ace/Thread.h> -#include <ace/TSS_T.h> -#include <ace/Atomic_Op.h> -#include <assert.h> - -namespace ACE_Based -{ - - class Runnable - { - public: - virtual ~Runnable() { } - virtual void run() = 0; - - void incReference() { ++m_refs; } - void decReference() - { - if (!--m_refs) - delete this; - } - private: - ACE_Atomic_Op<ACE_Thread_Mutex, long> m_refs; - }; - - enum Priority - { - Idle, - Lowest, - Low, - Normal, - High, - Highest, - Realtime - }; - -#define MAXPRIORITYNUM (Realtime + 1) - - class ThreadPriority - { - public: - ThreadPriority(); - int getPriority(Priority p) const; - - private: - int m_priority[MAXPRIORITYNUM]; - }; - - class Thread - { - public: - Thread(); - explicit Thread(Runnable* instance); - ~Thread(); - - bool start(); - bool wait(); - void destroy(); - - void suspend(); - void resume(); - - void setPriority(Priority type); - - static void Sleep(unsigned long msecs); - static ACE_thread_t currentId(); - static ACE_hthread_t currentHandle(); - static Thread * current(); - - private: - Thread(const Thread&); - Thread& operator=(const Thread&); - - static ACE_THR_FUNC_RETURN ThreadTask(void * param); - - ACE_thread_t m_iThreadId; - ACE_hthread_t m_hThreadHandle; - Runnable* m_task; - - typedef ACE_TSS<Thread> ThreadStorage; - //global object - container for Thread class representation of every thread - static ThreadStorage m_ThreadStorage; - //use this object to determine current OS thread priority values mapped to enum Priority{ } - static ThreadPriority m_TpEnum; - }; - -} -#endif diff --git a/src/server/shared/Utilities/ByteConverter.h b/src/server/shared/Utilities/ByteConverter.h index b114f8915a4..8eebb05bb13 100644 --- a/src/server/shared/Utilities/ByteConverter.h +++ b/src/server/shared/Utilities/ByteConverter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -47,9 +47,13 @@ namespace ByteConverter #if TRINITY_ENDIAN == TRINITY_BIGENDIAN template<typename T> inline void EndianConvert(T& val) { ByteConverter::apply<T>(&val); } template<typename T> inline void EndianConvertReverse(T&) { } +template<typename T> inline void EndianConvertPtr(void* val) { ByteConverter::apply<T>(val); } +template<typename T> inline void EndianConvertPtrReverse(void*) { } #else template<typename T> inline void EndianConvert(T&) { } template<typename T> inline void EndianConvertReverse(T& val) { ByteConverter::apply<T>(&val); } +template<typename T> inline void EndianConvertPtr(void*) { } +template<typename T> inline void EndianConvertPtrReverse(void* val) { ByteConverter::apply<T>(val); } #endif template<typename T> void EndianConvert(T*); // will generate link error diff --git a/src/server/shared/Utilities/EventProcessor.cpp b/src/server/shared/Utilities/EventProcessor.cpp index aeb67869882..fcae42cf27d 100644 --- a/src/server/shared/Utilities/EventProcessor.cpp +++ b/src/server/shared/Utilities/EventProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Utilities/EventProcessor.h b/src/server/shared/Utilities/EventProcessor.h index 8abf0f09dfe..10ae6aa954c 100644 --- a/src/server/shared/Utilities/EventProcessor.h +++ b/src/server/shared/Utilities/EventProcessor.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -28,7 +28,12 @@ class BasicEvent { public: - BasicEvent() { to_Abort = false; } + BasicEvent() + { + to_Abort = false; + m_addTime = 0; + m_execTime = 0; + } virtual ~BasicEvent() { } // override destructor to perform some actions on event removal // this method executes when the event is triggered diff --git a/src/server/shared/Utilities/ServiceWin32.cpp b/src/server/shared/Utilities/ServiceWin32.cpp index c50aca87c09..ecf403423f7 100644 --- a/src/server/shared/Utilities/ServiceWin32.cpp +++ b/src/server/shared/Utilities/ServiceWin32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com> * * This program is free software; you can redistribute it and/or modify it @@ -24,11 +24,6 @@ #include <windows.h> #include <winsvc.h> -// stupid ACE define -#ifdef main -#undef main -#endif //main - #if !defined(WINADVAPI) #if !defined(_ADVAPI32_) #define WINADVAPI DECLSPEC_IMPORT @@ -60,7 +55,7 @@ bool WinServiceInstall() if (GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0) { SC_HANDLE service; - std::strcat(path, " --service"); + std::strcat(path, " --service run"); service = CreateService(serviceControlManager, serviceName, // name of service serviceLongName, // service name to display @@ -119,6 +114,8 @@ bool WinServiceInstall() } CloseServiceHandle(serviceControlManager); } + + printf("Service installed\n"); return true; } @@ -143,6 +140,8 @@ bool WinServiceUninstall() CloseServiceHandle(serviceControlManager); } + + printf("Service uninstalled\n"); return true; } diff --git a/src/server/shared/Utilities/ServiceWin32.h b/src/server/shared/Utilities/ServiceWin32.h index bc2917d4bcb..52223ccc7f6 100644 --- a/src/server/shared/Utilities/ServiceWin32.h +++ b/src/server/shared/Utilities/ServiceWin32.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com> * * This program is free software; you can redistribute it and/or modify it diff --git a/src/server/shared/Utilities/SignalHandler.h b/src/server/shared/Utilities/SignalHandler.h deleted file mode 100644 index 51bb9a4b27b..00000000000 --- a/src/server/shared/Utilities/SignalHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * 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 __SIGNAL_HANDLER_H__ -#define __SIGNAL_HANDLER_H__ - -#include <ace/Event_Handler.h> - -namespace Trinity -{ - -/// Handle termination signals -class SignalHandler : public ACE_Event_Handler -{ - public: - int handle_signal(int SigNum, siginfo_t* = NULL, ucontext_t* = NULL) - { - HandleSignal(SigNum); - return 0; - } - virtual void HandleSignal(int /*SigNum*/) { }; -}; - -} - -#endif /* __SIGNAL_HANDLER_H__ */ diff --git a/src/server/shared/Utilities/Timer.h b/src/server/shared/Utilities/Timer.h index b0b395865b4..0e2d6ddbff5 100644 --- a/src/server/shared/Utilities/Timer.h +++ b/src/server/shared/Utilities/Timer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -19,13 +19,15 @@ #ifndef TRINITY_TIMER_H #define TRINITY_TIMER_H -#include "ace/OS_NS_sys_time.h" -#include "Common.h" +#include <chrono> + +using namespace std::chrono; inline uint32 getMSTime() { - static const ACE_Time_Value ApplicationStartTime = ACE_OS::gettimeofday(); - return (ACE_OS::gettimeofday() - ApplicationStartTime).msec(); + static const system_clock::time_point ApplicationStartTime = system_clock::now(); + + return uint32(duration_cast<milliseconds>(system_clock::now() - ApplicationStartTime).count()); } inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) @@ -44,158 +46,158 @@ inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime) struct IntervalTimer { - public: - - IntervalTimer() - : _interval(0), _current(0) - { - } - - void Update(time_t diff) - { - _current += diff; - if (_current < 0) - _current = 0; - } - - bool Passed() - { - return _current >= _interval; - } - - void Reset() - { - if (_current >= _interval) - _current %= _interval; - } - - void SetCurrent(time_t current) - { - _current = current; - } - - void SetInterval(time_t interval) - { - _interval = interval; - } - - time_t GetInterval() const - { - return _interval; - } - - time_t GetCurrent() const - { - return _current; - } - - private: - - time_t _interval; - time_t _current; +public: + + IntervalTimer() + : _interval(0), _current(0) + { + } + + void Update(time_t diff) + { + _current += diff; + if (_current < 0) + _current = 0; + } + + bool Passed() + { + return _current >= _interval; + } + + void Reset() + { + if (_current >= _interval) + _current %= _interval; + } + + void SetCurrent(time_t current) + { + _current = current; + } + + void SetInterval(time_t interval) + { + _interval = interval; + } + + time_t GetInterval() const + { + return _interval; + } + + time_t GetCurrent() const + { + return _current; + } + +private: + + time_t _interval; + time_t _current; }; struct TimeTracker { - public: +public: - TimeTracker(time_t expiry) - : i_expiryTime(expiry) - { - } + TimeTracker(time_t expiry) + : i_expiryTime(expiry) + { + } - void Update(time_t diff) - { - i_expiryTime -= diff; - } + void Update(time_t diff) + { + i_expiryTime -= diff; + } - bool Passed() const - { - return i_expiryTime <= 0; - } + bool Passed() const + { + return i_expiryTime <= 0; + } - void Reset(time_t interval) - { - i_expiryTime = interval; - } + void Reset(time_t interval) + { + i_expiryTime = interval; + } - time_t GetExpiry() const - { - return i_expiryTime; - } + time_t GetExpiry() const + { + return i_expiryTime; + } - private: +private: - time_t i_expiryTime; + time_t i_expiryTime; }; struct TimeTrackerSmall { - public: +public: - TimeTrackerSmall(uint32 expiry = 0) - : i_expiryTime(expiry) - { - } + TimeTrackerSmall(uint32 expiry = 0) + : i_expiryTime(expiry) + { + } - void Update(int32 diff) - { - i_expiryTime -= diff; - } + void Update(int32 diff) + { + i_expiryTime -= diff; + } - bool Passed() const - { - return i_expiryTime <= 0; - } + bool Passed() const + { + return i_expiryTime <= 0; + } - void Reset(uint32 interval) - { - i_expiryTime = interval; - } + void Reset(uint32 interval) + { + i_expiryTime = interval; + } - int32 GetExpiry() const - { - return i_expiryTime; - } + int32 GetExpiry() const + { + return i_expiryTime; + } - private: +private: - int32 i_expiryTime; + int32 i_expiryTime; }; struct PeriodicTimer { - public: +public: - PeriodicTimer(int32 period, int32 start_time) - : i_period(period), i_expireTime(start_time) - { - } + PeriodicTimer(int32 period, int32 start_time) + : i_period(period), i_expireTime(start_time) + { + } - bool Update(const uint32 diff) - { - if ((i_expireTime -= diff) > 0) - return false; + bool Update(const uint32 diff) + { + if ((i_expireTime -= diff) > 0) + return false; - i_expireTime += i_period > int32(diff) ? i_period : diff; - return true; - } + i_expireTime += i_period > int32(diff) ? i_period : diff; + return true; + } - void SetPeriodic(int32 period, int32 start_time) - { - i_expireTime = start_time; - i_period = period; - } + void SetPeriodic(int32 period, int32 start_time) + { + i_expireTime = start_time; + i_period = period; + } - // Tracker interface - void TUpdate(int32 diff) { i_expireTime -= diff; } - bool TPassed() const { return i_expireTime <= 0; } - void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; } + // Tracker interface + void TUpdate(int32 diff) { i_expireTime -= diff; } + bool TPassed() const { return i_expireTime <= 0; } + void TReset(int32 diff, int32 period) { i_expireTime += period > diff ? period : diff; } - private: +private: - int32 i_period; - int32 i_expireTime; + int32 i_period; + int32 i_expireTime; }; #endif diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 48012b6eea8..f2c02510ed4 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -18,45 +18,65 @@ #include "Util.h" #include "Common.h" +#include "CompilerDefs.h" #include "utf8.h" #include "SFMT.h" #include "Errors.h" // for ASSERT -#include <ace/TSS_T.h> +#include <stdarg.h> +#include <boost/thread/tss.hpp> -typedef ACE_TSS<SFMTRand> SFMTRandTSS; -static SFMTRandTSS sfmtRand; +#if COMPILER == COMPILER_GNU + #include <sys/socket.h> + #include <netinet/in.h> + #include <arpa/inet.h> +#endif + +static boost::thread_specific_ptr<SFMTRand> sfmtRand; + +static SFMTRand* GetRng() +{ + SFMTRand* rand = sfmtRand.get(); + + if (!rand) + { + rand = new SFMTRand(); + sfmtRand.reset(rand); + } + + return rand; +} int32 irand(int32 min, int32 max) { ASSERT(max >= min); - return int32(sfmtRand->IRandom(min, max)); + return int32(GetRng()->IRandom(min, max)); } uint32 urand(uint32 min, uint32 max) { ASSERT(max >= min); - return sfmtRand->URandom(min, max); + return GetRng()->URandom(min, max); } float frand(float min, float max) { ASSERT(max >= min); - return float(sfmtRand->Random() * (max - min) + min); + return float(GetRng()->Random() * (max - min) + min); } -int32 rand32() +uint32 rand32() { - return int32(sfmtRand->BRandom()); + return GetRng()->BRandom(); } -double rand_norm(void) +double rand_norm() { - return sfmtRand->Random(); + return GetRng()->Random(); } -double rand_chance(void) +double rand_chance() { - return sfmtRand->Random() * 100.0; + return GetRng()->Random() * 100.0; } Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve) @@ -127,6 +147,14 @@ void stripLineInvisibleChars(std::string &str) } +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) +struct tm* localtime_r(const time_t* time, struct tm *result) +{ + localtime_s(result, time); + return result; +} +#endif + std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly) { uint64 secs = timeInSecs % MINUTE; @@ -216,7 +244,7 @@ uint32 TimeStringToSecs(const std::string& timestring) std::string TimeToTimestampStr(time_t t) { tm aTm; - ACE_OS::localtime_r(&t, &aTm); + localtime_r(&t, &aTm); // YYYY year // MM month (2 digits 01-12) // DD day (2 digits 01-31) @@ -239,21 +267,6 @@ bool IsIPAddress(char const* ipaddress) return inet_addr(ipaddress) != INADDR_NONE; } -std::string GetAddressString(ACE_INET_Addr const& addr) -{ - char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16]; - addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16); - return buf; -} - -bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask) -{ - uint32 mask = subnetMask.get_ip_address(); - if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask)) - return true; - return false; -} - /// create PID file uint32 CreatePIDFile(const std::string& filename) { @@ -510,6 +523,9 @@ void vutf8printf(FILE* out, const char *str, va_list* ap) wchar_t wtemp_buf[32*1024]; size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap); + //vsnprintf returns -1 if the buffer is too small + if (temp_len == size_t(-1)) + temp_len = 32*1024-1; size_t wtemp_len = 32*1024-1; Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len); @@ -544,3 +560,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 30a6b27f186..20c17b14023 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #include <string> #include <vector> #include <list> -#include <ace/INET_Addr.h> +#include <map> // Searcher for map of structs template<typename T, class S> struct Finder @@ -70,34 +70,29 @@ void stripLineInvisibleChars(std::string &src); int32 MoneyStringToMoney(const std::string& moneyString); +struct tm* localtime_r(const time_t* time, struct tm *result); + std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false); uint32 TimeStringToSecs(const std::string& timestring); std::string TimeToTimestampStr(time_t t); -/* Return a random number in the range min..max; (max-min) must be smaller than 32768. */ +/* Return a random number in the range min..max. */ int32 irand(int32 min, int32 max); -/* Return a random number in the range min..max (inclusive). For reliable results, the difference -* between max and min should be less than RAND32_MAX. */ +/* Return a random number in the range min..max (inclusive). */ uint32 urand(uint32 min, uint32 max); -/* Return a random number in the range 0 .. RAND32_MAX. */ -int32 rand32(); +/* Return a random number in the range 0 .. UINT32_MAX. */ +uint32 rand32(); /* Return a random number in the range min..max */ float frand(float min, float max); -/* Return a random double from 0.0 to 1.0 (exclusive). Floats support only 7 valid decimal digits. - * A double supports up to 15 valid decimal digits and is used internally (RAND32_MAX has 10 digits). - * With an FPU, there is usually no difference in performance between float and double. -*/ -double rand_norm(void); +/* Return a random double from 0.0 to 1.0 (exclusive). */ +double rand_norm(); -/* Return a random double from 0.0 to 99.9999999999999. Floats support only 7 valid decimal digits. - * A double supports up to 15 valid decimal digits and is used internally (RAND32_MAX has 10 digits). - * With an FPU, there is usually no difference in performance between float and double. -*/ -double rand_chance(void); +/* Return a random double from 0.0 to 100.0 (exclusive). */ +double rand_chance(); /* Return true if a random roll fits in the specified chance (range 0-100). */ inline bool roll_chance_f(float chance) @@ -346,20 +341,9 @@ void vutf8printf(FILE* out, const char *str, va_list* ap); bool IsIPAddress(char const* ipaddress); -/// Checks if address belongs to the a network with specified submask -bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask); - -/// Transforms ACE_INET_Addr address into string format "dotted_ip:port" -std::string GetAddressString(ACE_INET_Addr const& addr); - uint32 CreatePIDFile(const std::string& filename); std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); -#endif - -//handler for operations on large flags -#ifndef _FLAG96 -#define _FLAG96 // simple class for not-modifyable list template <typename T> @@ -406,13 +390,6 @@ public: part[2] = p3; } - flag96(uint64 p1, uint32 p2) - { - part[0] = (uint32)(p1 & UI64LIT(0x00000000FFFFFFFF)); - part[1] = (uint32)((p1 >> 32) & UI64LIT(0x00000000FFFFFFFF)); - part[2] = p2; - } - inline bool IsEqual(uint32 p1 = 0, uint32 p2 = 0, uint32 p3 = 0) const { return (part[0] == p1 && part[1] == p2 && part[2] == p3); @@ -565,4 +542,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 = uint8(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 |= uint8(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 &= uint8(~(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 |
