diff options
Diffstat (limited to 'src')
175 files changed, 3145 insertions, 6067 deletions
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index 4391ac0450a..d6f0515a8e1 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -50,13 +50,13 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication ${CMAKE_SOURCE_DIR}/src/server/shared/Logging + ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Authentication ${CMAKE_CURRENT_SOURCE_DIR}/Realms ${CMAKE_CURRENT_SOURCE_DIR}/Server - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) @@ -79,7 +79,7 @@ target_link_libraries(authserver ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${ACE_LIBRARY} + ${Boost_LIBRARIES} ) if( WIN32 ) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 9f96d21e55e..701f65c0c14 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -24,28 +24,26 @@ * authentication server */ -#include <ace/Dev_Poll_Reactor.h> -#include <ace/TP_Reactor.h> -#include <ace/ACE.h> -#include <ace/Sig_Handler.h> +#include <cstdlib> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/program_options.hpp> +#include <iostream> #include <openssl/opensslv.h> #include <openssl/crypto.h> +#include "AsyncAcceptor.h" +#include "AuthSession.h" #include "Common.h" -#include "Database/DatabaseEnv.h" #include "Configuration/Config.h" +#include "Database/DatabaseEnv.h" #include "Log.h" +#include "ProcessPriority.h" +#include "RealmList.h" #include "SystemConfig.h" #include "Util.h" -#include "SignalHandler.h" -#include "RealmList.h" -#include "RealmAcceptor.h" -#ifdef __linux__ -#include <sched.h> -#include <sys/resource.h> -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif +using boost::asio::ip::tcp; +using namespace boost::program_options; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" @@ -53,77 +51,35 @@ bool StartDB(); void StopDB(); +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void KeepDatabaseAliveHandler(const boost::system::error_code& error); +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); -bool stopEvent = false; // Setting it to true stops the server - -LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database - -/// Handle authserver's termination signals -class AuthServerSignalHandler : public Trinity::SignalHandler -{ -public: - virtual void HandleSignal(int sigNum) - { - switch (sigNum) - { - case SIGINT: - case SIGTERM: - stopEvent = true; - break; - } - } -}; - -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - TC_LOG_INFO("server.authserver", "Usage: \n %s [<options>]\n" - " -c config_file use config_file as configuration file\n\r", - prog); -} +boost::asio::io_service _ioService; +boost::asio::deadline_timer _dbPingTimer(_ioService); +uint32 _dbPingInterval; +LoginDatabaseWorkerPool LoginDatabase; -/// Launch the auth server -extern int main(int argc, char** argv) +int main(int argc, char** argv) { - // Command line parsing to get the configuration file name - char const* configFile = _TRINITY_REALM_CONFIG; - int count = 1; - while (count < argc) - { - if (strcmp(argv[count], "-c") == 0) - { - if (++count >= argc) - { - printf("Runtime-Error: -c option requires an input argument\n"); - usage(argv[0]); - return 1; - } - else - configFile = argv[count]; - } - ++count; - } + std::string configFile = _TRINITY_REALM_CONFIG; + auto vm = GetConsoleArguments(argc, argv, configFile); + // exit if help is enabled + if (vm.count("help")) + return 0; if (!sConfigMgr->LoadInitial(configFile)) { - printf("Invalid or missing configuration file : %s\n", configFile); + printf("Invalid or missing configuration file : %s\n", configFile.c_str()); printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n"); return 1; } TC_LOG_INFO("server.authserver", "%s (authserver)", _FULLVERSION); TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n"); - TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile); - - TC_LOG_INFO("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); - -#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); -#else - ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); -#endif - - TC_LOG_DEBUG("server.authserver", "Max allowed open files is %d", ACE::max_handles()); + TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile.c_str()); + TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); // authserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); @@ -143,129 +99,39 @@ extern int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - if (sRealmList->size() == 0) + sRealmList.Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + + if (sRealmList.size() == 0) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); return 1; } - // Launch the listening network socket - RealmAcceptor acceptor; - - int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); - if (rmport < 0 || rmport > 0xFFFF) + // Start the listening port (acceptor) for auth connections + int32 port = sConfigMgr->GetIntDefault("RealmServerPort", 3724); + if (port < 0 || port > 0xFFFF) { TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)"); return 1; } + + std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port); - std::string bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - - ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str()); - - if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) - { - TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); - return 1; - } - - // Initialize the signal handlers - AuthServerSignalHandler SignalINT, SignalTERM; - - // Register authservers's signal handlers - ACE_Sig_Handler Handler; - Handler.register_handler(SIGINT, &SignalINT); - Handler.register_handler(SIGTERM, &SignalTERM); - -#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("server.authserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff); - else if (SetProcessAffinityMask(hProcess, currentAffinity)) - TC_LOG_INFO("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity); - else - TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); - } - } - - if (highPriority) - { - if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) - TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH"); - else - TC_LOG_ERROR("server.authserver", "Can't set authserver 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("server.authserver", "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("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); - } - } - - if (highPriority) - { - if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) - TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno)); - else - TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); - } - -#endif -#endif - - // maximum counter for next ping - uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); - uint32 loopCounter = 0; + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); + signals.async_wait(SignalHandler); - // Wait for termination signal - while (!stopEvent) - { - // dont move this outside the loop, the reactor will modify it - ACE_Time_Value interval(0, 100000); + // Set process priority according to configuration settings + SetProcessPriority("server.authserver"); - if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) - break; + // Enabled a timed callback for handling the database keep alive ping + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); - if ((++loopCounter) == numLoops) - { - loopCounter = 0; - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); - LoginDatabase.KeepAlive(); - } - } + // Start the io service worker loop + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -274,6 +140,7 @@ extern int main(int argc, char** argv) return 0; } + /// Initialize connection to the database bool StartDB() { @@ -318,3 +185,53 @@ void StopDB() LoginDatabase.Close(); MySQL::Library_End(); } + +void SignalHandler(const boost::system::error_code& error, int signalNumber) +{ + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + _ioService.stop(); + break; + } + } +} + +void KeepDatabaseAliveHandler(const boost::system::error_code& error) +{ + if (!error) + { + TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + LoginDatabase.KeepAlive(); + + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); + } +} + +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile) +{ + options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file") + ; + variables_map variablesMap; + try + { + store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap); + notify(variablesMap); + } + catch (std::exception& e) { + std::cerr << e.what() << "\n"; + } + + if (variablesMap.count("help")) { + std::cout << all << "\n"; + } + + return variablesMap; +} diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 5fc3b0a3416..ef757a656d5 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -1,6 +1,6 @@ +#include "Common.h" #include "Configuration/Config.h" #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "RealmSocket.h" -#include "Common.h" +#include "AuthSession.h" diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 4aeecfc0aaa..4dd2ab96dd9 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,22 +16,31 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <boost/asio/ip/tcp.hpp> #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +namespace boost { namespace asio { namespace ip { class address; } } } + +RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) { } +RealmList::~RealmList() +{ + delete _resolver; +} // Load the realm list from the database -void RealmList::Initialize(uint32 updateInterval) +void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _resolver = new boost::asio::ip::tcp::resolver(ioService); m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -42,12 +51,14 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.flag = flag; realm.timezone = timezone; realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = popu; + realm.populationLevel = population; // Append port to IP address. + realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; + realm.port = port; realm.gamebuild = build; } @@ -78,28 +89,62 @@ void RealmList::UpdateRealms(bool init) { do { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string externalAddress = fields[2].GetString(); - std::string localAddress = fields[3].GetString(); - std::string localSubmask = fields[4].GetString(); - uint16 port = fields[5].GetUInt16(); - uint8 icon = fields[6].GetUInt8(); - RealmFlags flag = RealmFlags(fields[7].GetUInt8()); - uint8 timezone = fields[8].GetUInt8(); - uint8 allowedSecurityLevel = fields[9].GetUInt8(); - float pop = fields[10].GetFloat(); - uint32 build = fields[11].GetUInt32(); - - ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); - ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); - ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); - - UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); - - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); + try + { + boost::asio::ip::tcp::resolver::iterator end; + + Field* fields = result->Fetch(); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(fields[2].GetString(), ""); + boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return; + } + + ip::address externalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(fields[3].GetString(), ""); + endPoint = _resolver->resolve(localAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return; + } + + ip::address localAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(fields[4].GetString(), ""); + endPoint = _resolver->resolve(localSubmaskQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return; + } + + ip::address localSubmask = (*endPoint).endpoint().address(); + + uint16 port = fields[5].GetUInt16(); + uint8 icon = fields[6].GetUInt8(); + RealmFlags flag = RealmFlags(fields[7].GetUInt8()); + uint8 timezone = fields[8].GetUInt8(); + uint8 allowedSecurityLevel = fields[9].GetUInt8(); + float pop = fields[10].GetFloat(); + uint32 build = fields[11].GetUInt32(); + + UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + + if (init) + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + } + catch (std::exception& ex) + { + TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + ASSERT(false); + } } while (result->NextRow()); } diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1d76c39e4f0..b1c77d5a4b5 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,30 +19,33 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include <ace/Singleton.h> -#include <ace/Null_Mutex.h> -#include <ace/INET_Addr.h> +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/io_service.hpp> #include "Common.h" +using namespace boost::asio; + enum RealmFlags { - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 + REALM_FLAG_NONE = 0x00, + REALM_FLAG_INVALID = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 }; // Storage object for a realm struct Realm { - ACE_INET_Addr ExternalAddress; - ACE_INET_Addr LocalAddress; - ACE_INET_Addr LocalSubnetMask; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 port; std::string name; uint8 icon; RealmFlags flag; @@ -59,10 +62,15 @@ class RealmList public: typedef std::map<std::string, Realm> RealmMap; - RealmList(); - ~RealmList() { } + static RealmList& instance() + { + static RealmList *instance = new RealmList(); + return *instance; + } + + ~RealmList(); - void Initialize(uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); void UpdateIfNeed(); @@ -73,13 +81,17 @@ public: uint32 size() const { return m_realms.size(); } private: - void UpdateRealms(bool init=false); - void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); + RealmList(); + + void UpdateRealms(bool init = false); + void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; + boost::asio::ip::tcp::resolver* _resolver; }; -#define sRealmList ACE_Singleton<RealmList, ACE_Null_Mutex>::instance() +#define sRealmList RealmList::instance() #endif diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSession.cpp index 4ddad3e6eb0..f518dc7593b 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -1,64 +1,57 @@ /* - * 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 - * 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 <algorithm> -#include <openssl/md5.h> - -#include "Common.h" -#include "Database/DatabaseEnv.h" +* 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 +* 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 <memory> +#include <boost/lexical_cast.hpp> +#include <boost/asio/write.hpp> +#include <AuthSession.h> +#include <Log.h> #include "ByteBuffer.h" -#include "Configuration/Config.h" -#include "Log.h" -#include "RealmList.h" -#include "AuthSocket.h" #include "AuthCodes.h" -#include "TOTP.h" +#include "Database/DatabaseEnv.h" #include "SHA1.h" #include "openssl/crypto.h" +#include "Configuration/Config.h" +#include "RealmList.h" -#define ChunkSize 2048 +using boost::asio::ip::tcp; enum eAuthCmd { - AUTH_LOGON_CHALLENGE = 0x00, - AUTH_LOGON_PROOF = 0x01, - AUTH_RECONNECT_CHALLENGE = 0x02, - AUTH_RECONNECT_PROOF = 0x03, - REALM_LIST = 0x10, - XFER_INITIATE = 0x30, - XFER_DATA = 0x31, - XFER_ACCEPT = 0x32, - XFER_RESUME = 0x33, - XFER_CANCEL = 0x34 + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + AUTH_RECONNECT_CHALLENGE = 0x02, + AUTH_RECONNECT_PROOF = 0x03, + REALM_LIST = 0x10, + XFER_INITIATE = 0x30, + XFER_DATA = 0x31, + XFER_ACCEPT = 0x32, + XFER_RESUME = 0x33, + XFER_CANCEL = 0x34 }; enum eStatus { - STATUS_CONNECTED = 0, + STATUS_CONNECTED = 0, STATUS_AUTHED }; -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some paltform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif typedef struct AUTH_LOGON_CHALLENGE_C { @@ -86,7 +79,7 @@ typedef struct AUTH_LOGON_PROOF_C uint8 M1[20]; uint8 crc_hash[20]; uint8 number_of_keys; - uint8 securityFlags; // 0x00-0x04 + uint8 securityFlags; } sAuthLogonProof_C; typedef struct AUTH_LOGON_PROOF_S @@ -116,245 +109,110 @@ typedef struct AUTH_RECONNECT_PROOF_C uint8 number_of_keys; } sAuthReconnectProof_C; -typedef struct XFER_INIT -{ - uint8 cmd; // XFER_INITIATE - uint8 fileNameLen; // strlen(fileName); - uint8 fileName[5]; // fileName[fileNameLen] - uint64 file_size; // file size (bytes) - uint8 md5[MD5_DIGEST_LENGTH]; // MD5 -} XFER_INIT; - -typedef struct XFER_DATA -{ - uint8 opcode; - uint16 data_size; - uint8 data[ChunkSize]; -} XFER_DATA_STRUCT; +#pragma pack(pop) + typedef struct AuthHandler { eAuthCmd cmd; uint32 status; - bool (AuthSocket::*handler)(void); + size_t packetSize; + bool (AuthSession::*handler)(); } AuthHandler; -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -// Launch a thread to transfer a patch to the client -class PatcherRunnable: public ACE_Based::Runnable -{ -public: - PatcherRunnable(class AuthSocket*); - void run(); - -private: - AuthSocket* mySocket; -}; - -typedef struct PATCH_INFO -{ - uint8 md5[MD5_DIGEST_LENGTH]; -} PATCH_INFO; - -// Caches MD5 hash of client patches present on the server -class Patcher -{ -public: - typedef std::map<std::string, PATCH_INFO*> Patches; - ~Patcher(); - Patcher(); - Patches::const_iterator begin() const { return _patches.begin(); } - Patches::const_iterator end() const { return _patches.end(); } - void LoadPatchMD5(char*); - bool GetHash(char * pat, uint8 mymd5[16]); - -private: - void LoadPatchesInfo(); - Patches _patches; -}; +#define BYTE_SIZE 32 +#define REALMLIST_SKIP_PACKETS 5 const AuthHandler table[] = { - { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, - { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, - { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, - { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, - { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, - { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, - { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, - { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } + { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleLogonChallenge }, + { AUTH_LOGON_PROOF, STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::_HandleLogonProof }, + { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleReconnectChallenge }, + { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::_HandleReconnectProof }, + { REALM_LIST, STATUS_AUTHED, REALMLIST_SKIP_PACKETS, &AuthSession::_HandleRealmList } }; -#define AUTH_TOTAL_COMMANDS 8 - -// Holds the MD5 hash of client patches present on the server -Patcher PatchesCache; - -// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket(RealmSocket& socket) : - pPatch(NULL), socket_(socket), _authed(false), _build(0), - _expversion(0), _accountSecurityLevel(SEC_PLAYER) +void AuthSession::AsyncReadHeader() { - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); -} + auto self(shared_from_this()); -// Close patch file descriptor before leaving -AuthSocket::~AuthSocket(void) { } + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes == 1) + { + for (const AuthHandler& entry : table) + { + if ((uint8)entry.cmd == _readBuffer[0] && (entry.status == STATUS_CONNECTED || (_isAuthenticated && entry.status == STATUS_AUTHED))) + { + // Handle dynamic size packet + if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) + { + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size -// Accept the connection -void AuthSocket::OnAccept(void) -{ - TC_LOG_DEBUG("server.authserver", "'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + AsyncReadData(entry.handler, *reinterpret_cast<uint16*>(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size + } + else + { + AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); + } + break; + } + } + } + else + { + _socket.close(); + } + }); } -void AuthSocket::OnClose(void) +void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) { - TC_LOG_DEBUG("server.authserver", "AuthSocket::OnClose"); -} + auto self(shared_from_this()); -// Read the packet from the client -void AuthSocket::OnRead() -{ - #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3 - uint32 challengesInARow = 0; - uint8 _cmd; - while (1) + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) { - if (!socket().recv_soft((char *)&_cmd, 1)) - return; - - if (_cmd == AUTH_LOGON_CHALLENGE) + if (!error && transferedBytes > 0) { - ++challengesInARow; - if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) + if (!(*this.*handler)()) { - TC_LOG_WARN("server.authserver", "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, socket().getRemoteAddress().c_str()); - socket().shutdown(); + _socket.close(); return; } - } - - size_t i; - // Circle through known commands and call the correct command handler - for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) - { - if ((uint8)table[i].cmd == _cmd && (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED))) - { - TC_LOG_DEBUG("server.authserver", "Got data for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - - if (!(*this.*table[i].handler)()) - { - TC_LOG_DEBUG("server.authserver", "Command handler failed for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - return; - } - break; - } + AsyncReadHeader(); } - - // Report unknown packets in the error log - if (i == AUTH_TOTAL_COMMANDS) + else { - TC_LOG_ERROR("server.authserver", "Got unknown packet from '%s'", socket().getRemoteAddress().c_str()); - socket().shutdown(); - return; + _socket.close(); } - } + }); } -// Make the SRP6 calculation from hash in dB -void AuthSocket::_SetVSFields(const std::string& rI) +void AuthSession::AsyncWrite(std::size_t length) { - s.SetRand(s_BYTE_SIZE * 8); - - BigNumber I; - I.SetHexStr(rI.c_str()); - - // In case of leading zeros in the rI hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memset(mDigest, 0, SHA_DIGEST_LENGTH); - if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) - memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - SHA1Hash sha; - sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); - sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); - sha.Finalize(); - BigNumber x; - x.SetBinary(sha.GetDigest(), sha.GetLength()); - v = g.ModExp(x, N); - - // No SQL injection (username escaped) - char *v_hex, *s_hex; - v_hex = v.AsHexStr(); - s_hex = s.AsHexStr(); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v_hex); - stmt->setString(1, s_hex); - stmt->setString(2, _login); - LoginDatabase.Execute(stmt); - - OPENSSL_free(v_hex); - OPENSSL_free(s_hex); + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); } -// Logon Challenge command handler -bool AuthSocket::_HandleLogonChallenge() +bool AuthSession::_HandleLogonChallenge() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonChallenge"); - if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - // Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector<uint8> buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); - - EndianConvertPtr<uint16>(&buf[0]); - - uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got header, body is %#04x bytes", remaining); - - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) - return false; - - //No big fear of memory outage (size is int16, i.e. < 65536) - buf.resize(remaining + buf.size() + 1); - buf[buf.size() - 1] = 0; - sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; - - // Read the remaining of the packet - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); - - // BigEndian code, nop in little endian case - // size already converted - EndianConvertPtr<uint32>(&ch->gamename[0]); - EndianConvert(ch->build); - EndianConvertPtr<uint32>(&ch->platform[0]); - EndianConvertPtr<uint32>(&ch->os[0]); - EndianConvertPtr<uint32>(&ch->country[0]); - EndianConvert(ch->timezone_bias); - EndianConvert(ch->ip); + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); ByteBuffer pkt; - _login = (const char*)ch->I; - _build = ch->build; + _login.assign((const char*)challenge->I, challenge->I_len); + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -368,14 +226,16 @@ bool AuthSocket::_HandleLogonChallenge() // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - std::string const& ip_address = socket().getRemoteAddress(); + std::string const& ipAddress = _socket.remote_endpoint().address().to_string(); + unsigned short port = _socket.remote_endpoint().port(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ip_address); + stmt->setString(0, ipAddress); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); } else { @@ -394,9 +254,9 @@ bool AuthSocket::_HandleLogonChallenge() if (fields[2].GetUInt8() == 1) // if ip is locked { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ip_address.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); @@ -413,7 +273,7 @@ bool AuthSocket::_HandleLogonChallenge() TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); else if (!accountCountry.empty()) { - uint32 ip = inet_addr(ip_address.c_str()); + uint32 ip = inet_addr(ipAddress.c_str()); EndianConvertReverse(ip); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); @@ -421,7 +281,9 @@ bool AuthSocket::_HandleLogonChallenge() if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), accountCountry.c_str(), loginCountry.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), + accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); @@ -450,12 +312,14 @@ bool AuthSocket::_HandleLogonChallenge() if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), + port, _login.c_str()); } else { pkt << uint8(WOW_FAIL_SUSPENDED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", + ipAddress.c_str(), port, _login.c_str()); } } else @@ -470,8 +334,8 @@ bool AuthSocket::_HandleLogonChallenge() TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2 since bytes are stored as hexstring - if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2) - _SetVSFields(rI); + if (databaseV.size() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); @@ -533,10 +397,12 @@ bool AuthSocket::_HandleLogonChallenge() _localizationName.resize(4); for (int i = 0; i < 4; ++i) - _localizationName[i] = ch->country[4-i-1]; + _localizationName[i] = challenge->country[4 - i - 1]; - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(), - _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName) + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) ); } } @@ -545,39 +411,38 @@ bool AuthSocket::_HandleLogonChallenge() pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); } - socket().send((char const*)pkt.contents(), pkt.size()); + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + return true; } // Logon Proof command handler -bool AuthSocket::_HandleLogonProof() +bool AuthSession::_HandleLogonProof() { + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); // Read the packet - sAuthLogonProof_C lp; - - if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) - return false; + sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer; // If the client has no valid version if (_expversion == NO_VALID_EXP_FLAG) { // Check if we have the appropriate patch on the disk TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented"); - socket().shutdown(); - return true; + return false; } // Continue the SRP6 calculation based on data received from the client BigNumber A; - A.SetBinary(lp.A, 32); + A.SetBinary(logonProof->A, 32); // SRP safeguard: abort if A == 0 if (A.isZero()) { - socket().shutdown(); - return true; + return false; } SHA1Hash sha; @@ -645,9 +510,9 @@ bool AuthSocket::_HandleLogonProof() M.SetBinary(sha.GetDigest(), 20); // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray().get(), lp.M1, 20)) + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket @@ -655,7 +520,7 @@ bool AuthSocket::_HandleLogonProof() PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); stmt->setString(0, K_hex); - stmt->setString(1, socket().getRemoteAddress().c_str()); + stmt->setString(1, GetRemoteIpAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); @@ -669,8 +534,11 @@ bool AuthSocket::_HandleLogonProof() sha.Finalize(); // Check auth token - if ((lp.securityFlags & 0x04) || !_tokenKey.empty()) + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) { + // TODO To be fixed + + /* uint8 size; socket().recv((char*)&size, 1); char* token = new char[size + 1]; @@ -681,10 +549,10 @@ bool AuthSocket::_HandleLogonProof() delete[] token; if (validToken != incomingToken) { - char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); - return false; - } + char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + socket().send(data, sizeof(data)); + return false; + }*/ } if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients @@ -696,7 +564,9 @@ bool AuthSocket::_HandleLogonProof() proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) proof.unk2 = 0x00; // SurveyId proof.unk3 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); } else { @@ -705,26 +575,31 @@ bool AuthSocket::_HandleLogonProof() proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk2 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); } - _authed = true; + _isAuthenticated = true; } else { char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); + std::memcpy(_writeBuffer, data, sizeof(data)); + AsyncWrite(sizeof(data)); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); // We can not include the failed account login hook. However, this is a workaround to still log this. - if (sConfigMgr->GetBoolDefault("Additional.IP.Based.Login.Logging", false)) + if (sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false)) { PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); logstmt->setString(0, _login); - logstmt->setString(1, socket().getRemoteAddress()); + logstmt->setString(1, GetRemoteIpAddress()); logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); LoginDatabase.Execute(logstmt); @@ -758,17 +633,17 @@ bool AuthSocket::_HandleLogonProof() LoginDatabase.Execute(stmt); TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); } else { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, socket().getRemoteAddress()); + stmt->setString(0, GetRemoteIpAddress()); stmt->setUInt32(1, WrongPassBanTime); LoginDatabase.Execute(stmt); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); } } } @@ -778,38 +653,15 @@ bool AuthSocket::_HandleLogonProof() return true; } -// Reconnect Challenge command handler -bool AuthSocket::_HandleReconnectChallenge() +bool AuthSession::_HandleReconnectChallenge() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; - - // Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector<uint8> buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - EndianConvertPtr<uint16>(&buf[0]); + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); - uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got header, body is %#04x bytes", remaining); - - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) - return false; - - // No big fear of memory outage (size is int16, i.e. < 65536) - buf.resize(remaining + buf.size() + 1); - buf[buf.size() - 1] = 0; - sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; - - // Read the remaining of the packet - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); - - _login = (const char*)ch->I; + _login.assign((const char*)challenge->I, challenge->I_len); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); stmt->setString(0, _login); @@ -818,15 +670,15 @@ bool AuthSocket::_HandleReconnectChallenge() // Stop if the account is not found if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); return false; } // Reinitialize build, expansion and the account securitylevel - _build = ch->build; + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -838,7 +690,7 @@ bool AuthSocket::_HandleReconnectChallenge() uint8 secLevel = fields[2].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - K.SetHexStr ((*result)[0].GetCString()); + K.SetHexStr((*result)[0].GetCString()); // Sending response ByteBuffer pkt; @@ -847,24 +699,22 @@ bool AuthSocket::_HandleReconnectChallenge() _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - socket().send((char const*)pkt.contents(), pkt.size()); + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + return true; } - -// Reconnect Proof command handler -bool AuthSocket::_HandleReconnectProof() +bool AuthSession::_HandleReconnectProof() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - // Read the packet - sAuthReconnectProof_C lp; - if (!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) - return false; + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; BigNumber t1; - t1.SetBinary(lp.R1, 16); + t1.SetBinary(reconnectProof->R1, 16); SHA1Hash sha; sha.Initialize(); @@ -872,55 +722,64 @@ bool AuthSocket::_HandleReconnectProof() sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); - if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) + if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) { // Sending response ByteBuffer pkt; pkt << uint8(AUTH_RECONNECT_PROOF); pkt << uint8(0x00); pkt << uint16(0x00); // 2 bytes zeros - socket().send((char const*)pkt.contents(), pkt.size()); - _authed = true; + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + _isAuthenticated = true; return true; } else { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); return false; } } -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +tcp::endpoint const GetAddressForClient(Realm const& realm, ip::address const& clientAddr) { + ip::address realmIp; + // Attempt to send best address for client if (clientAddr.is_loopback()) { // Try guessing if realm is also connected locally if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) - return clientAddr; - - // Assume that user connecting from the machine that authserver is located on - // has all realms available in his local network - return realm.LocalAddress; + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + realmIp = realm.LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong()) == + (realm.LocalAddress.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = realm.LocalAddress; + } + else + realmIp = realm.ExternalAddress; } - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; + tcp::endpoint endpoint(realmIp, realm.port); // Return external IP - return realm.ExternalAddress; + return endpoint; } -// Realm List command handler -bool AuthSocket::_HandleRealmList() +bool AuthSession::_HandleRealmList() { TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - if (socket().recv_len() < 5) - return false; - - socket().recv_skip(5); // Get the user id (else close the connection) // No SQL injection (prepared statement) @@ -929,8 +788,8 @@ bool AuthSocket::_HandleRealmList() PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); return false; } @@ -938,16 +797,13 @@ bool AuthSocket::_HandleRealmList() uint32 id = fields[0].GetUInt32(); // Update realm list if need - sRealmList->UpdateIfNeed(); - - ACE_INET_Addr clientAddr; - socket().peer().get_remote_addr(clientAddr); + sRealmList.UpdateIfNeed(); // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; size_t RealmListSize = 0; - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { const Realm &realm = i->second; // don't work with realms which not compatible with the client @@ -975,9 +831,6 @@ bool AuthSocket::_HandleRealmList() name = ss.str(); } - // We don't need the port number from which client connects with but the realm's port - clientAddr.set_port_number(realm.ExternalAddress.get_port_number()); - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; uint8 AmountOfCharacters = 0; @@ -993,7 +846,7 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << boost::lexical_cast<std::string>(GetAddressForClient(realm, _socket.remote_endpoint().address())); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category @@ -1038,182 +891,47 @@ bool AuthSocket::_HandleRealmList() hdr.append(RealmListSizeBuffer); // append RealmList's size buffer hdr.append(pkt); // append realms in the realmlist - socket().send((char const*)hdr.contents(), hdr.size()); - - return true; -} - -// Resume patch transfer -bool AuthSocket::_HandleXferResume() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferResume"); - // Check packet length and patch existence - if (socket().recv_len() < 9 || !pPatch) // FIXME: pPatch is never used - { - TC_LOG_ERROR("server.authserver", "Error while resuming patch transfer (wrong packet)"); - return false; - } + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(hdr.size()); - // Launch a PatcherRunnable thread starting at given patch file offset - uint64 start; - socket().recv_skip(1); - socket().recv((char*)&start, sizeof(start)); - fseek(pPatch, long(start), 0); - - ACE_Based::Thread u(new PatcherRunnable(this)); return true; } -// Cancel patch transfer -bool AuthSocket::_HandleXferCancel() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferCancel"); - - // Close and delete the socket - socket().recv_skip(1); //clear input buffer - socket().shutdown(); - - return true; -} - -// Accept patch transfer -bool AuthSocket::_HandleXferAccept() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferAccept"); - - // Check packet length and patch existence - if (!pPatch) - { - TC_LOG_ERROR("server.authserver", "Error while accepting patch transfer (wrong packet)"); - return false; - } - - // Launch a PatcherRunnable thread, starting at the beginning of the patch file - socket().recv_skip(1); // clear input buffer - fseek(pPatch, 0, 0); - - ACE_Based::Thread u(new PatcherRunnable(this)); - return true; -} - -PatcherRunnable::PatcherRunnable(class AuthSocket* as) -{ - mySocket = as; -} - -// Send content of patch file to the client -void PatcherRunnable::run() { } - -// Preload MD5 hashes of existing patch files on server -#ifndef _WIN32 -#include <dirent.h> -#include <errno.h> -void Patcher::LoadPatchesInfo() -{ - DIR *dirp; - struct dirent *dp; - dirp = opendir("./patches/"); - - if (!dirp) - return; - - while (dirp) - { - errno = 0; - if ((dp = readdir(dirp)) != NULL) - { - int l = strlen(dp->d_name); - - if (l < 8) - continue; - - if (!memcmp(&dp->d_name[l - 4], ".mpq", 4)) - LoadPatchMD5(dp->d_name); - } - else - { - if (errno != 0) - { - closedir(dirp); - return; - } - break; - } - } - - if (dirp) - closedir(dirp); -} -#else -void Patcher::LoadPatchesInfo() -{ - WIN32_FIND_DATA fil; - HANDLE hFil = FindFirstFile("./patches/*.mpq", &fil); - if (hFil == INVALID_HANDLE_VALUE) - return; // no patches were found - - do - LoadPatchMD5(fil.cFileName); - while (FindNextFile(hFil, &fil)); -} -#endif - -// Calculate and store MD5 hash for a given patch file -void Patcher::LoadPatchMD5(char *szFileName) +// Make the SRP6 calculation from hash in dB +void AuthSession::SetVSFields(const std::string& rI) { - // Try to open the patch file - std::string path = "./patches/"; - path += szFileName; - FILE* pPatch = fopen(path.c_str(), "rb"); - TC_LOG_DEBUG("network", "Loading patch info from %s\n", path.c_str()); - - if (!pPatch) - { - TC_LOG_ERROR("server.authserver", "Error loading patch %s\n", path.c_str()); - return; - } - - // Calculate the MD5 hash - MD5_CTX ctx; - MD5_Init(&ctx); - uint8* buf = new uint8[512 * 1024]; + s.SetRand(BYTE_SIZE * 8); - while (!feof(pPatch)) - { - size_t read = fread(buf, 1, 512 * 1024, pPatch); - MD5_Update(&ctx, buf, read); - } + BigNumber I; + I.SetHexStr(rI.c_str()); - delete [] buf; - fclose(pPatch); + // In case of leading zeros in the rI hash, restore them + uint8 mDigest[SHA_DIGEST_LENGTH]; + memset(mDigest, 0, SHA_DIGEST_LENGTH); + if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) + memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); - // Store the result in the internal patch hash map - _patches[path] = new PATCH_INFO; - MD5_Final((uint8 *)&_patches[path]->md5, &ctx); -} + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); -// Get cached MD5 hash for a given patch file -bool Patcher::GetHash(char * pat, uint8 mymd5[16]) -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - if (!stricmp(pat, i->first.c_str())) - { - memcpy(mymd5, i->second->md5, 16); - return true; - } + SHA1Hash sha; + sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); + sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); - return false; -} + // No SQL injection (username escaped) + char *v_hex, *s_hex; + v_hex = v.AsHexStr(); + s_hex = s.AsHexStr(); -// Launch the patch hashing mechanism on object creation -Patcher::Patcher() -{ - LoadPatchesInfo(); -} + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); + stmt->setString(0, v_hex); + stmt->setString(1, s_hex); + stmt->setString(2, _login); + LoginDatabase.Execute(stmt); -// Empty and delete the patch map on termination -Patcher::~Patcher() -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - delete i->second; + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); } diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h new file mode 100644 index 00000000000..4ae33f44cb3 --- /dev/null +++ b/src/server/authserver/Server/AuthSession.h @@ -0,0 +1,84 @@ +/* +* 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 +* 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 __AUTHSESSION_H__ +#define __AUTHSESSION_H__ + +#include <memory> +#include <boost/asio/ip/tcp.hpp> +#include "Common.h" +#include "BigNumber.h" + +using boost::asio::ip::tcp; + +const size_t bufferSize = 4096; + +#define BUFFER_SIZE 4096 + +class AuthSession : public std::enable_shared_from_this < AuthSession > +{ +public: + AuthSession(tcp::socket&& socket) : _socket(std::move(socket)) + { + N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword(7); + } + + void Start() + { + AsyncReadHeader(); + } + + bool _HandleLogonChallenge(); + bool _HandleLogonProof(); + bool _HandleReconnectChallenge(); + bool _HandleReconnectProof(); + bool _HandleRealmList(); + + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } + +private: + void AsyncReadHeader(); + void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset); + void AsyncWrite(size_t length); + + + void SetVSFields(const std::string& rI); + + BigNumber N, s, g, v; + BigNumber b, B; + BigNumber K; + BigNumber _reconnectProof; + + tcp::socket _socket; + char _readBuffer[BUFFER_SIZE]; + char _writeBuffer[BUFFER_SIZE]; + + bool _isAuthenticated; + std::string _tokenKey; + std::string _login; + std::string _localizationName; + std::string _os; + uint16 _build; + uint8 _expversion; + + AccountTypes _accountSecurityLevel; +}; + +#endif diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h deleted file mode 100644 index 5e04d459ba1..00000000000 --- a/src/server/authserver/Server/AuthSocket.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 - * 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 _AUTHSOCKET_H -#define _AUTHSOCKET_H - -#include "Common.h" -#include "BigNumber.h" -#include "RealmSocket.h" - -class ACE_INET_Addr; -struct Realm; - -// Handle login commands -class AuthSocket: public RealmSocket::Session -{ -public: - const static int s_BYTE_SIZE = 32; - - AuthSocket(RealmSocket& socket); - virtual ~AuthSocket(void); - - virtual void OnRead(void); - virtual void OnAccept(void); - virtual void OnClose(void); - - static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); - - bool _HandleLogonChallenge(); - bool _HandleLogonProof(); - bool _HandleReconnectChallenge(); - bool _HandleReconnectProof(); - bool _HandleRealmList(); - - //data transfer handle for patch - bool _HandleXferResume(); - bool _HandleXferCancel(); - bool _HandleXferAccept(); - - void _SetVSFields(const std::string& rI); - - FILE* pPatch; - ACE_Thread_Mutex patcherLock; - -private: - RealmSocket& socket_; - RealmSocket& socket(void) { return socket_; } - - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; - - bool _authed; - - std::string _login; - std::string _tokenKey; - - // Since GetLocaleByName() is _NOT_ bijective, we have to store the locale as a string. Otherwise we can't differ - // between enUS and enGB, which is important for the patch system - std::string _localizationName; - std::string _os; - uint16 _build; - uint8 _expversion; - AccountTypes _accountSecurityLevel; -}; - -#endif diff --git a/src/server/authserver/Server/RealmAcceptor.h b/src/server/authserver/Server/RealmAcceptor.h deleted file mode 100644 index e89135c4896..00000000000 --- a/src/server/authserver/Server/RealmAcceptor.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2008-2014 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 __REALMACCEPTOR_H__ -#define __REALMACCEPTOR_H__ - -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "RealmSocket.h" -#include "AuthSocket.h" - -class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor> -{ -public: - RealmAcceptor(void) { } - virtual ~RealmAcceptor(void) - { - if (reactor()) - reactor()->cancel_timer(this, 1); - } - -protected: - virtual int make_svc_handler(RealmSocket* &sh) - { - if (sh == 0) - ACE_NEW_RETURN(sh, RealmSocket, -1); - - sh->reactor(reactor()); - sh->set_session(new AuthSocket(*sh)); - return 0; - } - - virtual int handle_timeout(const ACE_Time_Value& /*current_time*/, const void* /*act = 0*/) - { - TC_LOG_DEBUG("server.authserver", "Resuming acceptor"); - reactor()->cancel_timer(this, 1); - return reactor()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); - } - - virtual int handle_accept_error(void) - { -#if defined(ENFILE) && defined(EMFILE) - if (errno == ENFILE || errno == EMFILE) - { - TC_LOG_ERROR("server.authserver", "Out of file descriptors, suspending incoming connections for 10 seconds"); - reactor()->remove_handler(this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); - reactor()->schedule_timer(this, NULL, ACE_Time_Value(10)); - } -#endif - return 0; - } -}; - -#endif diff --git a/src/server/authserver/Server/RealmSocket.cpp b/src/server/authserver/Server/RealmSocket.cpp deleted file mode 100644 index 1013639cc50..00000000000 --- a/src/server/authserver/Server/RealmSocket.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008-2014 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/>. - */ - -#include <ace/OS_NS_string.h> -#include <ace/INET_Addr.h> -#include <ace/SString.h> - -#include "RealmSocket.h" -#include "Log.h" - -RealmSocket::Session::Session(void) { } - -RealmSocket::Session::~Session(void) { } - -RealmSocket::RealmSocket(void) : - input_buffer_(4096), session_(NULL), - _remoteAddress(), _remotePort(0) -{ - reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED); - - msg_queue()->high_water_mark(8 * 1024 * 1024); - msg_queue()->low_water_mark(8 * 1024 * 1024); -} - -RealmSocket::~RealmSocket(void) -{ - if (msg_queue()) - msg_queue()->close(); - - // delete RealmSocketObject must never be called from our code. - closing_ = true; - - delete session_; - - peer().close(); -} - -int RealmSocket::open(void * arg) -{ - ACE_INET_Addr addr; - - if (peer().get_remote_addr(addr) == -1) - { - TC_LOG_ERROR("server.authserver", "Error %s while opening realm socket!", ACE_OS::strerror(errno)); - return -1; - } - - _remoteAddress = addr.get_host_addr(); - _remotePort = addr.get_port_number(); - - // Register with ACE Reactor - if (Base::open(arg) == -1) - return -1; - - if (session_) - session_->OnAccept(); - - // reactor takes care of the socket from now on - remove_reference(); - - return 0; -} - -int RealmSocket::close(u_long) -{ - shutdown(); - - closing_ = true; - - remove_reference(); - - return 0; -} - -const std::string& RealmSocket::getRemoteAddress(void) const -{ - return _remoteAddress; -} - -uint16 RealmSocket::getRemotePort(void) const -{ - return _remotePort; -} - -size_t RealmSocket::recv_len(void) const -{ - return input_buffer_.length(); -} - -bool RealmSocket::recv_soft(char *buf, size_t len) -{ - if (input_buffer_.length() < len) - return false; - - ACE_OS::memcpy(buf, input_buffer_.rd_ptr(), len); - - return true; -} - -bool RealmSocket::recv(char *buf, size_t len) -{ - bool ret = recv_soft(buf, len); - - if (ret) - recv_skip(len); - - return ret; -} - -void RealmSocket::recv_skip(size_t len) -{ - input_buffer_.rd_ptr(len); -} - -ssize_t RealmSocket::noblk_send(ACE_Message_Block &message_block) -{ - const size_t len = message_block.length(); - - if (len == 0) - return -1; - - // Try to send the message directly. -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send(message_block.rd_ptr(), len); -#endif // MSG_NOSIGNAL - - if (n < 0) - { - if (errno == EWOULDBLOCK) // Blocking signal - return 0; - else // Error happened - return -1; - } - else if (n == 0) - { - // Can this happen ? - return -1; - } - - // return bytes transmitted - return n; -} - -bool RealmSocket::send(const char *buf, size_t len) -{ - if (buf == NULL || len == 0) - return true; - - ACE_Data_Block db(len, ACE_Message_Block::MB_DATA, (const char*)buf, 0, 0, ACE_Message_Block::DONT_DELETE, 0); - ACE_Message_Block message_block(&db, ACE_Message_Block::DONT_DELETE, 0); - - message_block.wr_ptr(len); - - if (msg_queue()->is_empty()) - { - // Try to send it directly. - ssize_t n = noblk_send(message_block); - - if (n < 0) - return false; - - size_t un = size_t(n); - if (un == len) - return true; - - // fall down - message_block.rd_ptr(un); - } - - ACE_Message_Block* mb = message_block.clone(); - - if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - { - mb->release(); - return false; - } - - if (reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1) - return false; - - return true; -} - -int RealmSocket::handle_output(ACE_HANDLE) -{ - if (closing_) - return -1; - - ACE_Message_Block* mb = 0; - - if (msg_queue()->is_empty()) - { - reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); - return 0; - } - - if (msg_queue()->dequeue_head(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - return -1; - - ssize_t n = noblk_send(*mb); - - if (n < 0) - { - mb->release(); - return -1; - } - else if (size_t(n) == mb->length()) - { - mb->release(); - return 1; - } - else - { - mb->rd_ptr(n); - - if (msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) - { - mb->release(); - return -1; - } - - return 0; - } - - ACE_NOTREACHED(return -1); -} - -int RealmSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask) -{ - // As opposed to WorldSocket::handle_close, we don't need locks here. - closing_ = true; - - if (h == ACE_INVALID_HANDLE) - peer().close_writer(); - - if (session_) - session_->OnClose(); - - reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK); - return 0; -} - -int RealmSocket::handle_input(ACE_HANDLE) -{ - if (closing_) - return -1; - - const ssize_t space = input_buffer_.space(); - - ssize_t n = peer().recv(input_buffer_.wr_ptr(), space); - - if (n < 0) - return errno == EWOULDBLOCK ? 0 : -1; - else if (n == 0) // EOF - return -1; - - input_buffer_.wr_ptr((size_t)n); - - if (session_ != NULL) - { - session_->OnRead(); - input_buffer_.crunch(); - } - - // return 1 in case there is more data to read from OS - return n == space ? 1 : 0; -} - -void RealmSocket::set_session(Session* session) -{ - delete session_; - - session_ = session; -} diff --git a/src/server/authserver/Server/RealmSocket.h b/src/server/authserver/Server/RealmSocket.h deleted file mode 100644 index c1190d638b3..00000000000 --- a/src/server/authserver/Server/RealmSocket.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2008-2014 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 __REALMSOCKET_H__ -#define __REALMSOCKET_H__ - -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/Message_Block.h> -#include <ace/Basic_Types.h> -#include "Common.h" - -class RealmSocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ -private: - typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Base; - -public: - class Session - { - public: - Session(void); - virtual ~Session(void); - - virtual void OnRead(void) = 0; - virtual void OnAccept(void) = 0; - virtual void OnClose(void) = 0; - }; - - RealmSocket(void); - virtual ~RealmSocket(void); - - size_t recv_len(void) const; - bool recv_soft(char *buf, size_t len); - bool recv(char *buf, size_t len); - void recv_skip(size_t len); - - bool send(const char *buf, size_t len); - - const std::string& getRemoteAddress(void) const; - - uint16 getRemotePort(void) const; - - virtual int open(void *); - - virtual int close(u_long); - - virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); - virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); - - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - void set_session(Session* session); - -private: - ssize_t noblk_send(ACE_Message_Block &message_block); - - ACE_Message_Block input_buffer_; - Session* session_; - std::string _remoteAddress; - uint16 _remotePort; -}; - -#endif /* __REALMSOCKET_H__ */ diff --git a/src/server/collision/BoundingIntervalHierarchy.h b/src/server/collision/BoundingIntervalHierarchy.h index 4d38bfc18c4..491a299ca68 100644 --- a/src/server/collision/BoundingIntervalHierarchy.h +++ b/src/server/collision/BoundingIntervalHierarchy.h @@ -177,7 +177,7 @@ class BIH { uint32 tn = tree[node]; uint32 axis = (tn & (3 << 30)) >> 30; - bool BVH2 = tn & (1 << 29); + bool BVH2 = (tn & (1 << 29)) != 0; int offset = tn & ~(7 << 29); if (!BVH2) { @@ -271,7 +271,7 @@ class BIH { uint32 tn = tree[node]; uint32 axis = (tn & (3 << 30)) >> 30; - bool BVH2 = tn & (1 << 29); + bool BVH2 = (tn & (1 << 29)) != 0; int offset = tn & ~(7 << 29); if (!BVH2) { diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index a2024bff7cb..378bd62a78a 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -75,7 +75,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Management ${CMAKE_CURRENT_SOURCE_DIR}/Maps ${CMAKE_CURRENT_SOURCE_DIR}/Models - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ) diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp index 813a3c04288..1d267cbd2a5 100644 --- a/src/server/collision/Management/VMapManager2.cpp +++ b/src/server/collision/Management/VMapManager2.cpp @@ -25,8 +25,6 @@ #include "ModelInstance.h" #include "WorldModel.h" #include <G3D/Vector3.h> -#include <ace/Null_Mutex.h> -#include <ace/Singleton.h> #include "DisableMgr.h" #include "DBCStores.h" #include "Log.h" @@ -252,7 +250,7 @@ namespace VMAP WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename) { //! Critical section, thread safe access to iLoadedModelFiles - TRINITY_GUARD(ACE_Thread_Mutex, LoadedModelFilesLock); + std::lock_guard<std::mutex> lock(LoadedModelFilesLock); ModelFileMap::iterator model = iLoadedModelFiles.find(filename); if (model == iLoadedModelFiles.end()) @@ -275,7 +273,7 @@ namespace VMAP void VMapManager2::releaseModelInstance(const std::string &filename) { //! Critical section, thread safe access to iLoadedModelFiles - TRINITY_GUARD(ACE_Thread_Mutex, LoadedModelFilesLock); + std::lock_guard<std::mutex> lock(LoadedModelFilesLock); ModelFileMap::iterator model = iLoadedModelFiles.find(filename); if (model == iLoadedModelFiles.end()) diff --git a/src/server/collision/Management/VMapManager2.h b/src/server/collision/Management/VMapManager2.h index 711025e67c0..03de6951d5d 100644 --- a/src/server/collision/Management/VMapManager2.h +++ b/src/server/collision/Management/VMapManager2.h @@ -19,10 +19,10 @@ #ifndef _VMAPMANAGER2_H #define _VMAPMANAGER2_H +#include <mutex> +#include <unordered_map> #include "Define.h" #include "IVMapManager.h" -#include <unordered_map> -#include <ace/Thread_Mutex.h> //=========================================================== @@ -73,7 +73,7 @@ namespace VMAP ModelFileMap iLoadedModelFiles; InstanceTreeMap iInstanceMapTrees; // Mutex for iLoadedModelFiles - ACE_Thread_Mutex LoadedModelFilesLock; + std::mutex LoadedModelFilesLock; bool _loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY); /* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */ diff --git a/src/server/collision/Models/ModelInstance.cpp b/src/server/collision/Models/ModelInstance.cpp index 3262c154965..475984c4fd3 100644 --- a/src/server/collision/Models/ModelInstance.cpp +++ b/src/server/collision/Models/ModelInstance.cpp @@ -167,7 +167,7 @@ namespace VMAP check += fread(&spawn.iPos, sizeof(float), 3, rf); check += fread(&spawn.iRot, sizeof(float), 3, rf); check += fread(&spawn.iScale, sizeof(float), 1, rf); - bool has_bound = (spawn.flags & MOD_HAS_BOUND); + bool has_bound = (spawn.flags & MOD_HAS_BOUND) != 0; if (has_bound) // only WMOs have bound in MPQ, only available after computation { Vector3 bLow, bHigh; @@ -206,7 +206,7 @@ namespace VMAP check += fwrite(&spawn.iPos, sizeof(float), 3, wf); check += fwrite(&spawn.iRot, sizeof(float), 3, wf); check += fwrite(&spawn.iScale, sizeof(float), 1, wf); - bool has_bound = (spawn.flags & MOD_HAS_BOUND); + bool has_bound = (spawn.flags & MOD_HAS_BOUND) != 0; if (has_bound) // only WMOs have bound in MPQ, only available after computation { check += fwrite(&spawn.iBound.low(), sizeof(float), 3, wf); diff --git a/src/server/collision/VMapDefinitions.h b/src/server/collision/VMapDefinitions.h index 0bc74df51ec..8cd965ddffd 100644 --- a/src/server/collision/VMapDefinitions.h +++ b/src/server/collision/VMapDefinitions.h @@ -19,6 +19,7 @@ #ifndef _VMAPDEFINITIONS_H #define _VMAPDEFINITIONS_H #include <cstring> +#include <cstdio> #define LIQUID_TILE_SIZE (533.333f / 128.f) diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h index fc2d009e673..f2854f1a9ce 100644 --- a/src/server/game/AI/CreatureAIFactory.h +++ b/src/server/game/AI/CreatureAIFactory.h @@ -49,7 +49,6 @@ CreatureAIFactory<REAL_AI>::Create(void* data) const typedef FactoryHolder<CreatureAI> CreatureAICreator; typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry; -typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository; //GO struct SelectableGameObjectAI : public FactoryHolder<GameObjectAI>, public Permissible<GameObject> @@ -77,5 +76,4 @@ GameObjectAIFactory<REAL_GO_AI>::Create(void* data) const typedef FactoryHolder<GameObjectAI> GameObjectAICreator; typedef FactoryHolder<GameObjectAI>::FactoryHolderRegistry GameObjectAIRegistry; -typedef FactoryHolder<GameObjectAI>::FactoryHolderRepository GameObjectAIRepository; #endif diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index 473af0d787e..afbd306c184 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -31,7 +31,7 @@ namespace FactorySelector CreatureAI* selectAI(Creature* creature) { const CreatureAICreator* ai_factory = NULL; - CreatureAIRegistry& ai_registry(*CreatureAIRepository::instance()); + CreatureAIRegistry& ai_registry(*CreatureAIRegistry::instance()); if (creature->IsPet()) ai_factory = ai_registry.GetRegistryItem("PetAI"); @@ -101,7 +101,7 @@ namespace FactorySelector MovementGenerator* selectMovementGenerator(Creature* creature) { - MovementGeneratorRegistry& mv_registry(*MovementGeneratorRepository::instance()); + MovementGeneratorRegistry& mv_registry(*MovementGeneratorRegistry::instance()); ASSERT(creature->GetCreatureTemplate()); const MovementGeneratorCreator* mv_factory = mv_registry.GetRegistryItem(creature->GetDefaultMovementType()); @@ -130,7 +130,7 @@ namespace FactorySelector GameObjectAI* SelectGameObjectAI(GameObject* go) { const GameObjectAICreator* ai_factory = NULL; - GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance()); + GameObjectAIRegistry& ai_registry(*GameObjectAIRegistry::instance()); // scriptname in db if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 3d14b8f69e9..0380ec8bae9 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1396,11 +1396,17 @@ typedef std::unordered_map<uint32, ObjectGuidList*> ObjectListMap; class SmartWaypointMgr { - friend class ACE_Singleton<SmartWaypointMgr, ACE_Null_Mutex>; - SmartWaypointMgr() { } - public: + private: + SmartWaypointMgr() { } ~SmartWaypointMgr(); + public: + static SmartWaypointMgr* instance() + { + static SmartWaypointMgr* instance = new SmartWaypointMgr(); + return instance; + } + void LoadFromDB(); WPPath* GetPath(uint32 id) @@ -1426,11 +1432,17 @@ typedef std::pair<CacheSpellContainer::const_iterator, CacheSpellContainer::cons class SmartAIMgr { - friend class ACE_Singleton<SmartAIMgr, ACE_Null_Mutex>; - SmartAIMgr() { } - public: + private: + SmartAIMgr() { } ~SmartAIMgr() { } + public: + static SmartAIMgr* instance() + { + static SmartAIMgr* instance = new SmartAIMgr(); + return instance; + } + void LoadSmartAIFromDB(); SmartAIEventList GetScript(int32 entry, SmartScriptType type) @@ -1598,6 +1610,6 @@ class SmartAIMgr CacheSpellContainer KillCreditSpellStore; }; -#define sSmartScriptMgr ACE_Singleton<SmartAIMgr, ACE_Null_Mutex>::instance() -#define sSmartWaypointMgr ACE_Singleton<SmartWaypointMgr, ACE_Null_Mutex>::instance() +#define sSmartScriptMgr SmartAIMgr::instance() +#define sSmartWaypointMgr SmartWaypointMgr::instance() #endif diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index b3012ace177..2f3137ae3cd 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -20,7 +20,6 @@ #define _ACCMGR_H #include "RBAC.h" -#include <ace/Singleton.h> enum AccountOpResult { @@ -51,13 +50,17 @@ typedef std::map<uint8, rbac::RBACPermissionContainer> RBACDefaultPermissionsCon class AccountMgr { - friend class ACE_Singleton<AccountMgr, ACE_Null_Mutex>; - private: AccountMgr(); ~AccountMgr(); public: + static AccountMgr* instance() + { + static AccountMgr* instance = new AccountMgr(); + return instance; + } + AccountOpResult CreateAccount(std::string username, std::string password, std::string email); static AccountOpResult DeleteAccount(uint32 accountId); static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); @@ -95,5 +98,5 @@ class AccountMgr rbac::RBACDefaultPermissionsContainer _defaultPermissions; }; -#define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance() +#define sAccountMgr AccountMgr::instance() #endif diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2c392b37954..d54b0572252 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -425,7 +425,7 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un { time_t birthday_start = time_t(sWorld->getIntConfig(CONFIG_BIRTHDAY_TIME)); tm birthday_tm; - ACE_OS::localtime_r(&birthday_start, &birthday_tm); + localtime_r(&birthday_start, &birthday_tm); // exactly N birthday birthday_tm.tm_year += birthday_login.nth_birthday; diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index c3a1481bb2e..7128b8d6318 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -23,7 +23,6 @@ #include <string> #include "Common.h" -#include <ace/Singleton.h> #include "DatabaseEnv.h" #include "DBCEnums.h" #include "DBCStores.h" @@ -305,11 +304,16 @@ class AchievementMgr class AchievementGlobalMgr { - friend class ACE_Singleton<AchievementGlobalMgr, ACE_Null_Mutex>; AchievementGlobalMgr() { } ~AchievementGlobalMgr() { } public: + static AchievementGlobalMgr* instance() + { + static AchievementGlobalMgr* instance = new AchievementGlobalMgr(); + return instance; + } + AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type) const { return m_AchievementCriteriasByType[type]; @@ -389,6 +393,6 @@ class AchievementGlobalMgr AchievementRewardLocales m_achievementRewardLocales; }; -#define sAchievementMgr ACE_Singleton<AchievementGlobalMgr, ACE_Null_Mutex>::instance() +#define sAchievementMgr AchievementGlobalMgr::instance() #endif diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index f45fc4100de..0f42a5833a2 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -19,8 +19,6 @@ #ifndef _AUCTION_HOUSE_MGR_H #define _AUCTION_HOUSE_MGR_H -#include <ace/Singleton.h> - #include "Common.h" #include "DatabaseEnv.h" #include "DBCStructure.h" @@ -137,13 +135,16 @@ class AuctionHouseObject class AuctionHouseMgr { - friend class ACE_Singleton<AuctionHouseMgr, ACE_Null_Mutex>; - private: AuctionHouseMgr(); ~AuctionHouseMgr(); public: + static AuctionHouseMgr* instance() + { + static AuctionHouseMgr* instance = new AuctionHouseMgr(); + return instance; + } typedef std::unordered_map<uint32, Item*> ItemMap; @@ -193,6 +194,6 @@ class AuctionHouseMgr ItemMap mAitems; }; -#define sAuctionMgr ACE_Singleton<AuctionHouseMgr, ACE_Null_Mutex>::instance() +#define sAuctionMgr AuctionHouseMgr::instance() #endif diff --git a/src/server/game/Battlefield/BattlefieldMgr.h b/src/server/game/Battlefield/BattlefieldMgr.h index bb8a076d5d0..9b51fd7710e 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.h +++ b/src/server/game/Battlefield/BattlefieldMgr.h @@ -19,7 +19,6 @@ #define BATTLEFIELD_MGR_H_ #include "Battlefield.h" -#include <ace/Singleton.h> class Player; class ZoneScript; @@ -28,11 +27,12 @@ class ZoneScript; class BattlefieldMgr { public: - // ctor - BattlefieldMgr(); - // dtor - ~BattlefieldMgr(); - + static BattlefieldMgr* instance() + { + static BattlefieldMgr* instance = new BattlefieldMgr(); + return instance; + } + // create battlefield events void InitBattlefield(); @@ -52,6 +52,9 @@ class BattlefieldMgr void Update(uint32 diff); private: + BattlefieldMgr(); + ~BattlefieldMgr(); + typedef std::vector<Battlefield*> BattlefieldSet; typedef std::map<uint32 /*zoneId*/, Battlefield*> BattlefieldMap; // contains all initiated battlefield events @@ -64,6 +67,6 @@ class BattlefieldMgr uint32 _updateTimer; }; -#define sBattlefieldMgr ACE_Singleton<BattlefieldMgr, ACE_Null_Mutex>::instance() +#define sBattlefieldMgr BattlefieldMgr::instance() #endif // BATTLEFIELD_MGR_H_ diff --git a/src/server/game/Battlegrounds/ArenaTeam.h b/src/server/game/Battlegrounds/ArenaTeam.h index c977a137c2a..d3b6342b273 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.h +++ b/src/server/game/Battlegrounds/ArenaTeam.h @@ -20,7 +20,6 @@ #define TRINITYCORE_ARENATEAM_H #include "QueryResult.h" -#include <ace/Singleton.h> #include <list> #include <map> diff --git a/src/server/game/Battlegrounds/ArenaTeamMgr.h b/src/server/game/Battlegrounds/ArenaTeamMgr.h index 946824fb656..9a4c1184133 100644 --- a/src/server/game/Battlegrounds/ArenaTeamMgr.h +++ b/src/server/game/Battlegrounds/ArenaTeamMgr.h @@ -22,11 +22,17 @@ class ArenaTeamMgr { - friend class ACE_Singleton<ArenaTeamMgr, ACE_Null_Mutex>; +private: ArenaTeamMgr(); ~ArenaTeamMgr(); public: + static ArenaTeamMgr* instance() + { + static ArenaTeamMgr* instance = new ArenaTeamMgr(); + return instance; + } + typedef std::unordered_map<uint32, ArenaTeam*> ArenaTeamContainer; ArenaTeam* GetArenaTeamById(uint32 arenaTeamId) const; @@ -50,6 +56,6 @@ protected: ArenaTeamContainer ArenaTeamStore; }; -#define sArenaTeamMgr ACE_Singleton<ArenaTeamMgr, ACE_Null_Mutex>::instance() +#define sArenaTeamMgr ArenaTeamMgr::instance() #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 20cd8e4f7be..21b87d2bb1f 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -23,7 +23,6 @@ #include "DBCEnums.h" #include "Battleground.h" #include "BattlegroundQueue.h" -#include <ace/Singleton.h> typedef std::map<uint32, Battleground*> BattlegroundContainer; typedef std::set<uint32> BattlegroundClientIdsContainer; @@ -58,13 +57,17 @@ struct BattlegroundTemplate class BattlegroundMgr { - friend class ACE_Singleton<BattlegroundMgr, ACE_Null_Mutex>; - private: BattlegroundMgr(); ~BattlegroundMgr(); public: + static BattlegroundMgr* instance() + { + static BattlegroundMgr* instance = new BattlegroundMgr(); + return instance; + } + void Update(uint32 diff); /* Packet Building */ @@ -171,6 +174,6 @@ class BattlegroundMgr BattlegroundMapTemplateContainer _battlegroundMapTemplates; }; -#define sBattlegroundMgr ACE_Singleton<BattlegroundMgr, ACE_Null_Mutex>::instance() +#define sBattlegroundMgr BattlegroundMgr::instance() #endif // __BATTLEGROUNDMGR_H diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index e29969d73b1..e52f75a1c41 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -191,7 +191,6 @@ GroupQueueInfo* BattlegroundQueue::AddGroup(Player* leader, Group* grp, Battlegr //add GroupInfo to m_QueuedGroups { - //ACE_Guard<ACE_Recursive_Thread_Mutex> guard(m_Lock); m_QueuedGroups[bracketId][index].push_back(ginfo); //announce to world, this code needs mutex diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 26fd0814dcb..84d6f87d75c 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -197,7 +197,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Weather ${CMAKE_CURRENT_SOURCE_DIR}/World ${CMAKE_SOURCE_DIR}/src/server/scripts/PrecompiledHeaders - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index 8f44b013e5c..9c7882fe4b7 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -18,7 +18,6 @@ #ifndef TRINITY_CALENDARMGR_H #define TRINITY_CALENDARMGR_H -#include <ace/Singleton.h> #include "Common.h" #include "DatabaseEnv.h" #include "WorldPacket.h" @@ -268,8 +267,6 @@ typedef std::map<uint64 /* eventId */, CalendarInviteStore > CalendarEventInvite class CalendarMgr { - friend class ACE_Singleton<CalendarMgr, ACE_Null_Mutex>; - private: CalendarMgr(); ~CalendarMgr(); @@ -283,6 +280,12 @@ class CalendarMgr uint64 _maxInviteId; public: + static CalendarMgr* instance() + { + static CalendarMgr* instance = new CalendarMgr(); + return instance; + } + void LoadFromDB(); CalendarEvent* GetEvent(uint64 eventId) const; @@ -329,6 +332,6 @@ class CalendarMgr void SendPacketToAllEventRelatives(WorldPacket packet, CalendarEvent const& calendarEvent); }; -#define sCalendarMgr ACE_Singleton<CalendarMgr, ACE_Null_Mutex>::instance() +#define sCalendarMgr CalendarMgr::instance() #endif diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp index 0975a690889..00824ae2056 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.cpp +++ b/src/server/game/Chat/Channels/ChannelMgr.cpp @@ -29,13 +29,13 @@ ChannelMgr::~ChannelMgr() ChannelMgr* ChannelMgr::forTeam(uint32 team) { if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) - return ACE_Singleton<AllianceChannelMgr, ACE_Null_Mutex>::instance(); // cross-faction + return AllianceChannelMgr::instance(); // cross-faction if (team == ALLIANCE) - return ACE_Singleton<AllianceChannelMgr, ACE_Null_Mutex>::instance(); + return AllianceChannelMgr::instance(); if (team == HORDE) - return ACE_Singleton<HordeChannelMgr, ACE_Null_Mutex>::instance(); + return HordeChannelMgr::instance(); return NULL; } diff --git a/src/server/game/Chat/Channels/ChannelMgr.h b/src/server/game/Chat/Channels/ChannelMgr.h index 603eb52f589..0fd5cdbfe24 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.h +++ b/src/server/game/Chat/Channels/ChannelMgr.h @@ -20,7 +20,6 @@ #include "Common.h" #include "Channel.h" -#include <ace/Singleton.h> #include <map> #include <string> @@ -31,12 +30,17 @@ class ChannelMgr { typedef std::map<std::wstring, Channel*> ChannelMap; - public: - ChannelMgr() : team(0) - { } - + protected: + ChannelMgr() : team(0) { } ~ChannelMgr(); + public: + static ChannelMgr* instance() + { + static ChannelMgr* instance = new ChannelMgr(); + return instance; + } + static ChannelMgr * forTeam(uint32 team); void setTeam(uint32 newTeam) { team = newTeam; } diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 876b922d243..a78434776e0 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -21,7 +21,6 @@ #include "Define.h" #include "Errors.h" -#include <ace/Singleton.h> #include <list> #include <map> @@ -223,13 +222,18 @@ typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used class ConditionMgr { - friend class ACE_Singleton<ConditionMgr, ACE_Null_Mutex>; - private: ConditionMgr(); ~ConditionMgr(); public: + + static ConditionMgr* instance() + { + static ConditionMgr* instance = new ConditionMgr(); + return instance; + } + void LoadConditions(bool isReload = false); bool isConditionTypeValid(Condition* cond); ConditionList GetConditionReferences(uint32 refId); @@ -265,6 +269,6 @@ class ConditionMgr SmartEventConditionContainer SmartEventConditionStore; }; -#define sConditionMgr ACE_Singleton<ConditionMgr, ACE_Null_Mutex>::instance() +#define sConditionMgr ConditionMgr::instance() #endif diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 24b2dbb05f8..1e1cd6dd9d6 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -535,7 +535,7 @@ struct AreaTableEntry { if (mapid == 609) return true; - return (flags & AREA_FLAG_SANCTUARY); + return (flags & AREA_FLAG_SANCTUARY) != 0; } }; @@ -1367,7 +1367,7 @@ struct MapEntry return MapID == 0 || MapID == 1 || MapID == 530 || MapID == 571; } - bool IsDynamicDifficultyMap() const { return Flags & MAP_FLAG_DYNAMIC_DIFFICULTY; } + bool IsDynamicDifficultyMap() const { return (Flags & MAP_FLAG_DYNAMIC_DIFFICULTY) != 0; } }; struct MapDifficultyEntry @@ -2051,12 +2051,12 @@ struct VehicleSeatEntry uint32 m_flagsB; // 45 // 46-57 added in 3.1, floats mostly - bool CanEnterOrExit() const { return m_flags & VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT; } - bool CanSwitchFromSeat() const { return m_flags & VEHICLE_SEAT_FLAG_CAN_SWITCH; } + bool CanEnterOrExit() const { return (m_flags & VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT) != 0; } + bool CanSwitchFromSeat() const { return (m_flags & VEHICLE_SEAT_FLAG_CAN_SWITCH) != 0; } bool IsUsableByOverride() const { return (m_flags & (VEHICLE_SEAT_FLAG_UNCONTROLLED | VEHICLE_SEAT_FLAG_UNK18) || (m_flagsB & (VEHICLE_SEAT_FLAG_B_USABLE_FORCED | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4))); } - bool IsEjectable() const { return m_flagsB & VEHICLE_SEAT_FLAG_B_EJECTABLE; } + bool IsEjectable() const { return (m_flagsB & VEHICLE_SEAT_FLAG_B_EJECTABLE) != 0; } }; struct WMOAreaTableEntry diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 2c31fe37d4d..03ac5254057 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -18,7 +18,6 @@ #ifndef _LFGMGR_H #define _LFGMGR_H -#include <ace/Singleton.h> #include "DBCStructure.h" #include "Field.h" #include "LFG.h" @@ -292,13 +291,17 @@ struct LFGDungeonData class LFGMgr { - friend class ACE_Singleton<LFGMgr, ACE_Null_Mutex>; - private: LFGMgr(); ~LFGMgr(); public: + static LFGMgr* instance() + { + static LFGMgr* instance = new LFGMgr(); + return instance; + } + // Functions used outside lfg namespace void Update(uint32 diff); @@ -466,5 +469,5 @@ class LFGMgr } // namespace lfg -#define sLFGMgr ACE_Singleton<lfg::LFGMgr, ACE_Null_Mutex>::instance() +#define sLFGMgr lfg::LFGMgr::instance() #endif diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index b790853f5e1..29832e4ff76 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -40,10 +40,17 @@ typedef std::unordered_map<uint32/*memberDBGUID*/, FormationInfo*> CreatureGro class FormationMgr { - friend class ACE_Singleton<FormationMgr, ACE_Null_Mutex>; - public: + private: FormationMgr() { } ~FormationMgr(); + + public: + static FormationMgr* instance() + { + static FormationMgr* instance = new FormationMgr(); + return instance; + } + void AddCreatureToGroup(uint32 group_id, Creature* creature); void RemoveCreatureFromGroup(CreatureGroup* group, Creature* creature); void LoadCreatureFormations(); @@ -78,6 +85,6 @@ class CreatureGroup void MemberAttackStart(Creature* member, Unit* target); }; -#define sFormationMgr ACE_Singleton<FormationMgr, ACE_Null_Mutex>::instance() +#define sFormationMgr FormationMgr::instance() #endif diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 4573b85c7f3..e041e063080 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -310,7 +310,7 @@ void Item::UpdateDuration(Player* owner, uint32 diff) void Item::SaveToDB(SQLTransaction& trans) { - bool isInTransaction = !(trans.null()); + bool isInTransaction = !trans; if (!isInTransaction) trans = CharacterDatabase.BeginTransaction(); @@ -1129,7 +1129,7 @@ void Item::SaveRefundDataToDB() void Item::DeleteRefundDataFromDB(SQLTransaction* trans) { - if (trans && !trans->null()) + if (trans) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE); stmt->setUInt32(0, GetGUIDLow()); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 10b8e5ffc06..7894d6cbcab 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7316,7 +7316,7 @@ void Player::ModifyHonorPoints(int32 value, SQLTransaction* trans /*=NULL*/) newValue = 0; SetHonorPoints(uint32(newValue)); - if (trans && !trans->null()) + if (trans && !trans) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_HONOR_POINTS); stmt->setUInt32(0, newValue); @@ -7332,7 +7332,7 @@ void Player::ModifyArenaPoints(int32 value, SQLTransaction* trans /*=NULL*/) newValue = 0; SetArenaPoints(uint32(newValue)); - if (trans && !trans->null()) + if (trans && !trans) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ARENA_POINTS); stmt->setUInt32(0, newValue); @@ -19765,7 +19765,7 @@ void Player::_SaveMail(SQLTransaction& trans) void Player::_SaveQuestStatus(SQLTransaction& trans) { - bool isTransaction = !trans.null(); + bool isTransaction = !trans; if (!isTransaction) trans = CharacterDatabase.BeginTransaction(); diff --git a/src/server/game/Entities/Player/SocialMgr.h b/src/server/game/Entities/Player/SocialMgr.h index 910c9164738..68c25fbf648 100644 --- a/src/server/game/Entities/Player/SocialMgr.h +++ b/src/server/game/Entities/Player/SocialMgr.h @@ -19,7 +19,6 @@ #ifndef __TRINITY_SOCIALMGR_H #define __TRINITY_SOCIALMGR_H -#include <ace/Singleton.h> #include "DatabaseEnv.h" #include "Common.h" @@ -123,13 +122,17 @@ class PlayerSocial class SocialMgr { - friend class ACE_Singleton<SocialMgr, ACE_Null_Mutex>; - private: SocialMgr(); ~SocialMgr(); public: + static SocialMgr* instance() + { + static SocialMgr* instance = new SocialMgr(); + return instance; + } + // Misc void RemovePlayerSocial(uint32 guid) { m_socialMap.erase(guid); } @@ -144,5 +147,5 @@ class SocialMgr SocialMap m_socialMap; }; -#define sSocialMgr ACE_Singleton<SocialMgr, ACE_Null_Mutex>::instance() +#define sSocialMgr SocialMgr::instance() #endif diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index e4522536a81..9e1514f11bd 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -1163,7 +1163,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %zu)", internal_event_id, mGameEventCreatureGuids.size()); return; } @@ -1190,7 +1190,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %zu)", internal_event_id, mGameEventGameobjectGuids.size()); return; } @@ -1223,7 +1223,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %u (size: " SIZEFMTD ")", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %u (size: %zu)", internal_event_id, mGameEventPoolIds.size()); return; } @@ -1238,7 +1238,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %zu)", internal_event_id, mGameEventCreatureGuids.size()); return; } @@ -1260,7 +1260,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %zu)", internal_event_id, mGameEventGameobjectGuids.size()); return; } @@ -1281,7 +1281,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) } if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %u (size: " SIZEFMTD ")", internal_event_id, mGameEventPoolIds.size()); + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %u (size: %zu)", internal_event_id, mGameEventPoolIds.size()); return; } @@ -1600,14 +1600,14 @@ void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate) //! Iterate over every supported source type (creature and gameobject) //! Not entirely sure how this will affect units in non-loaded grids. { - TRINITY_READ_GUARD(HashMapHolder<Creature>::LockType, *HashMapHolder<Creature>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Creature>::GetLock()); HashMapHolder<Creature>::MapType const& m = ObjectAccessor::GetCreatures(); for (HashMapHolder<Creature>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter) if (iter->second->IsInWorld()) iter->second->AI()->sOnGameEvent(activate, event_id); } { - TRINITY_READ_GUARD(HashMapHolder<GameObject>::LockType, *HashMapHolder<GameObject>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<GameObject>::GetLock()); HashMapHolder<GameObject>::MapType const& m = ObjectAccessor::GetGameObjects(); for (HashMapHolder<GameObject>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter) if (iter->second->IsInWorld()) diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index df062c6f660..94beb9912d5 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -22,7 +22,6 @@ #include "Common.h" #include "SharedDefines.h" #include "Define.h" -#include <ace/Singleton.h> #define max_ge_check_delay DAY // 1 day in seconds @@ -95,13 +94,17 @@ class Quest; class GameEventMgr { - friend class ACE_Singleton<GameEventMgr, ACE_Null_Mutex>; - private: GameEventMgr(); ~GameEventMgr() { }; public: + static GameEventMgr* instance() + { + static GameEventMgr* instance = new GameEventMgr(); + return instance; + } + typedef std::set<uint16> ActiveEvents; typedef std::vector<GameEventData> GameEventDataMap; ActiveEvents const& GetActiveEventList() const { return m_ActiveEvents; } @@ -180,7 +183,7 @@ class GameEventMgr GameEventGuidMap mGameEventGameobjectGuids; }; -#define sGameEventMgr ACE_Singleton<GameEventMgr, ACE_Null_Mutex>::instance() +#define sGameEventMgr GameEventMgr::instance() bool IsHolidayActive(HolidayIds id); bool IsEventActive(uint16 event_id); diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 8bf353d3eaa..ec33d8efbe1 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -16,6 +16,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/locks.hpp> + #include "ObjectAccessor.h" #include "CellImpl.h" #include "Corpse.h" @@ -205,7 +208,8 @@ Unit* ObjectAccessor::FindUnit(uint64 guid) Player* ObjectAccessor::FindPlayerByName(std::string const& name) { - TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); + std::string nameStr = name; std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower); HashMapHolder<Player>::MapType const& m = GetPlayers(); @@ -224,7 +228,8 @@ Player* ObjectAccessor::FindPlayerByName(std::string const& name) void ObjectAccessor::SaveAllPlayers() { - TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); + HashMapHolder<Player>::MapType const& m = GetPlayers(); for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) itr->second->SaveToDB(); @@ -232,7 +237,7 @@ void ObjectAccessor::SaveAllPlayers() Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid) { - TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, i_corpseLock); + boost::shared_lock<boost::shared_mutex> lock(_corpseLock); Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid); if (iter == i_player2corpse.end()) @@ -247,6 +252,8 @@ void ObjectAccessor::RemoveCorpse(Corpse* corpse) { ASSERT(corpse && corpse->GetType() != CORPSE_BONES); + boost::upgrade_lock<boost::shared_mutex> lock(_corpseLock); + /// @todo more works need to be done for corpse and other world object if (Map* map = corpse->FindMap()) { @@ -265,7 +272,7 @@ void ObjectAccessor::RemoveCorpse(Corpse* corpse) // Critical section { - TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, i_corpseLock); + boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID()); if (iter == i_player2corpse.end()) /// @todo Fix this @@ -285,7 +292,7 @@ void ObjectAccessor::AddCorpse(Corpse* corpse) // Critical section { - TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, i_corpseLock); + boost::unique_lock<boost::shared_mutex> lock(_corpseLock); ASSERT(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end()); i_player2corpse[corpse->GetOwnerGUID()] = corpse; @@ -298,7 +305,7 @@ void ObjectAccessor::AddCorpse(Corpse* corpse) void ObjectAccessor::AddCorpsesToGrid(GridCoord const& gridpair, GridType& grid, Map* map) { - TRINITY_READ_GUARD(ACE_RW_Thread_Mutex, i_corpseLock); + boost::shared_lock<boost::shared_mutex> lock(_corpseLock); for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter) { @@ -431,8 +438,8 @@ void ObjectAccessor::UnloadAll() /// Define the static members of HashMapHolder -template <class T> std::unordered_map< uint64, T* > HashMapHolder<T>::m_objectMap; -template <class T> typename HashMapHolder<T>::LockType HashMapHolder<T>::i_lock; +template <class T> std::unordered_map< uint64, T* > HashMapHolder<T>::_objectMap; +template <class T> boost::shared_mutex HashMapHolder<T>::_lock; /// Global definitions for the hashmap storage diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index b52699c85ac..79799cec55f 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -19,17 +19,17 @@ #ifndef TRINITY_OBJECTACCESSOR_H #define TRINITY_OBJECTACCESSOR_H -#include "Define.h" -#include <ace/Singleton.h> -#include <ace/Thread_Mutex.h> +#include <mutex> +#include <set> #include <unordered_map> +#include <boost/thread/locks.hpp> +#include <boost/thread/shared_mutex.hpp> -#include "UpdateData.h" - +#include "Define.h" #include "GridDefines.h" +#include "UpdateData.h" #include "Object.h" -#include <set> class Creature; class Corpse; @@ -48,42 +48,41 @@ class HashMapHolder public: typedef std::unordered_map<uint64, T*> MapType; - typedef ACE_RW_Thread_Mutex LockType; static void Insert(T* o) { - TRINITY_WRITE_GUARD(LockType, i_lock); - m_objectMap[o->GetGUID()] = o; + boost::shared_lock<boost::shared_mutex> lock(_lock); + + _objectMap[o->GetGUID()] = o; } static void Remove(T* o) { - TRINITY_WRITE_GUARD(LockType, i_lock); - m_objectMap.erase(o->GetGUID()); + boost::unique_lock<boost::shared_mutex> lock(_lock); + _objectMap.erase(o->GetGUID()); } static T* Find(uint64 guid) { - TRINITY_READ_GUARD(LockType, i_lock); - typename MapType::iterator itr = m_objectMap.find(guid); - return (itr != m_objectMap.end()) ? itr->second : NULL; + boost::shared_lock<boost::shared_mutex> lock(_lock); + typename MapType::iterator itr = _objectMap.find(guid); + return (itr != _objectMap.end()) ? itr->second : NULL; } - static MapType& GetContainer() { return m_objectMap; } + static MapType& GetContainer() { return _objectMap; } - static LockType* GetLock() { return &i_lock; } + static boost::shared_mutex* GetLock() { return &_lock; } private: //Non instanceable only static HashMapHolder() { } - static LockType i_lock; - static MapType m_objectMap; + static boost::shared_mutex _lock; + static MapType _objectMap; }; class ObjectAccessor { - friend class ACE_Singleton<ObjectAccessor, ACE_Null_Mutex>; private: ObjectAccessor(); ~ObjectAccessor(); @@ -93,6 +92,12 @@ class ObjectAccessor public: /// @todo: Override these template functions for each holder type and add assertions + static ObjectAccessor* instance() + { + static ObjectAccessor *instance = new ObjectAccessor(); + return instance; + } + template<class T> static T* GetObjectInOrOutOfWorld(uint64 guid, T* /*typeSpecifier*/) { return HashMapHolder<T>::Find(guid); @@ -195,13 +200,13 @@ class ObjectAccessor //non-static functions void AddUpdateObject(Object* obj) { - TRINITY_GUARD(ACE_Thread_Mutex, i_objectLock); + std::lock_guard<std::mutex> lock(_objectLock); i_objects.insert(obj); } void RemoveUpdateObject(Object* obj) { - TRINITY_GUARD(ACE_Thread_Mutex, i_objectLock); + std::lock_guard<std::mutex> lock(_objectLock); i_objects.erase(obj); } @@ -228,9 +233,9 @@ class ObjectAccessor std::set<Object*> i_objects; Player2CorpsesMapType i_player2corpse; - ACE_Thread_Mutex i_objectLock; - ACE_RW_Thread_Mutex i_corpseLock; + std::mutex _objectLock; + boost::shared_mutex _corpseLock; }; -#define sObjectAccessor ACE_Singleton<ObjectAccessor, ACE_Null_Mutex>::instance() +#define sObjectAccessor ObjectAccessor::instance() #endif diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 278460e73dd..4853c9b3ba5 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -5421,7 +5421,7 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) time_t curTime = time(NULL); tm lt; - ACE_OS::localtime_r(&curTime, <); + localtime_r(&curTime, <); uint64 basetime(curTime); TC_LOG_INFO("misc", "Returning mails current time: hour: %d, minute: %d, second: %d ", lt.tm_hour, lt.tm_min, lt.tm_sec); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 3f8013bbd78..3cf0c103452 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -35,7 +35,6 @@ #include "Map.h" #include "ObjectAccessor.h" #include "ObjectDefines.h" -#include <ace/Singleton.h> #include "VehicleDefines.h" #include <string> #include <map> @@ -687,13 +686,18 @@ class PlayerDumpReader; class ObjectMgr { friend class PlayerDumpReader; - friend class ACE_Singleton<ObjectMgr, ACE_Null_Mutex>; private: ObjectMgr(); ~ObjectMgr(); public: + static ObjectMgr* instance() + { + static ObjectMgr* instance = new ObjectMgr(); + return instance; + } + typedef std::unordered_map<uint32, Item*> ItemMap; typedef std::unordered_map<uint32, Quest*> QuestMap; @@ -1444,6 +1448,6 @@ class ObjectMgr std::set<uint32> _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template }; -#define sObjectMgr ACE_Singleton<ObjectMgr, ACE_Null_Mutex>::instance() +#define sObjectMgr ObjectMgr::instance() #endif diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h index a805b7514da..4bf440c881e 100644 --- a/src/server/game/Groups/GroupMgr.h +++ b/src/server/game/Groups/GroupMgr.h @@ -22,12 +22,17 @@ class GroupMgr { - friend class ACE_Singleton<GroupMgr, ACE_Null_Mutex>; private: GroupMgr(); ~GroupMgr(); public: + static GroupMgr* instance() + { + static GroupMgr* instance = new GroupMgr(); + return instance; + } + typedef std::map<uint32, Group*> GroupContainer; typedef std::vector<Group*> GroupDbContainer; @@ -53,6 +58,6 @@ protected: GroupDbContainer GroupDbStore; }; -#define sGroupMgr ACE_Singleton<GroupMgr, ACE_Null_Mutex>::instance() +#define sGroupMgr GroupMgr::instance() #endif diff --git a/src/server/game/Guilds/GuildMgr.h b/src/server/game/Guilds/GuildMgr.h index e8e6acb1bf0..032a8864e3e 100644 --- a/src/server/game/Guilds/GuildMgr.h +++ b/src/server/game/Guilds/GuildMgr.h @@ -22,13 +22,17 @@ class GuildMgr { - friend class ACE_Singleton<GuildMgr, ACE_Null_Mutex>; - private: GuildMgr(); ~GuildMgr(); public: + static GuildMgr* instance() + { + static GuildMgr* instance = new GuildMgr(); + return instance; + } + Guild* GetGuildByLeader(uint64 guid) const; Guild* GetGuildById(uint32 guildId) const; Guild* GetGuildByName(std::string const& guildName) const; @@ -48,6 +52,6 @@ protected: GuildContainer GuildStore; }; -#define sGuildMgr ACE_Singleton<GuildMgr, ACE_Null_Mutex>::instance() +#define sGuildMgr GuildMgr::instance() #endif diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp index 806cbd1c7fc..8a00ddc22f4 100644 --- a/src/server/game/Handlers/AddonHandler.cpp +++ b/src/server/game/Handlers/AddonHandler.cpp @@ -22,10 +22,6 @@ #include "Opcodes.h" #include "Log.h" -AddonHandler::AddonHandler() { } - -AddonHandler::~AddonHandler() { } - bool AddonHandler::BuildAddonPacket(WorldPacket* source, WorldPacket* target) { ByteBuffer AddOnPacked; diff --git a/src/server/game/Handlers/AddonHandler.h b/src/server/game/Handlers/AddonHandler.h index 97a541753d0..31bbfa01900 100644 --- a/src/server/game/Handlers/AddonHandler.h +++ b/src/server/game/Handlers/AddonHandler.h @@ -21,20 +21,23 @@ #include "Common.h" #include "Config.h" -#include <ace/Singleton.h> #include "WorldPacket.h" class AddonHandler { - /* Construction */ - friend class ACE_Singleton<AddonHandler, ACE_Null_Mutex>; - AddonHandler(); - public: - ~AddonHandler(); - //build addon packet + static AddonHandler* instance() + { + static AddonHandler* instance = new AddonHandler(); + return instance; + } + bool BuildAddonPacket(WorldPacket* Source, WorldPacket* Target); + + private: + AddonHandler() { } + ~AddonHandler() { } }; -#define sAddOnHandler ACE_Singleton<AddonHandler, ACE_Null_Mutex>::instance() +#define sAddOnHandler AddonHandler::instance() #endif diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index c4ff2581e75..baa20f76a40 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -255,7 +255,8 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) data << uint32(matchcount); // placeholder, count of players matching criteria data << uint32(displaycount); // placeholder, count of players displayed - TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); + HashMapHolder<Player>::MapType const& m = sObjectAccessor->GetPlayers(); for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) { diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index 4f1b576cae6..98b37386a3f 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -19,12 +19,12 @@ #ifndef _INSTANCESAVEMGR_H #define _INSTANCESAVEMGR_H -#include "Define.h" -#include <ace/Singleton.h> -#include <ace/Thread_Mutex.h> #include <list> #include <map> +#include <mutex> #include <unordered_map> + +#include "Define.h" #include "DatabaseEnv.h" #include "DBCEnums.h" #include "ObjectDefines.h" @@ -80,13 +80,18 @@ class InstanceSave /* online players bound to the instance (perm/solo) does not include the members of the group unless they have permanent saves */ - void AddPlayer(Player* player) { TRINITY_GUARD(ACE_Thread_Mutex, _lock); m_playerList.push_back(player); } + void AddPlayer(Player* player) + { + std::lock_guard<std::mutex> lock(_playerListLock); + m_playerList.push_back(player); + } + bool RemovePlayer(Player* player) { - _lock.acquire(); + _playerListLock.lock(); m_playerList.remove(player); bool isStillValid = UnloadIfEmpty(); - _lock.release(); + _playerListLock.unlock(); //delete here if needed, after releasing the lock if (m_toDelete) @@ -137,14 +142,13 @@ class InstanceSave bool m_canReset; bool m_toDelete; - ACE_Thread_Mutex _lock; + std::mutex _playerListLock; }; typedef std::unordered_map<uint32 /*PAIR32(map, difficulty)*/, time_t /*resetTime*/> ResetTimeByMapDifficultyMap; class InstanceSaveManager { - friend class ACE_Singleton<InstanceSaveManager, ACE_Thread_Mutex>; friend class InstanceSave; private: @@ -154,6 +158,12 @@ class InstanceSaveManager public: typedef std::unordered_map<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap; + static InstanceSaveManager* instance() + { + static InstanceSaveManager *instance = new InstanceSaveManager(); + return instance; + } + /* resetTime is a global propery of each (raid/heroic) map all instances of that map reset at the same time */ struct InstResetEvent @@ -221,5 +231,5 @@ class InstanceSaveManager ResetTimeQueue m_resetTimeQueue; }; -#define sInstanceSaveMgr ACE_Singleton<InstanceSaveManager, ACE_Thread_Mutex>::instance() +#define sInstanceSaveMgr InstanceSaveManager::instance() #endif diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index a49e69ec311..bfb38a31248 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -387,7 +387,7 @@ void Map::DeleteFromWorld(Player* player) void Map::EnsureGridCreated(const GridCoord &p) { - TRINITY_GUARD(ACE_Thread_Mutex, GridLock); + std::lock_guard<std::mutex> lock(_gridLock); EnsureGridCreated_i(p); } @@ -2899,7 +2899,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) // Is it needed? { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapLock); // Check moved to void WorldSession::HandleMoveWorldportAckOpcode() //if (!CanEnter(player)) //return false; @@ -3240,7 +3240,7 @@ bool BattlegroundMap::CanEnter(Player* player) bool BattlegroundMap::AddPlayerToMap(Player* player) { { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapLock); //Check moved to void WorldSession::HandleMoveWorldportAckOpcode() //if (!CanEnter(player)) //return false; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index a2d88905f50..b431ca4ba17 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -20,8 +20,6 @@ #define TRINITY_MAP_H #include "Define.h" -#include <ace/RW_Thread_Mutex.h> -#include <ace/Thread_Mutex.h> #include "DBCStructure.h" #include "GridDefines.h" @@ -574,8 +572,8 @@ class Map : public GridRefManager<NGridType> protected: void SetUnloadReferenceLock(const GridCoord &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } - ACE_Thread_Mutex Lock; - ACE_Thread_Mutex GridLock; + std::mutex _mapLock; + std::mutex _gridLock; MapEntry const* i_mapEntry; uint8 i_spawnMode; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index e914a5c3eee..498c669ba01 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -187,7 +187,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty) { // load/create a map - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapLock); // make sure we have a valid map id const MapEntry* entry = sMapStore.LookupEntry(GetId()); @@ -223,7 +223,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battleground* bg) { // load/create a map - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapLock); TC_LOG_DEBUG("maps", "MapInstanced::CreateBattleground: map bg %d for %d created.", InstanceId, GetId()); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 0b8c6401d89..9c023b86bc9 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -52,8 +52,8 @@ void MapManager::Initialize() int num_threads(sWorld->getIntConfig(CONFIG_NUMTHREADS)); // Start mtmaps if needed. - if (num_threads > 0 && m_updater.activate(num_threads) == -1) - abort(); + if (num_threads > 0) + m_updater.activate(num_threads); } void MapManager::InitializeVisibilityDistanceInfo() @@ -68,7 +68,7 @@ Map* MapManager::CreateBaseMap(uint32 id) if (map == NULL) { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapsLock); MapEntry const* entry = sMapStore.LookupEntry(id); ASSERT(entry); @@ -296,7 +296,7 @@ void MapManager::UnloadAll() uint32 MapManager::GetNumInstances() { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapsLock); uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) @@ -313,7 +313,7 @@ uint32 MapManager::GetNumInstances() uint32 MapManager::GetNumPlayersInInstances() { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + std::lock_guard<std::mutex> lock(_mapsLock); uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index b7fb0617a46..990d5e80c1a 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -24,18 +24,18 @@ #include "GridStates.h" #include "MapUpdater.h" -#include <ace/Singleton.h> -#include <ace/Thread_Mutex.h> - - class Transport; struct TransportCreatureProto; class MapManager { - friend class ACE_Singleton<MapManager, ACE_Thread_Mutex>; - public: + static MapManager* instance() + { + static MapManager* instance = new MapManager(); + return instance; + } + Map* CreateBaseMap(uint32 mapId); Map* FindBaseNonInstanceMap(uint32 mapId) const; Map* CreateMap(uint32 mapId, Player* player); @@ -141,7 +141,7 @@ class MapManager MapManager(const MapManager &); MapManager& operator=(const MapManager &); - ACE_Thread_Mutex Lock; + std::mutex _mapsLock; uint32 i_gridCleanUpDelay; MapMapType i_maps; IntervalTimer i_timer; @@ -150,5 +150,5 @@ class MapManager uint32 _nextInstanceId; MapUpdater m_updater; }; -#define sMapMgr ACE_Singleton<MapManager, ACE_Thread_Mutex>::instance() +#define sMapMgr MapManager::instance() #endif diff --git a/src/server/game/Maps/MapUpdater.cpp b/src/server/game/Maps/MapUpdater.cpp index dd697719d54..c456f57bd20 100644 --- a/src/server/game/Maps/MapUpdater.cpp +++ b/src/server/game/Maps/MapUpdater.cpp @@ -1,97 +1,125 @@ +/* +* 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 +* 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 <mutex> +#include <condition_variable> + #include "MapUpdater.h" -#include "DelayExecutor.h" #include "Map.h" -#include "DatabaseEnv.h" -#include <ace/Guard_T.h> -#include <ace/Method_Request.h> -class MapUpdateRequest : public ACE_Method_Request +class MapUpdateRequest { private: Map& m_map; MapUpdater& m_updater; - ACE_UINT32 m_diff; + uint32 m_diff; public: - MapUpdateRequest(Map& m, MapUpdater& u, ACE_UINT32 d) + MapUpdateRequest(Map& m, MapUpdater& u, uint32 d) : m_map(m), m_updater(u), m_diff(d) { } - virtual int call() + void call() { m_map.Update (m_diff); m_updater.update_finished(); - return 0; } }; -MapUpdater::MapUpdater(): -m_executor(), m_mutex(), m_condition(m_mutex), pending_requests(0) { } +MapUpdater::MapUpdater() : _cancelationToken(false), pending_requests(0) {} MapUpdater::~MapUpdater() { deactivate(); } -int MapUpdater::activate(size_t num_threads) +void MapUpdater::activate(size_t num_threads) { - return m_executor.start((int)num_threads); + for (size_t i = 0; i < num_threads; ++i) + { + _workerThreads.push_back(std::thread(&MapUpdater::WorkerThread, this)); + } } -int MapUpdater::deactivate() +void MapUpdater::deactivate() { + _cancelationToken = true; + wait(); - return m_executor.deactivate(); + _queue.Cancel(); + + for (auto& thread : _workerThreads) + { + thread.join(); + } } -int MapUpdater::wait() +void MapUpdater::wait() { - TRINITY_GUARD(ACE_Thread_Mutex, m_mutex); + std::unique_lock<std::mutex> lock(_lock); while (pending_requests > 0) - m_condition.wait(); + _condition.wait(lock); - return 0; + lock.unlock(); } -int MapUpdater::schedule_update(Map& map, ACE_UINT32 diff) +void MapUpdater::schedule_update(Map& map, uint32 diff) { - TRINITY_GUARD(ACE_Thread_Mutex, m_mutex); + std::lock_guard<std::mutex> lock(_lock); ++pending_requests; - if (m_executor.execute(new MapUpdateRequest(map, *this, diff)) == -1) - { - ACE_DEBUG((LM_ERROR, ACE_TEXT("(%t) \n"), ACE_TEXT("Failed to schedule Map Update"))); - - --pending_requests; - return -1; - } - - return 0; + _queue.Push(new MapUpdateRequest(map, *this, diff)); } bool MapUpdater::activated() { - return m_executor.activated(); + return _workerThreads.size() > 0; } void MapUpdater::update_finished() { - TRINITY_GUARD(ACE_Thread_Mutex, m_mutex); + std::lock_guard<std::mutex> lock(_lock); - if (pending_requests == 0) + --pending_requests; + + _condition.notify_all(); +} + +void MapUpdater::WorkerThread() +{ + while (1) { - ACE_ERROR((LM_ERROR, ACE_TEXT("(%t)\n"), ACE_TEXT("MapUpdater::update_finished BUG, report to devs"))); - return; - } + MapUpdateRequest* request = nullptr; - --pending_requests; + _queue.WaitAndPop(request); + + if (_cancelationToken) + return; - m_condition.broadcast(); + request->call(); + + delete request; + } } diff --git a/src/server/game/Maps/MapUpdater.h b/src/server/game/Maps/MapUpdater.h index 89798026339..c499110173e 100644 --- a/src/server/game/Maps/MapUpdater.h +++ b/src/server/game/Maps/MapUpdater.h @@ -1,11 +1,31 @@ +/* +* 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 +* 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 _MAP_UPDATER_H_INCLUDED #define _MAP_UPDATER_H_INCLUDED -#include <ace/Thread_Mutex.h> -#include <ace/Condition_Thread_Mutex.h> - -#include "DelayExecutor.h" +#include "Define.h" +#include <mutex> +#include <thread> +#include <condition_variable> +#include "ProducerConsumerQueue.h" +class MapUpdateRequest; class Map; class MapUpdater @@ -17,24 +37,30 @@ class MapUpdater friend class MapUpdateRequest; - int schedule_update(Map& map, ACE_UINT32 diff); + void schedule_update(Map& map, uint32 diff); - int wait(); + void wait(); - int activate(size_t num_threads); + void activate(size_t num_threads); - int deactivate(); + void deactivate(); bool activated(); private: - DelayExecutor m_executor; - ACE_Thread_Mutex m_mutex; - ACE_Condition_Thread_Mutex m_condition; + ProducerConsumerQueue<MapUpdateRequest*> _queue; + + std::vector<std::thread> _workerThreads; + std::atomic<bool> _cancelationToken; + + std::mutex _lock; + std::condition_variable _condition; size_t pending_requests; void update_finished(); + + void WorkerThread(); }; #endif //_MAP_UPDATER_H_INCLUDED diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 5da856b185c..6ebc6316710 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -18,7 +18,6 @@ #ifndef TRANSPORTMGR_H #define TRANSPORTMGR_H -#include <ace/Singleton.h> #include <G3D/Quat.h> #include "Spline.h" #include "DBCStores.h" @@ -96,10 +95,15 @@ typedef std::map<uint32, TransportAnimation> TransportAnimationContainer; class TransportMgr { - friend class ACE_Singleton<TransportMgr, ACE_Thread_Mutex>; friend void LoadDBCStores(std::string const&); public: + static TransportMgr* instance() + { + static TransportMgr* instance = new TransportMgr(); + return instance; + } + void Unload(); void LoadTransportTemplates(); @@ -155,6 +159,6 @@ class TransportMgr TransportAnimationContainer _transportAnimations; }; -#define sTransportMgr ACE_Singleton<TransportMgr, ACE_Thread_Mutex>::instance() +#define sTransportMgr TransportMgr::instance() #endif // TRANSPORTMGR_H diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index f545f9fd314..12116b5505d 100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -20,7 +20,6 @@ #define TRINITY_MOVEMENTGENERATOR_H #include "Define.h" -#include <ace/Singleton.h> #include "ObjectRegistry.h" #include "FactoryHolder.h" #include "Common.h" @@ -92,5 +91,4 @@ struct MovementGeneratorFactory : public SelectableMovement typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGeneratorCreator; typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry; -typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRepository MovementGeneratorRepository; #endif diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index bafc6322e71..b12396293aa 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -19,8 +19,6 @@ #ifndef TRINITY_WAYPOINTMANAGER_H #define TRINITY_WAYPOINTMANAGER_H -#include <ace/Singleton.h> -#include <ace/Null_Mutex.h> #include <vector> struct WaypointData @@ -38,9 +36,13 @@ typedef std::unordered_map<uint32, WaypointPath> WaypointPathContainer; class WaypointMgr { - friend class ACE_Singleton<WaypointMgr, ACE_Null_Mutex>; - public: + static WaypointMgr* instance() + { + static WaypointMgr* instance = new WaypointMgr(); + return instance; + } + // Attempts to reload a single path from database void ReloadPath(uint32 id); @@ -58,13 +60,12 @@ class WaypointMgr } private: - // Only allow instantiation from ACE_Singleton WaypointMgr(); ~WaypointMgr(); WaypointPathContainer _waypointStore; }; -#define sWaypointMgr ACE_Singleton<WaypointMgr, ACE_Null_Mutex>::instance() +#define sWaypointMgr WaypointMgr::instance() #endif diff --git a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h index 54ea2f3ba1d..ab1908e273d 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvPMgr.h +++ b/src/server/game/OutdoorPvP/OutdoorPvPMgr.h @@ -21,7 +21,6 @@ #define OUTDOORPVP_OBJECTIVE_UPDATE_INTERVAL 1000 #include "OutdoorPvP.h" -#include <ace/Singleton.h> class Player; class GameObject; @@ -38,13 +37,17 @@ struct OutdoorPvPData // class to handle player enter / leave / areatrigger / GO use events class OutdoorPvPMgr { - friend class ACE_Singleton<OutdoorPvPMgr, ACE_Null_Mutex>; - private: OutdoorPvPMgr(); ~OutdoorPvPMgr() { }; public: + static OutdoorPvPMgr* instance() + { + static OutdoorPvPMgr* instance = new OutdoorPvPMgr(); + return instance; + } + // create outdoor pvp events void InitOutdoorPvP(); @@ -101,6 +104,6 @@ class OutdoorPvPMgr uint32 m_UpdateTimer; }; -#define sOutdoorPvPMgr ACE_Singleton<OutdoorPvPMgr, ACE_Null_Mutex>::instance() +#define sOutdoorPvPMgr OutdoorPvPMgr::instance() #endif /*OUTDOOR_PVP_MGR_H_*/ diff --git a/src/server/game/Pools/PoolMgr.h b/src/server/game/Pools/PoolMgr.h index 2bc404b3a36..0a3f52b55f6 100644 --- a/src/server/game/Pools/PoolMgr.h +++ b/src/server/game/Pools/PoolMgr.h @@ -20,7 +20,6 @@ #define TRINITY_POOLHANDLER_H #include "Define.h" -#include <ace/Singleton.h> #include "Creature.h" #include "GameObject.h" #include "QuestDef.h" @@ -104,13 +103,17 @@ typedef std::pair<PooledQuestRelation::iterator, PooledQuestRelation::iterator> class PoolMgr { - friend class ACE_Singleton<PoolMgr, ACE_Null_Mutex>; - private: PoolMgr(); ~PoolMgr() { }; public: + static PoolMgr* instance() + { + static PoolMgr* instance = new PoolMgr(); + return instance; + } + void LoadFromDB(); void LoadQuestPools(); void SaveQuestsToDB(); @@ -164,7 +167,7 @@ class PoolMgr ActivePoolData mSpawnedData; }; -#define sPoolMgr ACE_Singleton<PoolMgr, ACE_Null_Mutex>::instance() +#define sPoolMgr PoolMgr::instance() // Method that tell if the creature is part of a pool and return the pool id if yes template<> diff --git a/src/server/game/PrecompiledHeaders/gamePCH.h b/src/server/game/PrecompiledHeaders/gamePCH.h index 68f628430c4..c7c6ca5d2d6 100644 --- a/src/server/game/PrecompiledHeaders/gamePCH.h +++ b/src/server/game/PrecompiledHeaders/gamePCH.h @@ -1,9 +1,6 @@ //add here most rarely modified headers to speed up debug build compilation -#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it - #include "Common.h" - #include "MapManager.h" #include "Log.h" #include "ObjectAccessor.h" diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 83f401d4e79..1b91ed1690c 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -175,8 +175,10 @@ struct TSpellSummary uint8 Effects; // set of enum SelectEffect } *SpellSummary; -ScriptMgr::ScriptMgr() - : _scriptCount(0), _scheduledScripts(0) { } +ScriptMgr::ScriptMgr() : _scriptCount(0) +{ + _scheduledScripts = 0; +} ScriptMgr::~ScriptMgr() { } @@ -398,35 +400,35 @@ void ScriptMgr::OnNetworkStop() FOREACH_SCRIPT(ServerScript)->OnNetworkStop(); } -void ScriptMgr::OnSocketOpen(WorldSocket* socket) +void ScriptMgr::OnSocketOpen(std::shared_ptr<WorldSocket> socket) { ASSERT(socket); FOREACH_SCRIPT(ServerScript)->OnSocketOpen(socket); } -void ScriptMgr::OnSocketClose(WorldSocket* socket, bool wasNew) +void ScriptMgr::OnSocketClose(std::shared_ptr<WorldSocket> socket, bool wasNew) { ASSERT(socket); FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket, wasNew); } -void ScriptMgr::OnPacketReceive(WorldSocket* socket, WorldPacket packet) +void ScriptMgr::OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet) { ASSERT(socket); FOREACH_SCRIPT(ServerScript)->OnPacketReceive(socket, packet); } -void ScriptMgr::OnPacketSend(WorldSocket* socket, WorldPacket packet) +void ScriptMgr::OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket packet) { ASSERT(socket); FOREACH_SCRIPT(ServerScript)->OnPacketSend(socket, packet); } -void ScriptMgr::OnUnknownPacketReceive(WorldSocket* socket, WorldPacket packet) +void ScriptMgr::OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet) { ASSERT(socket); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index ee95759c72e..260c43f9b3b 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -19,10 +19,8 @@ #ifndef SC_SCRIPTMGR_H #define SC_SCRIPTMGR_H +#include <atomic> #include "Common.h" -#include <ace/Singleton.h> -#include <ace/Atomic_Op.h> - #include "DBCStores.h" #include "QuestDef.h" #include "SharedDefines.h" @@ -216,30 +214,30 @@ class ServerScript : public ScriptObject public: - // Called when reactive socket I/O is started (WorldSocketMgr). + // Called when reactive socket I/O is started (WorldTcpSessionMgr). virtual void OnNetworkStart() { } // Called when reactive I/O is stopped. virtual void OnNetworkStop() { } // Called when a remote socket establishes a connection to the server. Do not store the socket object. - virtual void OnSocketOpen(WorldSocket* /*socket*/) { } + virtual void OnSocketOpen(std::shared_ptr<WorldSocket> /*socket*/) { } // Called when a socket is closed. Do not store the socket object, and do not rely on the connection // being open; it is not. - virtual void OnSocketClose(WorldSocket* /*socket*/, bool /*wasNew*/) { } + virtual void OnSocketClose(std::shared_ptr<WorldSocket> /*socket*/, bool /*wasNew*/) { } // Called when a packet is sent to a client. The packet object is a copy of the original packet, so reading // and modifying it is safe. - virtual void OnPacketSend(WorldSocket* /*socket*/, WorldPacket& /*packet*/) { } + virtual void OnPacketSend(std::shared_ptr<WorldSocket> /*socket*/, WorldPacket& /*packet*/) { } // Called when a (valid) packet is received by a client. The packet object is a copy of the original packet, so // reading and modifying it is safe. - virtual void OnPacketReceive(WorldSocket* /*socket*/, WorldPacket& /*packet*/) { } + virtual void OnPacketReceive(std::shared_ptr<WorldSocket> /*socket*/, WorldPacket& /*packet*/) { } // Called when an invalid (unknown opcode) packet is received by a client. The packet is a reference to the orignal // packet; not a copy. This allows you to actually handle unknown packets (for whatever purpose). - virtual void OnUnknownPacketReceive(WorldSocket* /*socket*/, WorldPacket& /*packet*/) { } + virtual void OnUnknownPacketReceive(std::shared_ptr<WorldSocket> /*socket*/, WorldPacket& /*packet*/) { } }; class WorldScript : public ScriptObject @@ -869,20 +867,23 @@ class GroupScript : public ScriptObject }; // Placed here due to ScriptRegistry::AddScript dependency. -#define sScriptMgr ACE_Singleton<ScriptMgr, ACE_Null_Mutex>::instance() +#define sScriptMgr ScriptMgr::instance() // Manages registration, loading, and execution of scripts. class ScriptMgr { - friend class ACE_Singleton<ScriptMgr, ACE_Null_Mutex>; friend class ScriptObject; private: - ScriptMgr(); virtual ~ScriptMgr(); public: /* Initialization */ + static ScriptMgr* instance() + { + static ScriptMgr* instance = new ScriptMgr(); + return instance; + } void Initialize(); void LoadDatabase(); @@ -907,11 +908,11 @@ class ScriptMgr void OnNetworkStart(); void OnNetworkStop(); - void OnSocketOpen(WorldSocket* socket); - void OnSocketClose(WorldSocket* socket, bool wasNew); - void OnPacketReceive(WorldSocket* socket, WorldPacket packet); - void OnPacketSend(WorldSocket* socket, WorldPacket packet); - void OnUnknownPacketReceive(WorldSocket* socket, WorldPacket packet); + void OnSocketOpen(std::shared_ptr<WorldSocket> socket); + void OnSocketClose(std::shared_ptr<WorldSocket> socket, bool wasNew); + void OnPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet); + void OnPacketSend(std::shared_ptr<WorldSocket> socket, WorldPacket packet); + void OnUnknownPacketReceive(std::shared_ptr<WorldSocket> socket, WorldPacket packet); public: /* WorldScript */ @@ -1126,7 +1127,7 @@ class ScriptMgr uint32 _scriptCount; //atomic op counter for active scripts amount - ACE_Atomic_Op<ACE_Thread_Mutex, long> _scheduledScripts; + std::atomic_long _scheduledScripts; }; #endif diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h index 11120f3031b..636343838c1 100644 --- a/src/server/game/Scripting/ScriptSystem.h +++ b/src/server/game/Scripting/ScriptSystem.h @@ -6,7 +6,6 @@ #define SC_SYSTEM_H #include "ScriptMgr.h" -#include <ace/Singleton.h> #define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available @@ -48,11 +47,17 @@ typedef std::vector<ScriptPointMove> ScriptPointVector; class SystemMgr { - friend class ACE_Singleton<SystemMgr, ACE_Null_Mutex>; + private: SystemMgr() { } ~SystemMgr() { } public: + static SystemMgr* instance() + { + static SystemMgr* instance = new SystemMgr(); + return instance; + } + typedef std::unordered_map<uint32, ScriptPointVector> PointMoveMap; //Database @@ -75,6 +80,6 @@ class SystemMgr static ScriptPointVector const _empty; }; -#define sScriptSystemMgr ACE_Singleton<SystemMgr, ACE_Null_Mutex>::instance() +#define sScriptSystemMgr SystemMgr::instance() #endif diff --git a/src/server/game/Server/Protocol/PacketLog.h b/src/server/game/Server/Protocol/PacketLog.h index 9c60655e627..71d87bf45ae 100644 --- a/src/server/game/Server/Protocol/PacketLog.h +++ b/src/server/game/Server/Protocol/PacketLog.h @@ -19,7 +19,6 @@ #define TRINITY_PACKETLOG_H #include "Common.h" -#include <ace/Singleton.h> enum Direction { @@ -31,13 +30,17 @@ class WorldPacket; class PacketLog { - friend class ACE_Singleton<PacketLog, ACE_Thread_Mutex>; - private: PacketLog(); ~PacketLog(); public: + static PacketLog* instance() + { + static PacketLog* instance = new PacketLog(); + return instance; + } + void Initialize(); bool CanLogPacket() const { return (_file != NULL); } void LogPacket(WorldPacket const& packet, Direction direction); @@ -46,5 +49,5 @@ class PacketLog FILE* _file; }; -#define sPacketLog ACE_Singleton<PacketLog, ACE_Thread_Mutex>::instance() +#define sPacketLog PacketLog::instance() #endif diff --git a/src/server/game/Server/Protocol/ServerPktHeader.h b/src/server/game/Server/Protocol/ServerPktHeader.h new file mode 100644 index 00000000000..4b0dae9f0f3 --- /dev/null +++ b/src/server/game/Server/Protocol/ServerPktHeader.h @@ -0,0 +1,59 @@ +/* +* 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 +* 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 __SERVERPKTHDR_H__ +#define __SERVERPKTHDR_H__ + +#include "Log.h" + +struct ServerPktHeader +{ + /** + * size is the length of the payload _plus_ the length of the opcode + */ + ServerPktHeader(uint32 size, uint16 cmd) : size(size) + { + uint8 headerIndex=0; + if (isLargePacket()) + { + TC_LOG_DEBUG("network", "initializing large server to client packet. Size: %u, cmd: %u", size, cmd); + header[headerIndex++] = 0x80 | (0xFF & (size >> 16)); + } + header[headerIndex++] = 0xFF &(size >> 8); + header[headerIndex++] = 0xFF & size; + + header[headerIndex++] = 0xFF & cmd; + header[headerIndex++] = 0xFF & (cmd >> 8); + } + + uint8 getHeaderLength() + { + // cmd = 2 bytes, size= 2||3bytes + return 2 + (isLargePacket() ? 3 : 2); + } + + bool isLargePacket() const + { + return size > 0x7FFF; + } + + const uint32 size; + uint8 header[5]; +}; + +#endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 9f8b3785e92..f30991b385e 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -20,7 +20,7 @@ \ingroup u2w */ -#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it +#include "WorldSocket.h" #include "Config.h" #include "Common.h" #include "DatabaseEnv.h" @@ -97,7 +97,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) } /// WorldSession constructor -WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): +WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -130,8 +130,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 if (sock) { - m_Address = sock->GetRemoteAddress(); - sock->AddReference(); + m_Address = sock->GetRemoteIpAddress(); ResetTimeOutTime(); LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query } @@ -150,8 +149,7 @@ WorldSession::~WorldSession() if (m_Socket) { m_Socket->CloseSocket(); - m_Socket->RemoveReference(); - m_Socket = NULL; + m_Socket = nullptr; } delete _warden; @@ -227,8 +225,7 @@ void WorldSession::SendPacket(WorldPacket const* packet) } #endif // !TRINITY_DEBUG - if (m_Socket->SendPacket(*packet) == -1) - m_Socket->CloseSocket(); + m_Socket->AsyncWrite(*packet); } /// Add an incoming packet to the queue @@ -281,9 +278,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) uint32 processedPackets = 0; time_t currentTime = time(NULL); - while (m_Socket && !m_Socket->IsClosed() && - !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && - _recvQueue.next(packet, updater)) + while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) { @@ -297,7 +292,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) } else { - OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; + OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) @@ -402,7 +397,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } - if (m_Socket && !m_Socket->IsClosed() && _warden) + if (m_Socket && m_Socket->IsOpen() && _warden) _warden->Update(); ProcessQueryCallbacks(); @@ -420,13 +415,12 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) _warden->Update(); ///- Cleanup socket pointer if need - if (m_Socket && m_Socket->IsClosed()) + if (m_Socket && !m_Socket->IsOpen()) { expireTime -= expireTime > diff ? diff : expireTime; if (expireTime < diff || forceExit) { - m_Socket->RemoveReference(); - m_Socket = NULL; + m_Socket = nullptr; } } @@ -780,7 +774,7 @@ void WorldSession::SaveTutorialsData(SQLTransaction &trans) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_HAS_TUTORIALS); stmt->setUInt32(0, GetAccountId()); - bool hasTutorials = !CharacterDatabase.Query(stmt).null(); + bool hasTutorials = bool(CharacterDatabase.Query(stmt)); // Modify data in DB stmt = CharacterDatabase.GetPreparedStatement(hasTutorials ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS); for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i) @@ -1105,27 +1099,23 @@ void WorldSession::ProcessQueryCallbacks() PreparedQueryResult result; //! HandleCharEnumOpcode - if (_charEnumCallback.ready()) + if (_charEnumCallback.valid() && _charEnumCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - _charEnumCallback.get(result); + result = _charEnumCallback.get(); HandleCharEnum(result); - _charEnumCallback.cancel(); } if (_charCreateCallback.IsReady()) { _charCreateCallback.GetResult(result); HandleCharCreateCallback(result, _charCreateCallback.GetParam()); - // Don't call FreeResult() here, the callback handler will do that depending on the events in the callback chain } //! HandlePlayerLoginOpcode - if (_charLoginCallback.ready()) + if (_charLoginCallback.valid() && _charLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - SQLQueryHolder* param; - _charLoginCallback.get(param); + SQLQueryHolder* param = _charLoginCallback.get(); HandlePlayerLogin((LoginQueryHolder*)param); - _charLoginCallback.cancel(); } //! HandleAddFriendOpcode @@ -1147,11 +1137,10 @@ void WorldSession::ProcessQueryCallbacks() } //- HandleCharAddIgnoreOpcode - if (_addIgnoreCallback.ready()) + if (_addIgnoreCallback.valid() && _addIgnoreCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - _addIgnoreCallback.get(result); + result = _addIgnoreCallback.get(); HandleAddIgnoreOpcodeCallBack(result); - _addIgnoreCallback.cancel(); } //- SendStabledPet @@ -1164,11 +1153,10 @@ void WorldSession::ProcessQueryCallbacks() } //- HandleStablePet - if (_stablePetCallback.ready()) + if (_stablePetCallback.valid() && _stablePetCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - _stablePetCallback.get(result); + result = _stablePetCallback.get(); HandleStablePetCallback(result); - _stablePetCallback.cancel(); } //- HandleUnstablePet diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index c8c81a415e1..7ad43907355 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -208,7 +208,7 @@ struct PacketCounter class WorldSession { public: - WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return m_playerLoading; } @@ -372,10 +372,11 @@ class WorldSession void SetLatency(uint32 latency) { m_latency = latency; } void ResetClientTimeDelay() { m_clientTimeDelay = 0; } - ACE_Atomic_Op<ACE_Thread_Mutex, time_t> m_timeOutTime; + std::atomic<time_t> m_timeOutTime; + void UpdateTimeOutTime(uint32 diff) { - if (time_t(diff) > m_timeOutTime.value()) + if (time_t(diff) > m_timeOutTime) m_timeOutTime = 0; else m_timeOutTime -= diff; @@ -980,7 +981,7 @@ class WorldSession uint32 m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set) Player* _player; - WorldSocket* m_Socket; + std::shared_ptr<WorldSocket> m_Socket; std::string m_Address; // Current Remote Address // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session! @@ -1001,15 +1002,15 @@ class WorldSession bool m_playerSave; LocaleConstant m_sessionDbcLocale; LocaleConstant m_sessionDbLocaleIndex; - uint32 m_latency; - uint32 m_clientTimeDelay; + std::atomic<uint32> m_latency; + std::atomic<uint32> m_clientTimeDelay; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; bool m_TutorialsChanged; AddonsList m_addonsList; uint32 recruiterId; bool isRecruiter; - ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; + LockedQueue<WorldPacket*> _recvQueue; rbac::RBACData* _RBACData; uint32 expireTime; bool forceExit; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index d35ee80099d..bbb86cf3d2f 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -1,750 +1,186 @@ /* - * 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 - * 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 <ace/Message_Block.h> -#include <ace/OS_NS_string.h> -#include <ace/OS_NS_unistd.h> -#include <ace/os_include/arpa/os_inet.h> -#include <ace/os_include/netinet/os_tcp.h> -#include <ace/os_include/sys/os_types.h> -#include <ace/os_include/sys/os_socket.h> -#include <ace/OS_NS_string.h> -#include <ace/Reactor.h> -#include <ace/Auto_Ptr.h> - +* 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 +* 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 <boost/asio/write.hpp> +#include <boost/asio/read_until.hpp> +#include <memory> #include "WorldSocket.h" -#include "Common.h" -#include "Player.h" -#include "Util.h" -#include "World.h" -#include "WorldPacket.h" -#include "SharedDefines.h" -#include "ByteBuffer.h" -#include "Opcodes.h" -#include "DatabaseEnv.h" +#include "ServerPktHeader.h" #include "BigNumber.h" -#include "SHA1.h" -#include "WorldSession.h" -#include "WorldSocketMgr.h" -#include "Log.h" -#include "PacketLog.h" +#include "Opcodes.h" #include "ScriptMgr.h" -#include "AccountMgr.h" - -#if defined(__GNUC__) -#pragma pack(1) -#else -#pragma pack(push, 1) -#endif - -struct ServerPktHeader -{ - /** - * size is the length of the payload _plus_ the length of the opcode - */ - ServerPktHeader(uint32 size, uint16 cmd) : size(size) - { - uint8 headerIndex=0; - if (isLargePacket()) - { - TC_LOG_DEBUG("network", "initializing large server to client packet. Size: %u, cmd: %u", size, cmd); - header[headerIndex++] = 0x80 | (0xFF & (size >> 16)); - } - header[headerIndex++] = 0xFF &(size >> 8); - header[headerIndex++] = 0xFF & size; - - header[headerIndex++] = 0xFF & cmd; - header[headerIndex++] = 0xFF & (cmd >> 8); - } - - uint8 getHeaderLength() - { - // cmd = 2 bytes, size= 2||3bytes - return 2 + (isLargePacket() ? 3 : 2); - } - - bool isLargePacket() const - { - return size > 0x7FFF; - } +#include "SHA1.h" - const uint32 size; - uint8 header[5]; -}; +using boost::asio::ip::tcp; +using boost::asio::streambuf; -struct ClientPktHeader -{ - uint16 size; - uint32 cmd; -}; - -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -WorldSocket::WorldSocket (void): WorldHandler(), -m_LastPingTime(ACE_Time_Value::zero), m_OverSpeedPings(0), m_Session(0), -m_RecvWPct(0), m_RecvPct(), m_Header(sizeof (ClientPktHeader)), -m_OutBuffer(0), m_OutBufferSize(65536), m_OutActive(false), -m_Seed(static_cast<uint32> (rand32())) +WorldSocket::WorldSocket(tcp::socket&& socket) + : _socket(std::move(socket)), _authSeed(static_cast<uint32>(rand32())), _OverSpeedPings(0), _worldSession(nullptr) { - reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); - - msg_queue()->high_water_mark(8 * 1024 * 1024); - msg_queue()->low_water_mark(8 * 1024 * 1024); -} - -WorldSocket::~WorldSocket (void) -{ - delete m_RecvWPct; - - if (m_OutBuffer) - m_OutBuffer->release(); - - closing_ = true; - - peer().close(); } -bool WorldSocket::IsClosed (void) const +void WorldSocket::Start() { - return closing_; + AsyncReadHeader(); + HandleSendAuthSession(); } -void WorldSocket::CloseSocket (void) +void WorldSocket::HandleSendAuthSession() { - { - ACE_GUARD (LockType, Guard, m_OutBufferLock); - - if (closing_) - return; - - closing_ = true; - peer().close_writer(); - } + WorldPacket packet(SMSG_AUTH_CHALLENGE, 37); + packet << uint32(1); // 1...31 + packet << uint32(_authSeed); - { - ACE_GUARD (LockType, Guard, m_SessionLock); + BigNumber seed1; + seed1.SetRand(16 * 8); + packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds - m_Session = NULL; - } + BigNumber seed2; + seed2.SetRand(16 * 8); + packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds + + AsyncWrite(packet); } -const std::string& WorldSocket::GetRemoteAddress (void) const -{ - return m_Address; -} -int WorldSocket::SendPacket(WorldPacket const& pct) +void WorldSocket::AsyncReadHeader() { - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - if (closing_) - return -1; - - // Dump outgoing packet - if (sPacketLog->CanLogPacket()) - sPacketLog->LogPacket(pct, SERVER_TO_CLIENT); - - WorldPacket const* pkt = &pct; - - - if (m_Session) - TC_LOG_TRACE("network.opcode", "S->C: %s %s", m_Session->GetPlayerInfo().c_str(), GetOpcodeNameForLogging(pkt->GetOpcode()).c_str()); - - sScriptMgr->OnPacketSend(this, *pkt); - - ServerPktHeader header(pkt->size()+2, pkt->GetOpcode()); - m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); - - if (m_OutBuffer->space() >= pkt->size() + header.getHeaderLength() && msg_queue()->is_empty()) - { - // Put the packet on the buffer. - if (m_OutBuffer->copy((char*) header.header, header.getHeaderLength()) == -1) - ACE_ASSERT (false); - - if (!pkt->empty()) - if (m_OutBuffer->copy((char*) pkt->contents(), pkt->size()) == -1) - ACE_ASSERT (false); - } - else + auto self(shared_from_this()); + _socket.async_read_some(boost::asio::buffer(_readBuffer, sizeof(ClientPktHeader)), [this, self](boost::system::error_code error, size_t transferedBytes) { - // Enqueue the packet. - ACE_Message_Block* mb; - - ACE_NEW_RETURN(mb, ACE_Message_Block(pkt->size() + header.getHeaderLength()), -1); - - mb->copy((char*) header.header, header.getHeaderLength()); - - if (!pkt->empty()) - mb->copy((const char*)pkt->contents(), pkt->size()); - - if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) + if (!error && transferedBytes == sizeof(ClientPktHeader)) { - TC_LOG_ERROR("network", "WorldSocket::SendPacket enqueue_tail failed"); - mb->release(); - return -1; - } - } - - return 0; -} - -long WorldSocket::AddReference (void) -{ - return static_cast<long> (add_reference()); -} - -long WorldSocket::RemoveReference (void) -{ - return static_cast<long> (remove_reference()); -} - -int WorldSocket::open (void *a) -{ - ACE_UNUSED_ARG (a); + ClientPktHeader* header = (ClientPktHeader*)&_readBuffer; - // Prevent double call to this func. - if (m_OutBuffer) - return -1; + if (_worldSession) + _authCrypt.DecryptRecv((uint8*)header, sizeof(ClientPktHeader)); - // This will also prevent the socket from being Updated - // while we are initializing it. - m_OutActive = true; + EndianConvertReverse(header->size); + EndianConvert(header->cmd); - // Hook for the manager. - if (sWorldSocketMgr->OnSocketOpen(this) == -1) - return -1; - - // Allocate the buffer. - ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); - - // Store peer address. - ACE_INET_Addr remote_addr; - - if (peer().get_remote_addr(remote_addr) == -1) - { - TC_LOG_ERROR("network", "WorldSocket::open: peer().get_remote_addr errno = %s", ACE_OS::strerror (errno)); - return -1; - } - - m_Address = remote_addr.get_host_addr(); - - if (HandleSendAuthSession() == -1) - return -1; - - // Register with ACE Reactor - if (reactor()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) - { - TC_LOG_ERROR("network", "WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); - return -1; - } - - // reactor takes care of the socket from now on - remove_reference(); - - return 0; -} - -int WorldSocket::close(u_long) -{ - shutdown(); - - closing_ = true; - - remove_reference(); - - return 0; -} - -int WorldSocket::handle_input(ACE_HANDLE) -{ - if (closing_) - return -1; - - switch (handle_input_missing_data()) - { - case -1 : - { - if ((errno == EWOULDBLOCK) || - (errno == EAGAIN)) - { - return Update(); // interesting line, isn't it ? - } - - TC_LOG_DEBUG("network", "WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); - - errno = ECONNRESET; - return -1; + AsyncReadData(header->size - sizeof(header->cmd)); } - case 0: + else { - TC_LOG_DEBUG("network", "WorldSocket::handle_input: Peer has closed connection"); - - errno = ECONNRESET; - return -1; + _socket.close(); } - case 1: - return 1; - default: - return Update(); // another interesting line ;) - } - - ACE_NOTREACHED(return -1); -} - -int WorldSocket::handle_output(ACE_HANDLE) -{ - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - if (closing_) - return -1; - - size_t send_len = m_OutBuffer->length(); - - if (send_len == 0) - return handle_output_queue(Guard); - -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send (m_OutBuffer->rd_ptr(), send_len); -#endif // MSG_NOSIGNAL - - if (n == 0) - return -1; - else if (n == -1) - { - if (errno == EWOULDBLOCK || errno == EAGAIN) - return schedule_wakeup_output (Guard); - - return -1; - } - else if (n < (ssize_t)send_len) //now n > 0 - { - m_OutBuffer->rd_ptr (static_cast<size_t> (n)); - - // move the data to the base of the buffer - m_OutBuffer->crunch(); - - return schedule_wakeup_output (Guard); - } - else //now n == send_len - { - m_OutBuffer->reset(); - - return handle_output_queue (Guard); - } - - ACE_NOTREACHED (return 0); + }); } -int WorldSocket::handle_output_queue(GuardType& g) +void WorldSocket::AsyncReadData(size_t dataSize) { - if (msg_queue()->is_empty()) - return cancel_wakeup_output(g); - - ACE_Message_Block* mblk; - - if (msg_queue()->dequeue_head(mblk, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) - { - TC_LOG_ERROR("network", "WorldSocket::handle_output_queue dequeue_head"); - return -1; - } - - const size_t send_len = mblk->length(); - -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(mblk->rd_ptr(), send_len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send(mblk->rd_ptr(), send_len); -#endif // MSG_NOSIGNAL - - if (n == 0) + auto self(shared_from_this()); + _socket.async_read_some(boost::asio::buffer(&_readBuffer[sizeof(ClientPktHeader)], dataSize), [this, dataSize, self](boost::system::error_code error, size_t transferedBytes) { - mblk->release(); - - return -1; - } - else if (n == -1) - { - if (errno == EWOULDBLOCK || errno == EAGAIN) + if (!error && transferedBytes == dataSize) { - msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero); - return schedule_wakeup_output (g); - } - - mblk->release(); - return -1; - } - else if (n < (ssize_t)send_len) //now n > 0 - { - mblk->rd_ptr(static_cast<size_t> (n)); + ClientPktHeader* header = (ClientPktHeader*)&_readBuffer; - if (msg_queue()->enqueue_head(mblk, (ACE_Time_Value*) &ACE_Time_Value::zero) == -1) - { - TC_LOG_ERROR("network", "WorldSocket::handle_output_queue enqueue_head"); - mblk->release(); - return -1; - } + header->size -= sizeof(header->cmd); - return schedule_wakeup_output (g); - } - else //now n == send_len - { - mblk->release(); + uint16 opcode = (uint16)header->cmd; - return msg_queue()->is_empty() ? cancel_wakeup_output(g) : ACE_Event_Handler::WRITE_MASK; - } + std::string opcodeName = GetOpcodeNameForLogging(opcode); - ACE_NOTREACHED(return -1); -} + WorldPacket packet(opcode, header->size); -int WorldSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask) -{ - // Critical section - { - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); - - closing_ = true; - - if (h == ACE_INVALID_HANDLE) - peer().close_writer(); - } - - // Critical section - { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - m_Session = NULL; - } - - reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK); - return 0; -} - -int WorldSocket::Update (void) -{ - if (closing_) - return -1; - - if (m_OutActive) - return 0; - - { - ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, 0); - if (m_OutBuffer->length() == 0 && msg_queue()->is_empty()) - return 0; - } - - int ret; - do - ret = handle_output(get_handle()); - while (ret > 0); - - return ret; -} - -int WorldSocket::handle_input_header (void) -{ - ACE_ASSERT(m_RecvWPct == NULL); - - ACE_ASSERT(m_Header.length() == sizeof(ClientPktHeader)); - - m_Crypt.DecryptRecv ((uint8*)m_Header.rd_ptr(), sizeof(ClientPktHeader)); - - ClientPktHeader& header = *((ClientPktHeader*)m_Header.rd_ptr()); - - EndianConvertReverse(header.size); - EndianConvert(header.cmd); - - if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240)) - { - Player* _player = m_Session ? m_Session->GetPlayer() : NULL; - TC_LOG_ERROR("network", "WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)", - m_Session ? m_Session->GetAccountId() : 0, - _player ? _player->GetGUIDLow() : 0, - _player ? _player->GetName().c_str() : "<none>", - header.size, header.cmd); - - errno = EINVAL; - return -1; - } - - header.size -= 4; - - ACE_NEW_RETURN(m_RecvWPct, WorldPacket ((uint16)header.cmd, header.size), -1); - - if (header.size > 0) - { - m_RecvWPct->resize(header.size); - m_RecvPct.base ((char*) m_RecvWPct->contents(), m_RecvWPct->size()); - } - else - { - ACE_ASSERT(m_RecvPct.space() == 0); - } - - return 0; -} - -int WorldSocket::handle_input_payload (void) -{ - // set errno properly here on error !!! - // now have a header and payload - - ACE_ASSERT (m_RecvPct.space() == 0); - ACE_ASSERT (m_Header.space() == 0); - ACE_ASSERT (m_RecvWPct != NULL); - - const int ret = ProcessIncoming (m_RecvWPct); - - m_RecvPct.base (NULL, 0); - m_RecvPct.reset(); - m_RecvWPct = NULL; - - m_Header.reset(); - - if (ret == -1) - errno = EINVAL; - - return ret; -} - -int WorldSocket::handle_input_missing_data (void) -{ - char buf [4096]; - - ACE_Data_Block db (sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - const size_t recv_size = message_block.space(); - - const ssize_t n = peer().recv (message_block.wr_ptr(), - recv_size); - - if (n <= 0) - return int(n); - - message_block.wr_ptr (n); - - while (message_block.length() > 0) - { - if (m_Header.space() > 0) - { - //need to receive the header - const size_t to_header = (message_block.length() > m_Header.space() ? m_Header.space() : message_block.length()); - m_Header.copy (message_block.rd_ptr(), to_header); - message_block.rd_ptr (to_header); - - if (m_Header.space() > 0) + if (header->size > 0) { - // Couldn't receive the whole header this time. - ACE_ASSERT (message_block.length() == 0); - errno = EWOULDBLOCK; - return -1; - } + packet.resize(header->size); - // We just received nice new header - if (handle_input_header() == -1) - { - ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); - return -1; + std::memcpy(packet.contents(), &_readBuffer[sizeof(ClientPktHeader)], header->size); } - } - - // Its possible on some error situations that this happens - // for example on closing when epoll receives more chunked data and stuff - // hope this is not hack, as proper m_RecvWPct is asserted around - if (!m_RecvWPct) - { - TC_LOG_ERROR("network", "Forcing close on input m_RecvWPct = NULL"); - errno = EINVAL; - return -1; - } - // We have full read header, now check the data payload - if (m_RecvPct.space() > 0) - { - //need more data in the payload - const size_t to_data = (message_block.length() > m_RecvPct.space() ? m_RecvPct.space() : message_block.length()); - m_RecvPct.copy (message_block.rd_ptr(), to_data); - message_block.rd_ptr (to_data); - - if (m_RecvPct.space() > 0) + switch (opcode) { - // Couldn't receive the whole data this time. - ACE_ASSERT (message_block.length() == 0); - errno = EWOULDBLOCK; - return -1; + case CMSG_PING: + HandlePing(packet); + break; + case CMSG_AUTH_SESSION: + if (_worldSession) + { + TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); + break; + } + + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + HandleAuthSession(packet); + break; + case CMSG_KEEP_ALIVE: + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + break; + default: + { + if (!_worldSession) + { + TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); + break; + } + + // Our Idle timer will reset on any non PING opcodes. + // Catches people idling on the login screen and any lingering ingame connections. + _worldSession->ResetTimeOutTime(); + + // Copy the packet to the heap before enqueuing + _worldSession->QueuePacket(new WorldPacket(packet)); + break; + } } - } - //just received fresh new payload - if (handle_input_payload() == -1) + AsyncReadHeader(); + } + else { - ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); - return -1; + _socket.close(); } - } - - return size_t(n) == recv_size ? 1 : 2; -} - -int WorldSocket::cancel_wakeup_output(GuardType& g) -{ - if (!m_OutActive) - return 0; - - m_OutActive = false; - - g.release(); - - if (reactor()->cancel_wakeup - (this, ACE_Event_Handler::WRITE_MASK) == -1) - { - // would be good to store errno from reactor with errno guard - TC_LOG_ERROR("network", "WorldSocket::cancel_wakeup_output"); - return -1; - } - - return 0; + }); } -int WorldSocket::schedule_wakeup_output(GuardType& g) +void WorldSocket::AsyncWrite(WorldPacket const& packet) { - if (m_OutActive) - return 0; - - m_OutActive = true; + ServerPktHeader header(packet.size() + 2, packet.GetOpcode()); + _authCrypt.EncryptSend((uint8*)header.header, header.getHeaderLength()); - g.release(); - - if (reactor()->schedule_wakeup - (this, ACE_Event_Handler::WRITE_MASK) == -1) + auto data = new char[header.getHeaderLength() + packet.size()]; + std::memcpy(data, (char*)header.header, header.getHeaderLength()); + + if (!packet.empty()) + std::memcpy(data + header.getHeaderLength(), (char const*)packet.contents(), packet.size()); + + // Use a shared_ptr here to prevent leaking memory after the async operation has completed + std::shared_ptr<char> buffer(data, [=](char* _b) { - TC_LOG_ERROR("network", "WorldSocket::schedule_wakeup_output"); - return -1; - } - - return 0; -} - -int WorldSocket::ProcessIncoming(WorldPacket* new_pct) -{ - ACE_ASSERT (new_pct); + delete[] _b; // Ensure that the data is deleted as an array + }); - // manage memory ;) - ACE_Auto_Ptr<WorldPacket> aptr(new_pct); + auto self(shared_from_this()); - const ACE_UINT16 opcode = new_pct->GetOpcode(); - - if (closing_) - return -1; - - // Dump received packet. - if (sPacketLog->CanLogPacket()) - sPacketLog->LogPacket(*new_pct, CLIENT_TO_SERVER); - - std::string opcodeName = GetOpcodeNameForLogging(opcode); - if (m_Session) - TC_LOG_TRACE("network.opcode", "C->S: %s %s", m_Session->GetPlayerInfo().c_str(), opcodeName.c_str()); - - try + boost::asio::async_write(_socket, boost::asio::buffer(buffer.get(), header.getHeaderLength() + packet.size()), [this, self, buffer](boost::system::error_code error, std::size_t /*length*/) { - switch (opcode) + if (error) { - case CMSG_PING: - return HandlePing(*new_pct); - case CMSG_AUTH_SESSION: - if (m_Session) - { - TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", m_Session->GetPlayerInfo().c_str()); - return -1; - } - - sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct)); - return HandleAuthSession(*new_pct); - case CMSG_KEEP_ALIVE: - TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); - sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct)); - return 0; - default: - { - ACE_GUARD_RETURN(LockType, Guard, m_SessionLock, -1); - if (!m_Session) - { - TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); - return -1; - } - - // Our Idle timer will reset on any non PING opcodes. - // Catches people idling on the login screen and any lingering ingame connections. - m_Session->ResetTimeOutTime(); - - // OK, give the packet to WorldSession - aptr.release(); - // WARNING here we call it with locks held. - // Its possible to cause deadlock if QueuePacket calls back - m_Session->QueuePacket(new_pct); - return 0; - } + _socket.close(); } - } - catch (ByteBufferException &) - { - TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet %s from client %s, accountid=%i. Disconnected client.", - opcodeName.c_str(), GetRemoteAddress().c_str(), m_Session ? int32(m_Session->GetAccountId()) : -1); - new_pct->hexlike(); - return -1; - } - - ACE_NOTREACHED (return 0); + }); } -int WorldSocket::HandleSendAuthSession() -{ - WorldPacket packet(SMSG_AUTH_CHALLENGE, 37); - packet << uint32(1); // 1...31 - packet << uint32(m_Seed); - - BigNumber seed1; - seed1.SetRand(16 * 8); - packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds - - BigNumber seed2; - seed2.SetRand(16 * 8); - packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds - return SendPacket(packet); -} - -int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) +void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { uint8 digest[20]; uint32 clientSeed; @@ -763,8 +199,8 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) if (sWorld->IsClosed()) { SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteAddress().c_str()); - return -1; + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().c_str()); + return; } // Read the content of the packet @@ -778,11 +214,11 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket.read(digest, 20); TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", - clientBuild, - unk2, - account.c_str(), - unk3, - clientSeed); + clientBuild, + unk2, + account.c_str(), + unk3, + clientSeed); // Get the account information from the realmd database // 0 1 2 3 4 5 6 7 8 @@ -799,7 +235,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // We can not log here, as we do not know the account. Thus, no accountId. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); - return -1; + return; } Field* fields = result->Fetch(); @@ -810,7 +246,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) expansion = world_expansion; // For hook purposes, we get Remoteaddress at this point. - std::string address = GetRemoteAddress(); + std::string address = GetRemoteIpAddress(); // As we don't know if attempted login process by ip works, we update last_attempt_ip right away stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); @@ -827,13 +263,13 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) ///- Re-check ip locking (same check as in realmd). if (fields[3].GetUInt8() == 1) // if ip is locked { - if (strcmp (fields[2].GetCString(), address.c_str())) + if (strcmp(fields[2].GetCString(), address.c_str())) { SendAuthResponseError(AUTH_FAILED); TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well sScriptMgr->OnFailedAccountLogin(id); - return -1; + return; } } @@ -853,7 +289,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); } - locale = LocaleConstant (fields[6].GetUInt8()); + locale = LocaleConstant(fields[6].GetUInt8()); if (locale >= TOTAL_LOCALES) locale = LOCALE_enUS; @@ -865,7 +301,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { SendAuthResponseError(AUTH_REJECT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); - return -1; + return; } // Checks gmlevel per Realm @@ -897,7 +333,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); sScriptMgr->OnFailedAccountLogin(id); - return -1; + return; } // Check locked state for server @@ -908,17 +344,16 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); sScriptMgr->OnFailedAccountLogin(id); - return -1; + return; } // Check that Key and account name are the same on client and server uint32 t = 0; - uint32 seed = m_Seed; sha.UpdateData(account); sha.UpdateData((uint8*)&t, 4); sha.UpdateData((uint8*)&clientSeed, 4); - sha.UpdateData((uint8*)&seed, 4); + sha.UpdateData((uint8*)&_authSeed, 4); sha.UpdateBigNumbers(&k, NULL); sha.Finalize(); @@ -926,7 +361,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { SendAuthResponseError(AUTH_FAILED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); - return -1; + return; } TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", @@ -953,31 +388,34 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); // NOTE ATM the socket is single-threaded, have this in mind ... - ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); + _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); - m_Crypt.Init(&k); + _authCrypt.Init(&k); - m_Session->LoadGlobalAccountData(); - m_Session->LoadTutorialsData(); - m_Session->ReadAddonsInfo(recvPacket); - m_Session->LoadPermissions(); + _worldSession->LoadGlobalAccountData(); + _worldSession->LoadTutorialsData(); + _worldSession->ReadAddonsInfo(recvPacket); + _worldSession->LoadPermissions(); // At this point, we can safely hook a successful login sScriptMgr->OnAccountLogin(id); // Initialize Warden system only if it is enabled by config if (wardenActive) - m_Session->InitWarden(&k, os); + _worldSession->InitWarden(&k, os); - // Sleep this Network thread for - uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY); - ACE_OS::sleep(ACE_Time_Value(0, sleepTime)); + sWorld->AddSession(_worldSession); +} + +void WorldSocket::SendAuthResponseError(uint8 code) +{ + WorldPacket packet(SMSG_AUTH_RESPONSE, 1); + packet << uint8(code); - sWorld->AddSession(m_Session); - return 0; + AsyncWrite(packet); } -int WorldSocket::HandlePing(WorldPacket& recvPacket) +void WorldSocket::HandlePing(WorldPacket& recvPacket) { uint32 ping; uint32 latency; @@ -986,65 +424,55 @@ int WorldSocket::HandlePing(WorldPacket& recvPacket) recvPacket >> ping; recvPacket >> latency; - if (m_LastPingTime == ACE_Time_Value::zero) - m_LastPingTime = ACE_OS::gettimeofday(); // for 1st ping + if (_LastPingTime == steady_clock::time_point()) + { + _LastPingTime = steady_clock::now(); + } else { - ACE_Time_Value cur_time = ACE_OS::gettimeofday(); - ACE_Time_Value diff_time (cur_time); - diff_time -= m_LastPingTime; - m_LastPingTime = cur_time; + steady_clock::time_point now = steady_clock::now(); + + steady_clock::duration diff = now - _LastPingTime; - if (diff_time < ACE_Time_Value (27)) + _LastPingTime = now; + + if (diff < seconds(27)) { - ++m_OverSpeedPings; + ++_OverSpeedPings; - uint32 max_count = sWorld->getIntConfig (CONFIG_MAX_OVERSPEED_PINGS); + uint32 maxAllowed = sWorld->getIntConfig(CONFIG_MAX_OVERSPEED_PINGS); - if (max_count && m_OverSpeedPings > max_count) + if (maxAllowed && _OverSpeedPings > maxAllowed) { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - - if (m_Session && !m_Session->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING)) + if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING)) { TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)", - m_Session->GetPlayerInfo().c_str(), GetRemoteAddress().c_str()); + _worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().c_str()); - return -1; + _socket.close(); + return; } } } else - m_OverSpeedPings = 0; + _OverSpeedPings = 0; } - // critical section + if (_worldSession) { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); + _worldSession->SetLatency(latency); + _worldSession->ResetClientTimeDelay(); + } + else + { + TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", + GetRemoteIpAddress().c_str()); - if (m_Session) - { - m_Session->SetLatency (latency); - m_Session->ResetClientTimeDelay(); - } - else - { - TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, " - "but is not authenticated or got recently kicked, " - " address = %s", - GetRemoteAddress().c_str()); - return -1; - } + _socket.close(); + return; } WorldPacket packet(SMSG_PONG, 4); packet << ping; - return SendPacket(packet); -} - -void WorldSocket::SendAuthResponseError(uint8 code) -{ - WorldPacket packet(SMSG_AUTH_RESPONSE, 1); - packet << uint8(code); - SendPacket(packet); + return AsyncWrite(packet); } diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 1f98be0152b..a6520a70846 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -1,218 +1,85 @@ /* - * 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 - * 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/>. - */ - -/** \addtogroup u2w User to World Communication - * @{ - * \file WorldSocket.h - * \author Derex <derex101@gmail.com> - */ - -#ifndef _WORLDSOCKET_H -#define _WORLDSOCKET_H - -#include <ace/Basic_Types.h> -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/Thread_Mutex.h> -#include <ace/Guard_T.h> -#include <ace/Unbounded_Queue.h> -#include <ace/Message_Block.h> - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -#pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - +* 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 +* 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 __WORLDSOCKET_H__ +#define __WORLDSOCKET_H__ + +#include <memory> +#include <chrono> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/streambuf.hpp> #include "Common.h" #include "AuthCrypt.h" +#include "Util.h" +#include "WorldPacket.h" +#include "WorldSession.h" -class ACE_Message_Block; -class WorldPacket; -class WorldSession; - -/// Handler that can communicate over stream sockets. -typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> WorldHandler; - -/** - * WorldSocket. - * - * This class is responsible for the communication with - * remote clients. - * Most methods return -1 on failure. - * The class uses reference counting. - * - * For output the class uses one buffer (64K usually) and - * a queue where it stores packet if there is no place on - * the queue. The reason this is done, is because the server - * does really a lot of small-size writes to it, and it doesn't - * scale well to allocate memory for every. When something is - * written to the output buffer the socket is not immediately - * activated for output (again for the same reason), there - * is 10ms celling (thats why there is Update() method). - * This concept is similar to TCP_CORK, but TCP_CORK - * uses 200ms celling. As result overhead generated by - * sending packets from "producer" threads is minimal, - * and doing a lot of writes with small size is tolerated. - * - * The calls to Update() method are managed by WorldSocketMgr - * and ReactorRunnable. - * - * For input, the class uses one 4096 bytes buffer on stack - * to which it does recv() calls. And then received data is - * distributed where its needed. 4096 matches pretty well the - * traffic generated by client for now. - * - * The input/output do speculative reads/writes (AKA it tryes - * to read all data available in the kernel buffer or tryes to - * write everything available in userspace buffer), - * which is ok for using with Level and Edge Triggered IO - * notification. - * - */ -class WorldSocket : public WorldHandler -{ - public: - WorldSocket (void); - virtual ~WorldSocket (void); - - friend class WorldSocketMgr; - - /// Mutex type used for various synchronizations. - typedef ACE_Thread_Mutex LockType; - typedef ACE_Guard<LockType> GuardType; - - /// Check if socket is closed. - bool IsClosed(void) const; - - /// Close the socket. - void CloseSocket(void); - - /// Get address of connected peer. - const std::string& GetRemoteAddress(void) const; - - /// Send A packet on the socket, this function is reentrant. - /// @param pct packet to send - /// @return -1 of failure - int SendPacket(const WorldPacket& pct); - - /// Add reference to this object. - long AddReference(void); - - /// Remove reference to this object. - long RemoveReference(void); - - /// things called by ACE framework. - - /// Called on open, the void* is the acceptor. - virtual int open(void *); - - /// Called on failures inside of the acceptor, don't call from your code. - virtual int close(u_long); - - /// Called when we can read from the socket. - virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); +using boost::asio::ip::tcp; - /// Called when the socket can write. - virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); +#pragma pack(push, 1) - /// Called when connection is closed or error happens. - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, - ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - /// Called by WorldSocketMgr/ReactorRunnable. - int Update(void); - - private: - /// Helper functions for processing incoming data. - int handle_input_header(void); - int handle_input_payload(void); - int handle_input_missing_data(void); - - /// Help functions to mark/unmark the socket for output. - /// @param g the guard is for m_OutBufferLock, the function will release it - int cancel_wakeup_output(GuardType& g); - int schedule_wakeup_output(GuardType& g); - - /// Drain the queue if its not empty. - int handle_output_queue(GuardType& g); - - /// process one incoming packet. - /// @param new_pct received packet, note that you need to delete it. - int ProcessIncoming(WorldPacket* new_pct); - - /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. - int HandleAuthSession(WorldPacket& recvPacket); - - /// Called by ProcessIncoming() on CMSG_PING. - int HandlePing(WorldPacket& recvPacket); - - int HandleSendAuthSession(); +struct ClientPktHeader +{ + uint16 size; + uint32 cmd; +}; - private: - void SendAuthResponseError(uint8); - /// Time in which the last ping was received - ACE_Time_Value m_LastPingTime; +#pragma pack(pop) - /// Keep track of over-speed pings, to prevent ping flood. - uint32 m_OverSpeedPings; +class WorldSocket : public std::enable_shared_from_this<WorldSocket> +{ +public: + WorldSocket(tcp::socket&& socket); - /// Address of the remote peer - std::string m_Address; + WorldSocket(WorldSocket const& right) = delete; + WorldSocket& operator=(WorldSocket const& right) = delete; - /// Class used for managing encryption of the headers - AuthCrypt m_Crypt; + void Start(); - /// Mutex lock to protect m_Session - LockType m_SessionLock; + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } - /// Session to which received packets are routed - WorldSession* m_Session; + void CloseSocket() { _socket.close(); }; + bool IsOpen() { return _socket.is_open(); }; - /// here are stored the fragments of the received data - WorldPacket* m_RecvWPct; + void AsyncWrite(WorldPacket const& packet); - /// This block actually refers to m_RecvWPct contents, - /// which allows easy and safe writing to it. - /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. - ACE_Message_Block m_RecvPct; +private: + void HandleSendAuthSession(); + void HandleAuthSession(WorldPacket& recvPacket); + void SendAuthResponseError(uint8 code); - /// Fragment of the received header. - ACE_Message_Block m_Header; + void HandlePing(WorldPacket& recvPacket); - /// Mutex for protecting output related data. - LockType m_OutBufferLock; + void AsyncReadHeader(); + void AsyncReadData(size_t dataSize); - /// Buffer used for writing output. - ACE_Message_Block* m_OutBuffer; + tcp::socket _socket; - /// Size of the m_OutBuffer. - size_t m_OutBufferSize; + char _readBuffer[4096]; - /// True if the socket is registered with the reactor for output - bool m_OutActive; + uint32 _authSeed; + AuthCrypt _authCrypt; - uint32 m_Seed; + std::chrono::steady_clock::time_point _LastPingTime; + uint32 _OverSpeedPings; - WorldSocket(WorldSocket const& right) = delete; - WorldSocket& operator=(WorldSocket const& right) = delete; + WorldSession* _worldSession; }; -#endif /* _WORLDSOCKET_H */ - -/// @} - +#endif diff --git a/src/server/game/Server/WorldSocketAcceptor.h b/src/server/game/Server/WorldSocketAcceptor.h deleted file mode 100644 index 0b07196a0cd..00000000000 --- a/src/server/game/Server/WorldSocketAcceptor.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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/>. - */ - -/** \addtogroup u2w User to World Communication - * @{ - * \file WorldSocketMgr.h - */ - -#ifndef __WORLDSOCKETACCEPTOR_H_ -#define __WORLDSOCKETACCEPTOR_H_ - -#include "Common.h" - -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "WorldSocket.h" - -class WorldSocketAcceptor : public ACE_Acceptor<WorldSocket, ACE_SOCK_Acceptor> -{ -public: - WorldSocketAcceptor(void) { } - virtual ~WorldSocketAcceptor(void) - { - if (reactor()) - reactor()->cancel_timer(this, 1); - } - -protected: - - virtual int handle_timeout(const ACE_Time_Value& /*current_time*/, const void* /*act = 0*/) - { - TC_LOG_DEBUG("misc", "Resuming acceptor"); - reactor()->cancel_timer(this, 1); - return reactor()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); - } - - virtual int handle_accept_error(void) - { -#if defined(ENFILE) && defined(EMFILE) - if (errno == ENFILE || errno == EMFILE) - { - TC_LOG_ERROR("misc", "Out of file descriptors, suspending incoming connections for 10 seconds"); - reactor()->remove_handler(this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); - reactor()->schedule_timer(this, NULL, ACE_Time_Value(10)); - } -#endif - return 0; - } -}; - -#endif /* __WORLDSOCKETACCEPTOR_H_ */ -/// @} diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp deleted file mode 100644 index 7880552ffa1..00000000000 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ /dev/null @@ -1,360 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/** \file WorldSocketMgr.cpp -* \ingroup u2w -* \author Derex <derex101@gmail.com> -*/ - -#include "WorldSocketMgr.h" - -#include <ace/ACE.h> -#include <ace/Log_Msg.h> -#include <ace/Reactor.h> -#include <ace/Reactor_Impl.h> -#include <ace/TP_Reactor.h> -#include <ace/Dev_Poll_Reactor.h> -#include <ace/Guard_T.h> -#include <ace/Atomic_Op.h> -#include <ace/os_include/arpa/os_inet.h> -#include <ace/os_include/netinet/os_tcp.h> -#include <ace/os_include/sys/os_types.h> -#include <ace/os_include/sys/os_socket.h> - -#include <set> - -#include "Log.h" -#include "Common.h" -#include "Config.h" -#include "DatabaseEnv.h" -#include "WorldSocket.h" -#include "WorldSocketAcceptor.h" -#include "ScriptMgr.h" - -/** -* This is a helper class to WorldSocketMgr, that manages -* network threads, and assigning connections from acceptor thread -* to other network threads -*/ -class ReactorRunnable : protected ACE_Task_Base -{ - public: - - ReactorRunnable() : - m_Reactor(0), - m_Connections(0), - m_ThreadId(-1) - { - ACE_Reactor_Impl* imp; - - #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - - imp = new ACE_Dev_Poll_Reactor(); - - imp->max_notify_iterations (128); - imp->restart (1); - - #else - - imp = new ACE_TP_Reactor(); - imp->max_notify_iterations (128); - - #endif - - m_Reactor = new ACE_Reactor (imp, 1); - } - - virtual ~ReactorRunnable() - { - Stop(); - Wait(); - - delete m_Reactor; - } - - void Stop() - { - m_Reactor->end_reactor_event_loop(); - } - - int Start() - { - if (m_ThreadId != -1) - return -1; - - return (m_ThreadId = activate()); - } - - void Wait() { ACE_Task_Base::wait(); } - - long Connections() - { - return static_cast<long> (m_Connections.value()); - } - - int AddSocket (WorldSocket* sock) - { - TRINITY_GUARD(ACE_Thread_Mutex, m_NewSockets_Lock); - - ++m_Connections; - sock->AddReference(); - sock->reactor (m_Reactor); - m_NewSockets.insert (sock); - - sScriptMgr->OnSocketOpen(sock); - - return 0; - } - - ACE_Reactor* GetReactor() - { - return m_Reactor; - } - - protected: - - void AddNewSockets() - { - TRINITY_GUARD(ACE_Thread_Mutex, m_NewSockets_Lock); - - if (m_NewSockets.empty()) - return; - - for (SocketSet::const_iterator i = m_NewSockets.begin(); i != m_NewSockets.end(); ++i) - { - WorldSocket* sock = (*i); - - if (sock->IsClosed()) - { - sScriptMgr->OnSocketClose(sock, true); - - sock->RemoveReference(); - --m_Connections; - } - else - m_Sockets.insert (sock); - } - - m_NewSockets.clear(); - } - - virtual int svc() - { - TC_LOG_DEBUG("misc", "Network Thread Starting"); - - ACE_ASSERT (m_Reactor); - - SocketSet::iterator i, t; - - while (!m_Reactor->reactor_event_loop_done()) - { - // dont be too smart to move this outside the loop - // the run_reactor_event_loop will modify interval - ACE_Time_Value interval (0, 10000); - - if (m_Reactor->run_reactor_event_loop (interval) == -1) - break; - - AddNewSockets(); - - for (i = m_Sockets.begin(); i != m_Sockets.end();) - { - if ((*i)->Update() == -1) - { - t = i; - ++i; - - (*t)->CloseSocket(); - - sScriptMgr->OnSocketClose((*t), false); - - (*t)->RemoveReference(); - --m_Connections; - m_Sockets.erase (t); - } - else - ++i; - } - } - - TC_LOG_DEBUG("misc", "Network Thread exits"); - - return 0; - } - - private: - typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> AtomicInt; - typedef std::set<WorldSocket*> SocketSet; - - ACE_Reactor* m_Reactor; - AtomicInt m_Connections; - int m_ThreadId; - - SocketSet m_Sockets; - - SocketSet m_NewSockets; - ACE_Thread_Mutex m_NewSockets_Lock; -}; - -WorldSocketMgr::WorldSocketMgr() : - m_NetThreads(0), - m_NetThreadsCount(0), - m_SockOutKBuff(-1), - m_SockOutUBuff(65536), - m_UseNoDelay(true), - m_Acceptor (0) { } - -WorldSocketMgr::~WorldSocketMgr() -{ - delete [] m_NetThreads; - delete m_Acceptor; -} - -int -WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) -{ - m_UseNoDelay = sConfigMgr->GetBoolDefault ("Network.TcpNodelay", true); - - int num_threads = sConfigMgr->GetIntDefault ("Network.Threads", 1); - - if (num_threads <= 0) - { - TC_LOG_ERROR("misc", "Network.Threads is wrong in your config file"); - return -1; - } - - m_NetThreadsCount = static_cast<size_t> (num_threads + 1); - - m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; - - TC_LOG_DEBUG("misc", "Max allowed socket connections %d", ACE::max_handles()); - - // -1 means use default - m_SockOutKBuff = sConfigMgr->GetIntDefault ("Network.OutKBuff", -1); - - m_SockOutUBuff = sConfigMgr->GetIntDefault ("Network.OutUBuff", 65536); - - if (m_SockOutUBuff <= 0) - { - TC_LOG_ERROR("misc", "Network.OutUBuff is wrong in your config file"); - return -1; - } - - m_Acceptor = new WorldSocketAcceptor; - - ACE_INET_Addr listen_addr (port, address); - - if (m_Acceptor->open(listen_addr, m_NetThreads[0].GetReactor(), ACE_NONBLOCK) == -1) - { - TC_LOG_ERROR("misc", "Failed to open acceptor, check if the port is free"); - return -1; - } - - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Start(); - - return 0; -} - -int -WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) -{ - if (!sLog->ShouldLog("misc", LOG_LEVEL_DEBUG)) - ACE_Log_Msg::instance()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); - - if (StartReactiveIO(port, address) == -1) - return -1; - - sScriptMgr->OnNetworkStart(); - - return 0; -} - -void -WorldSocketMgr::StopNetwork() -{ - if (m_Acceptor) - { - m_Acceptor->close(); - } - - if (m_NetThreadsCount != 0) - { - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Stop(); - } - - Wait(); - - sScriptMgr->OnNetworkStop(); -} - -void -WorldSocketMgr::Wait() -{ - if (m_NetThreadsCount != 0) - { - for (size_t i = 0; i < m_NetThreadsCount; ++i) - m_NetThreads[i].Wait(); - } -} - -int -WorldSocketMgr::OnSocketOpen (WorldSocket* sock) -{ - // set some options here - if (m_SockOutKBuff >= 0) - { - if (sock->peer().set_option (SOL_SOCKET, - SO_SNDBUF, - (void*) & m_SockOutKBuff, - sizeof (int)) == -1 && errno != ENOTSUP) - { - TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); - return -1; - } - } - - static const int ndoption = 1; - - // Set TCP_NODELAY. - if (m_UseNoDelay) - { - if (sock->peer().set_option (ACE_IPPROTO_TCP, - TCP_NODELAY, - (void*)&ndoption, - sizeof (int)) == -1) - { - TC_LOG_ERROR("misc", "WorldSocketMgr::OnSocketOpen: peer().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); - return -1; - } - } - - sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff); - - // we skip the Acceptor Thread - size_t min = 1; - - ACE_ASSERT (m_NetThreadsCount >= 1); - - for (size_t i = 1; i < m_NetThreadsCount; ++i) - if (m_NetThreads[i].Connections() < m_NetThreads[min].Connections()) - min = i; - - return m_NetThreads[min].AddSocket (sock); -} diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h deleted file mode 100644 index fb8ddb42b9e..00000000000 --- a/src/server/game/Server/WorldSocketMgr.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/** \addtogroup u2w User to World Communication - * @{ - * \file WorldSocketMgr.h - * \author Derex <derex101@gmail.com> - */ - -#ifndef __WORLDSOCKETMGR_H -#define __WORLDSOCKETMGR_H - -#include <ace/Basic_Types.h> -#include <ace/Singleton.h> -#include <ace/Thread_Mutex.h> - -class WorldSocket; -class ReactorRunnable; -class ACE_Event_Handler; - -/// Manages all sockets connected to peers and network threads -class WorldSocketMgr -{ -public: - friend class WorldSocket; - friend class ACE_Singleton<WorldSocketMgr, ACE_Thread_Mutex>; - - /// Start network, listen at address:port . - int StartNetwork(ACE_UINT16 port, const char* address); - - /// Stops all network threads, It will wait for all running threads . - void StopNetwork(); - - /// Wait untill all network threads have "joined" . - void Wait(); - -private: - int OnSocketOpen(WorldSocket* sock); - - int StartReactiveIO(ACE_UINT16 port, const char* address); - -private: - WorldSocketMgr(); - virtual ~WorldSocketMgr(); - - ReactorRunnable* m_NetThreads; - size_t m_NetThreadsCount; - - int m_SockOutKBuff; - int m_SockOutUBuff; - bool m_UseNoDelay; - - class WorldSocketAcceptor* m_Acceptor; -}; - -#define sWorldSocketMgr ACE_Singleton<WorldSocketMgr, ACE_Thread_Mutex>::instance() - -#endif -/// @} diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 757bd813613..53b4cef73e8 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -21,8 +21,6 @@ // For static or at-server-startup loaded spell data -#include <ace/Singleton.h> - #include "Define.h" #include "DBCStructure.h" #include "SharedDefines.h" @@ -603,7 +601,6 @@ bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group); class SpellMgr { - friend class ACE_Singleton<SpellMgr, ACE_Null_Mutex>; // Constructors private: SpellMgr(); @@ -611,6 +608,13 @@ class SpellMgr // Accessors (const or static functions) public: + static SpellMgr* instance() + { + static SpellMgr* instance = new SpellMgr(); + + return instance; + } + // Spell correctness for client using static bool IsSpellValid(SpellInfo const* spellInfo, Player* player = NULL, bool msg = true); @@ -766,6 +770,6 @@ class SpellMgr SpellInfoMap mSpellInfoMap; }; -#define sSpellMgr ACE_Singleton<SpellMgr, ACE_Null_Mutex>::instance() +#define sSpellMgr SpellMgr::instance() #endif diff --git a/src/server/game/Texts/CreatureTextMgr.h b/src/server/game/Texts/CreatureTextMgr.h index ab5b9f59032..f8c499f7ce6 100644 --- a/src/server/game/Texts/CreatureTextMgr.h +++ b/src/server/game/Texts/CreatureTextMgr.h @@ -82,11 +82,17 @@ typedef std::unordered_map<uint64, CreatureTextRepeatGroup> CreatureTextRepeatMa class CreatureTextMgr { - friend class ACE_Singleton<CreatureTextMgr, ACE_Null_Mutex>; - CreatureTextMgr() { }; + private: + CreatureTextMgr() { }; + ~CreatureTextMgr() { }; public: - ~CreatureTextMgr() { }; + static CreatureTextMgr* instance() + { + static CreatureTextMgr* instance = new CreatureTextMgr(); + return instance; + } + void LoadCreatureTexts(); void LoadCreatureTextLocales(); CreatureTextMap const& GetTextMap() const { return mTextMap; } @@ -113,7 +119,7 @@ class CreatureTextMgr LocaleCreatureTextMap mLocaleTextMap; }; -#define sCreatureTextMgr ACE_Singleton<CreatureTextMgr, ACE_Null_Mutex>::instance() +#define sCreatureTextMgr CreatureTextMgr::instance() template<class Builder> class CreatureTextLocalizer diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h index 5bfe78abbba..5f85ee307ed 100644 --- a/src/server/game/Tickets/TicketMgr.h +++ b/src/server/game/Tickets/TicketMgr.h @@ -19,7 +19,6 @@ #define _TICKETMGR_H #include <string> -#include <ace/Singleton.h> #include "ObjectMgr.h" @@ -174,13 +173,17 @@ typedef std::map<uint32, GmTicket*> GmTicketList; class TicketMgr { - friend class ACE_Singleton<TicketMgr, ACE_Null_Mutex>; - private: TicketMgr(); ~TicketMgr(); public: + static TicketMgr* instance() + { + static TicketMgr* instance = new TicketMgr(); + return instance; + } + void LoadTickets(); void LoadSurveys(); @@ -246,6 +249,6 @@ protected: uint64 _lastChange; }; -#define sTicketMgr ACE_Singleton<TicketMgr, ACE_Null_Mutex>::instance() +#define sTicketMgr TicketMgr::instance() #endif // _TICKETMGR_H diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index 44bab1d31b3..98ed381a2b1 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -164,7 +164,7 @@ void WardenCheckMgr::LoadWardenOverrides() uint32 count = 0; - ACE_WRITE_GUARD(ACE_RW_Mutex, g, _checkStoreLock); + boost::unique_lock<boost::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); do { diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 8f2fa37400d..c9e26283060 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -20,6 +20,8 @@ #define _WARDENCHECKMGR_H #include <map> +#include <boost/thread/locks.hpp> +#include <boost/thread/shared_mutex.hpp> #include "Cryptography/BigNumber.h" enum WardenActions @@ -48,11 +50,17 @@ struct WardenCheckResult class WardenCheckMgr { - friend class ACE_Singleton<WardenCheckMgr, ACE_Null_Mutex>; - WardenCheckMgr(); - ~WardenCheckMgr(); + private: + WardenCheckMgr(); + ~WardenCheckMgr(); public: + static WardenCheckMgr* instance() + { + static WardenCheckMgr* instance = new WardenCheckMgr(); + return instance; + } + // We have a linear key without any gaps, so we use vector for fast access typedef std::vector<WardenCheck*> CheckContainer; typedef std::map<uint32, WardenCheckResult*> CheckResultContainer; @@ -66,13 +74,13 @@ class WardenCheckMgr void LoadWardenChecks(); void LoadWardenOverrides(); - ACE_RW_Mutex _checkStoreLock; + boost::shared_mutex _checkStoreLock; private: CheckContainer CheckStore; CheckResultContainer CheckResultStore; }; -#define sWardenCheckMgr ACE_Singleton<WardenCheckMgr, ACE_Null_Mutex>::instance() +#define sWardenCheckMgr WardenCheckMgr::instance() #endif diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index 18bf2897358..5c3a86988db 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -206,7 +206,7 @@ void WardenWin::RequestData() ByteBuffer buff; buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST); - ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock); + boost::shared_lock<boost::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_OTHER_CHECKS); ++i) { @@ -369,7 +369,7 @@ void WardenWin::HandleData(ByteBuffer &buff) uint8 type; uint16 checkFailed = 0; - ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock); + boost::shared_lock<boost::shared_mutex> lock(sWardenCheckMgr->_checkStoreLock); for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr) { diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index 8d39f553910..dea7dfa6819 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -94,7 +94,7 @@ bool Weather::ReGenerate() // season source http://aa.usno.navy.mil/data/docs/EarthSeasons.html time_t gtime = sWorld->GetGameTime(); struct tm ltime; - ACE_OS::localtime_r(>ime, <ime); + localtime_r(>ime, <ime); uint32 season = ((ltime.tm_yday - 78 + 365)/91)%4; static char const* seasonName[WEATHER_SEASONS] = { "spring", "summer", "fall", "winter" }; diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp index 5cf5cde75fd..938c91b0228 100644 --- a/src/server/game/Weather/WeatherMgr.cpp +++ b/src/server/game/Weather/WeatherMgr.cpp @@ -24,7 +24,6 @@ #include "Weather.h" #include "Log.h" #include "ObjectMgr.h" -#include "AutoPtr.h" #include "Player.h" #include "WorldPacket.h" #include "WorldSession.h" @@ -34,7 +33,7 @@ namespace WeatherMgr namespace { - typedef std::unordered_map<uint32, Trinity::AutoPtr<Weather, ACE_Null_Mutex> > WeatherMap; + typedef std::unordered_map<uint32, std::shared_ptr<Weather> > WeatherMap; typedef std::unordered_map<uint32, WeatherData> WeatherZoneMap; WeatherMap m_weathers; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 6023ad86628..631c4e61d5f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -20,6 +20,7 @@ \ingroup world */ +#include <atomic> #include "Common.h" #include "Memory.h" #include "DatabaseEnv.h" @@ -81,9 +82,10 @@ #include "BattlefieldMgr.h" #include "TransportMgr.h" -ACE_Atomic_Op<ACE_Thread_Mutex, bool> World::m_stopEvent = false; + +std::atomic<bool> World::m_stopEvent(false); uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; -ACE_Atomic_Op<ACE_Thread_Mutex, uint32> World::m_worldLoopCounter = 0; +std::atomic<uint32> World::m_worldLoopCounter(0); float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE; float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE; @@ -668,7 +670,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Group", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Guild", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Auction", false); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = sConfigMgr->GetBoolDefault("AllowTwoSide.trade", false); + m_bool_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = sConfigMgr->GetBoolDefault("AllowTwoSide.Trade", false); m_int_configs[CONFIG_STRICT_PLAYER_NAMES] = sConfigMgr->GetIntDefault ("StrictPlayerNames", 0); m_int_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfigMgr->GetIntDefault ("StrictCharterNames", 0); m_int_configs[CONFIG_STRICT_PET_NAMES] = sConfigMgr->GetIntDefault ("StrictPetNames", 0); @@ -1257,8 +1259,6 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false); - m_bool_configs[CONFIG_IP_BASED_LOGIN_LOGGING] = sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false); - // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); @@ -1316,7 +1316,7 @@ void World::SetInitialWorldSettings() ///- Update the realm entry in the database with the realm type from the config file //No SQL injection as values are treated as integers - + // not send custom type REALM_FFA_PVP to realm list uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE); @@ -1751,7 +1751,7 @@ void World::SetInitialWorldSettings() //one second is 1000 -(tested on win system) /// @todo Get rid of magic numbers tm localTm; - ACE_OS::localtime_r(&m_gameTime, &localTm); + localtime_r(&m_gameTime, &localTm); mail_timer = ((((localTm.tm_hour + 20) % 24)* HOUR * IN_MILLISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval()); //1440 mail_timer_expires = ((DAY * IN_MILLISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval())); @@ -2594,7 +2594,7 @@ void World::ShutdownMsg(bool show, Player* player) void World::ShutdownCancel() { // nothing cancel or too later - if (!m_ShutdownTimer || m_stopEvent.value()) + if (!m_ShutdownTimer || m_stopEvent) return; ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED; @@ -2733,7 +2733,7 @@ void World::UpdateRealmCharCount(uint32 accountId) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); stmt->setUInt32(0, accountId); PreparedQueryResultFuture result = CharacterDatabase.AsyncQuery(stmt); - m_realmCharCallbacks.insert(result); + m_realmCharCallbacks.push_back(std::move(result)); } void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) @@ -2781,7 +2781,7 @@ void World::InitDailyQuestResetTime() // FIX ME: client not show day start time time_t curTime = time(NULL); tm localTm; - ACE_OS::localtime_r(&curTime, &localTm); + localtime_r(&curTime, &localTm); localTm.tm_hour = 6; localTm.tm_min = 0; localTm.tm_sec = 0; @@ -2815,7 +2815,7 @@ void World::InitRandomBGResetTime() // generate time by config time_t curTime = time(NULL); tm localTm; - ACE_OS::localtime_r(&curTime, &localTm); + localtime_r(&curTime, &localTm); localTm.tm_hour = getIntConfig(CONFIG_RANDOM_BG_RESET_HOUR); localTm.tm_min = 0; localTm.tm_sec = 0; @@ -2843,7 +2843,7 @@ void World::InitGuildResetTime() // generate time by config time_t curTime = time(NULL); tm localTm; - ACE_OS::localtime_r(&curTime, &localTm); + localtime_r(&curTime, &localTm); localTm.tm_hour = getIntConfig(CONFIG_GUILD_RESET_HOUR); localTm.tm_min = 0; localTm.tm_sec = 0; @@ -2928,7 +2928,7 @@ void World::ResetMonthlyQuests() // generate time time_t curTime = time(NULL); tm localTm; - ACE_OS::localtime_r(&curTime, &localTm); + localtime_r(&curTime, &localTm); int month = localTm.tm_mon; int year = localTm.tm_year; @@ -3090,19 +3090,17 @@ void World::ProcessQueryCallbacks() { PreparedQueryResult result; - while (!m_realmCharCallbacks.is_empty()) + for (std::deque<std::future<PreparedQueryResult>>::iterator itr = m_realmCharCallbacks.begin(); itr != m_realmCharCallbacks.end(); ) { - ACE_Future<PreparedQueryResult> lResult; - ACE_Time_Value timeout = ACE_Time_Value::zero; - if (m_realmCharCallbacks.next_readable(lResult, &timeout) != 1) - break; - - if (lResult.ready()) + if ((*itr).wait_for(std::chrono::seconds(0)) != std::future_status::ready) { - lResult.get(result); - _UpdateRealmCharCount(result); - lResult.cancel(); + ++itr; + continue; } + + result = (*itr).get(); + _UpdateRealmCharCount(result); + itr = m_realmCharCallbacks.erase(itr); } } diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 61acdc37b07..22dece5d4f0 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -25,12 +25,11 @@ #include "Common.h" #include "Timer.h" -#include <ace/Singleton.h> -#include <ace/Atomic_Op.h> #include "SharedDefines.h" #include "QueryResult.h" #include "Callback.h" +#include <atomic> #include <map> #include <set> #include <list> @@ -155,7 +154,6 @@ enum WorldBoolConfigs CONFIG_STATS_LIMITS_ENABLE, CONFIG_INSTANCES_RESET_ANNOUNCE, CONFIG_IP_BASED_ACTION_LOGGING, - CONFIG_IP_BASED_LOGIN_LOGGING, BOOL_CONFIG_VALUE_COUNT }; @@ -520,10 +518,13 @@ struct CharacterNameData class World { public: - static ACE_Atomic_Op<ACE_Thread_Mutex, uint32> m_worldLoopCounter; + static World* instance() + { + static World* instance = new World(); + return instance; + } - World(); - ~World(); + static std::atomic<uint32> m_worldLoopCounter; WorldSession* FindSession(uint32 id) const; void AddSession(WorldSession* s); @@ -636,7 +637,7 @@ class World void ShutdownMsg(bool show = false, Player* player = NULL); static uint8 GetExitCode() { return m_ExitCode; } static void StopNow(uint8 exitcode) { m_stopEvent = true; m_ExitCode = exitcode; } - static bool IsStopped() { return m_stopEvent.value(); } + static bool IsStopped() { return m_stopEvent; } void Update(uint32 diff); @@ -758,7 +759,10 @@ class World void ResetRandomBG(); void ResetGuildCap(); private: - static ACE_Atomic_Op<ACE_Thread_Mutex, bool> m_stopEvent; + World(); + ~World(); + + static std::atomic<bool> m_stopEvent; static uint8 m_ExitCode; uint32 m_ShutdownTimer; uint32 m_ShutdownMask; @@ -811,7 +815,7 @@ class World static int32 m_visibility_notify_periodInBGArenas; // CLI command holder to be thread safe - ACE_Based::LockedQueue<CliCommandHolder*, ACE_Thread_Mutex> cliCmdQueue; + LockedQueue<CliCommandHolder*> cliCmdQueue; // next daily quests and random bg reset time time_t m_NextDailyQuestReset; @@ -825,7 +829,7 @@ class World // sessions that are added async void AddSession_(WorldSession* s); - ACE_Based::LockedQueue<WorldSession*, ACE_Thread_Mutex> addSessQueue; + LockedQueue<WorldSession*> addSessQueue; // used versions std::string m_DBVersion; @@ -840,11 +844,11 @@ class World void LoadCharacterNameData(); void ProcessQueryCallbacks(); - ACE_Future_Set<PreparedQueryResult> m_realmCharCallbacks; + std::deque<std::future<PreparedQueryResult>> m_realmCharCallbacks; }; extern uint32 realmID; -#define sWorld ACE_Singleton<World, ACE_Null_Mutex>::instance() +#define sWorld World::instance() #endif /// @} diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 938520209a0..ba2709f0a23 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -141,7 +141,6 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Weather ${CMAKE_SOURCE_DIR}/src/server/game/World ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ) diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index 9d6af235298..cc5c8e49c69 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -459,7 +459,7 @@ public: { time_t timeBan = time_t(fields2[0].GetUInt32()); tm tmBan; - ACE_OS::localtime_r(&timeBan, &tmBan); + localtime_r(&timeBan, &tmBan); if (fields2[0].GetUInt32() == fields2[1].GetUInt32()) { @@ -471,7 +471,7 @@ public: { time_t timeUnban = time_t(fields2[1].GetUInt32()); tm tmUnban; - ACE_OS::localtime_r(&timeUnban, &tmUnban); + localtime_r(&timeUnban, &tmUnban); handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", accountName.c_str(), tmBan.tm_year%100, tmBan.tm_mon+1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min, tmUnban.tm_year%100, tmUnban.tm_mon+1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min, @@ -548,7 +548,7 @@ public: { time_t timeBan = time_t(banFields[0].GetUInt32()); tm tmBan; - ACE_OS::localtime_r(&timeBan, &tmBan); + localtime_r(&timeBan, &tmBan); if (banFields[0].GetUInt32() == banFields[1].GetUInt32()) { @@ -560,7 +560,7 @@ public: { time_t timeUnban = time_t(banFields[1].GetUInt32()); tm tmUnban; - ACE_OS::localtime_r(&timeUnban, &tmUnban); + localtime_r(&timeUnban, &tmUnban); handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", char_name.c_str(), tmBan.tm_year%100, tmBan.tm_mon+1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min, tmUnban.tm_year%100, tmUnban.tm_mon+1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min, @@ -630,7 +630,7 @@ public: Field* fields = result->Fetch(); time_t timeBan = time_t(fields[1].GetUInt32()); tm tmBan; - ACE_OS::localtime_r(&timeBan, &tmBan); + localtime_r(&timeBan, &tmBan); if (fields[1].GetUInt32() == fields[2].GetUInt32()) { handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|", @@ -641,7 +641,7 @@ public: { time_t timeUnban = time_t(fields[2].GetUInt32()); tm tmUnban; - ACE_OS::localtime_r(&timeUnban, &tmUnban); + localtime_r(&timeUnban, &tmUnban); handler->PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|", fields[0].GetCString(), tmBan.tm_year%100, tmBan.tm_mon+1, tmBan.tm_mday, tmBan.tm_hour, tmBan.tm_min, tmUnban.tm_year%100, tmUnban.tm_mon+1, tmUnban.tm_mday, tmUnban.tm_hour, tmUnban.tm_min, diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index f18f9b4499c..d0050a0d4fd 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -745,14 +745,14 @@ public: if (item->GetOwnerGUID() != player->GetGUID()) { - handler->PSendSysMessage("queue(" SIZEFMTD "): For the item with guid %d, the owner's guid (%d) and the player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); + handler->PSendSysMessage("queue(%zu): For the item with guid %d, the owner's guid (%d) and the player's guid (%d) don't match!", i, item->GetGUIDLow(), GUID_LOPART(item->GetOwnerGUID()), player->GetGUIDLow()); error = true; continue; } if (item->GetQueuePos() != i) { - handler->PSendSysMessage("queue(" SIZEFMTD "): For the item with guid %d, the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); + handler->PSendSysMessage("queue(%zu): For the item with guid %d, the queuepos doesn't match it's position in the queue!", i, item->GetGUIDLow()); error = true; continue; } @@ -764,14 +764,14 @@ public: if (test == NULL) { - handler->PSendSysMessage("queue(" SIZEFMTD "): The bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have any item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); + handler->PSendSysMessage("queue(%zu): The bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have any item at that position!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); error = true; continue; } if (test != item) { - handler->PSendSysMessage("queue(" SIZEFMTD "): The bag(%d) and slot(%d) values for the item with guid %d are incorrect, an item which guid is %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); + handler->PSendSysMessage("queue(%zu): The bag(%d) and slot(%d) values for the item with guid %d are incorrect, an item which guid is %d is there instead!", i, item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); error = true; continue; } diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index a2c0861c113..90fd0bdd71c 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -123,7 +123,7 @@ public: bool first = true; bool footer = false; - TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); HashMapHolder<Player>::MapType const& m = sObjectAccessor->GetPlayers(); for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) { diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 4dd6bee8a2b..76d5e0ebdaf 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -30,7 +30,6 @@ #include "SpellAuras.h" #include "TargetedMovementGenerator.h" #include "WeatherMgr.h" -#include "ace/INET_Addr.h" #include "Player.h" #include "Pet.h" #include "LFG.h" diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index d89edd4d925..0be5994e8ed 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -98,7 +98,7 @@ public: Movement::PointsArray const& pointPath = path.GetPath(); handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str()); handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : "SmoothPath"); - handler->PSendSysMessage("Result: %s - Length: " SIZEFMTD " - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType()); + handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType()); G3D::Vector3 const &start = path.GetStartPosition(); G3D::Vector3 const &end = path.GetEndPosition(); @@ -273,7 +273,7 @@ public: if (!creatureList.empty()) { - handler->PSendSysMessage("Found " SIZEFMTD " Creatures.", creatureList.size()); + handler->PSendSysMessage("Found %zu Creatures.", creatureList.size()); uint32 paths = 0; uint32 uStartTime = getMSTime(); diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index e7f1bf2d615..00a669609f9 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -297,7 +297,7 @@ public: stmt->setUInt16(0, uint16(atLogin)); CharacterDatabase.Execute(stmt); - TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); + boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock()); HashMapHolder<Player>::MapType const& plist = sObjectAccessor->GetPlayers(); for (HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr) itr->second->SetAtLoginFlag(atLogin); diff --git a/src/server/shared/AutoPtr.h b/src/server/shared/AutoPtr.h deleted file mode 100644 index 96ecbfc79fe..00000000000 --- a/src/server/shared/AutoPtr.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 _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 af113801067..a61248f01ea 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -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.h b/src/server/shared/Common.h index f49bbf0bada..8cab769ec8a 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -79,22 +79,12 @@ #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 #else # include <sys/types.h> # include <sys/ioctl.h> @@ -123,8 +113,6 @@ inline float finiteAlways(float f) { return finite(f) ? f : 0.0f; } -#define atol(a) strtoul( a, NULL, 10) - #define STRINGIZE(a) #a enum TimeConstants @@ -187,20 +175,4 @@ typedef std::vector<std::string> StringVector; #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/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index 3f8997e6d55..5cd7ef52f82 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -16,57 +16,38 @@ * 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(); +using namespace boost::property_tree; - 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; -} - -bool ConfigMgr::LoadInitial(char const* file) +bool ConfigMgr::LoadInitial(std::string const& file) { - 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; + boost::property_tree::ini_parser::read_ini(file, fullTree); -bool ConfigMgr::LoadMore(char const* file) -{ - ASSERT(file); - ASSERT(_config); + if (fullTree.empty()) + 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 (std::exception const& /*ex*/) + { + return false; + } - return LoadData(file); + return true; } bool ConfigMgr::Reload() @@ -74,78 +55,54 @@ bool ConfigMgr::Reload() return LoadInitial(_filename.c_str()); } -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 4693b21a0c7..68daca5440f 100644 --- a/src/server/shared/Configuration/Config.h +++ b/src/server/shared/Configuration/Config.h @@ -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); - /** - * 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 = new ConfigMgr(); + return instance; + } bool Reload(); - 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/Cryptography/ARC4.h b/src/server/shared/Cryptography/ARC4.h index 5304b0730a6..11d3d4ba87b 100644 --- a/src/server/shared/Cryptography/ARC4.h +++ b/src/server/shared/Cryptography/ARC4.h @@ -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/BigNumber.cpp b/src/server/shared/Cryptography/BigNumber.cpp index 1f3fc96e28d..c5e0635c5ec 100644 --- a/src/server/shared/Cryptography/BigNumber.cpp +++ b/src/server/shared/Cryptography/BigNumber.cpp @@ -16,13 +16,11 @@ * 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 <algorithm> -#include <ace/Auto_Ptr.h> +#include <memory> BigNumber::BigNumber() : _bn(BN_new()) @@ -170,7 +168,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 +184,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 dc553babec9..684a25e8801 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -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/OpenSSLCrypto.cpp b/src/server/shared/Cryptography/OpenSSLCrypto.cpp index bd72459e9df..6d8d6584e6c 100644 --- a/src/server/shared/Cryptography/OpenSSLCrypto.cpp +++ b/src/server/shared/Cryptography/OpenSSLCrypto.cpp @@ -17,28 +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) { -/// ACE_thread_t turns out to be a struct under Mac OS. -#ifndef __APPLE__ - CRYPTO_THREADID_set_numeric(id, ACE_Thread::self()); -#else - CRYPTO_THREADID_set_pointer(id, ACE_Thread::self()); -#endif + CRYPTO_THREADID_set_numeric(id, std::hash<std::thread::id>()(std::this_thread::get_id())); } void OpenSSLCrypto::threadsSetup() @@ -46,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); @@ -61,4 +56,4 @@ void OpenSSLCrypto::threadsCleanup() delete cryptoLocks[i]; } cryptoLocks.resize(0); -}
\ No newline at end of file +} diff --git a/src/server/shared/Database/AdhocStatement.cpp b/src/server/shared/Database/AdhocStatement.cpp index 896fefde5b7..7fae9173d20 100644 --- a/src/server/shared/Database/AdhocStatement.cpp +++ b/src/server/shared/Database/AdhocStatement.cpp @@ -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() @@ -45,11 +43,11 @@ bool BasicStatementTask::Execute() if (!result || !result->GetRowCount() || !result->NextRow()) { delete result; - m_result.set(QueryResult(NULL)); + m_result->set_value(QueryResult(NULL)); return false; } - 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 44a9fa3d3ee..40c1dbb7098 100644 --- a/src/server/shared/Database/AdhocStatement.h +++ b/src/server/shared/Database/AdhocStatement.h @@ -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/DatabaseWorker.cpp b/src/server/shared/Database/DatabaseWorker.cpp index 3581f8e0211..3944c008652 100644 --- a/src/server/shared/Database/DatabaseWorker.cpp +++ b/src/server/shared/Database/DatabaseWorker.cpp @@ -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; + + _queue->Cancel(); + + _workerThread.join(); +} + +void DatabaseWorker::WorkerThread() +{ + if (!_queue) + return; - SQLOperation *request = NULL; while (1) { - request = (SQLOperation*)(m_queue->dequeue()); - if (!request) - break; + SQLOperation* operation = nullptr; - request->SetConnection(m_conn); - request->call(); + _queue->WaitAndPop(operation); - delete request; - } + if (_cancelationToken) + 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 dc883dd3428..6f452c767f6 100644 --- a/src/server/shared/Database/DatabaseWorker.h +++ b/src/server/shared/Database/DatabaseWorker.h @@ -18,24 +18,26 @@ #ifndef _WORKERTHREAD_H #define _WORKERTHREAD_H -#include "Define.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: - 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; diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 9c56c75bf71..f0b540022da 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -18,8 +18,6 @@ #ifndef _DATABASEWORKERPOOL_H #define _DATABASEWORKERPOOL_H -#include <ace/Thread_Mutex.h> - #include "Common.h" #include "Callback.h" #include "MySQLConnection.h" @@ -51,8 +49,7 @@ class DatabaseWorkerPool /* Activity state */ DatabaseWorkerPool() : _connectionInfo(NULL) { - _messageQueue = new ACE_Message_Queue<ACE_SYNCH>(8 * 1024 * 1024, 8 * 1024 * 1024); - _queue = new ACE_Activation_Queue(_messageQueue); + _queue = new ProducerConsumerQueue<SQLOperation*>(); memset(_connectionCount, 0, sizeof(_connectionCount)); _connections.resize(IDX_SIZE); @@ -107,16 +104,10 @@ 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. } @@ -131,9 +122,7 @@ 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; - delete _messageQueue; TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); @@ -307,10 +296,9 @@ 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); Enqueue(task); - return res; //! Actual return value has no use yet + return task->GetFuture(); //! Actual return value has no use yet } //! 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. @@ -331,10 +319,9 @@ 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); Enqueue(task); - return res; + return task->GetFuture(); } //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture @@ -343,10 +330,9 @@ 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); Enqueue(task); - return res; //! Fool compiler, has no use yet + return task->GetFuture(); } /** @@ -416,7 +402,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); @@ -426,7 +412,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); @@ -488,7 +474,7 @@ class DatabaseWorkerPool void Enqueue(SQLOperation* op) { - _queue->enqueue(op); + _queue->Push(op); } //! Gets a free connection in the synchronous connection pool. @@ -523,11 +509,10 @@ class DatabaseWorkerPool IDX_SIZE }; - ACE_Message_Queue<ACE_SYNCH>* _messageQueue; //! Message Queue used by ACE_Activation_Queue - ACE_Activation_Queue* _queue; //! Queue shared by async worker threads. - std::vector< std::vector<T*> > _connections; - uint32 _connectionCount[2]; //! Counter of MySQL connections; - 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/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index 98d7fe231f1..61167681b0b 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -26,7 +26,7 @@ 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(); diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 604e9d39551..7fa2ff49324 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -26,7 +26,7 @@ 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(); diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index a815373a1c6..c8c38d8a629 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -26,7 +26,7 @@ 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(); diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 55d47c76430..8b24f508331 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -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), @@ -500,8 +501,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 +516,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 512df7c16c7..61b3b37cbc2 100644 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -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 @@ -70,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(); @@ -99,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; } @@ -125,12 +124,12 @@ 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; diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h index 0f6af8ace20..da234138879 100644 --- a/src/server/shared/Database/MySQLThreading.h +++ b/src/server/shared/Database/MySQLThreading.h @@ -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 fe052bf5043..fb1bfa687d0 100644 --- a/src/server/shared/Database/PreparedStatement.cpp +++ b/src/server/shared/Database/PreparedStatement.cpp @@ -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_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 6afb309db2c..16f7a9141d3 100644 --- a/src/server/shared/Database/PreparedStatement.h +++ b/src/server/shared/Database/PreparedStatement.h @@ -18,8 +18,8 @@ #ifndef _PREPAREDSTATEMENT_H #define _PREPAREDSTATEMENT_H +#include <future> #include "SQLOperation.h" -#include <ace/Future.h> #ifdef __APPLE__ #undef TYPE_BOOL @@ -153,21 +153,22 @@ class MySQLPreparedStatement 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(); + 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 7b4105ee076..bd938561b50 100644 --- a/src/server/shared/Database/QueryHolder.cpp +++ b/src/server/shared/Database/QueryHolder.cpp @@ -168,9 +168,6 @@ void SQLQueryHolder::SetSize(size_t size) bool SQLQueryHolderTask::Execute() { - //the result can't be ready as we are processing it right now - ASSERT(!m_result.ready()); - if (!m_holder) return false; @@ -202,6 +199,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 b92b2e5327e..37e23ecd653 100644 --- a/src/server/shared/Database/QueryHolder.h +++ b/src/server/shared/Database/QueryHolder.h @@ -18,7 +18,7 @@ #ifndef _QUERYHOLDER_H #define _QUERYHOLDER_H -#include <ace/Future.h> +#include <future> class SQLQueryHolder { @@ -39,18 +39,21 @@ 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; public: - SQLQueryHolderTask(SQLQueryHolder *holder, QueryResultHolderFuture res) - : m_holder(holder), m_result(res){ }; + SQLQueryHolderTask(SQLQueryHolder* holder) + : m_holder(holder) { }; + bool Execute(); + QueryResultHolderFuture GetFuture() { return m_result.get_future(); } }; diff --git a/src/server/shared/Database/QueryResult.h b/src/server/shared/Database/QueryResult.h index 4795fef4a4c..e8c277c03cf 100644 --- a/src/server/shared/Database/QueryResult.h +++ b/src/server/shared/Database/QueryResult.h @@ -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 @@ -60,7 +58,7 @@ class ResultSet ResultSet& operator=(ResultSet const& right) = delete; }; -typedef Trinity::AutoPtr<ResultSet, ACE_Thread_Mutex> QueryResult; +typedef std::shared_ptr<ResultSet> QueryResult; class PreparedResultSet { @@ -107,7 +105,7 @@ class PreparedResultSet 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 6f933a051e3..4d6e349449d 100644 --- a/src/server/shared/Database/SQLOperation.h +++ b/src/server/shared/Database/SQLOperation.h @@ -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(); diff --git a/src/server/shared/Database/Transaction.h b/src/server/shared/Database/Transaction.h index cb28f0ad876..c7cbbbbe712 100644 --- a/src/server/shared/Database/Transaction.h +++ b/src/server/shared/Database/Transaction.h @@ -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 diff --git a/src/server/shared/Debugging/Errors.cpp b/src/server/shared/Debugging/Errors.cpp index d656dc3fb4a..62e97d56d42 100644 --- a/src/server/shared/Debugging/Errors.cpp +++ b/src/server/shared/Debugging/Errors.cpp @@ -18,17 +18,15 @@ #include "Errors.h" -#include <ace/Stack_Trace.h> -#include <ace/OS_NS_unistd.h> #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 +35,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/Define.h b/src/server/shared/Define.h index e43853e5bb0..e173925f314 100644 --- a/src/server/shared/Define.h +++ b/src/server/shared/Define.h @@ -21,21 +21,25 @@ #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 +#endif #include <cstddef> +#include <cinttypes> #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 @@ -70,21 +74,19 @@ # define ATTR_DEPRECATED #endif //COMPILER == COMPILER_GNU -#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 aee84ab151e..a009fd37a7e 100644 --- a/src/server/shared/Dynamic/FactoryHolder.h +++ b/src/server/shared/Dynamic/FactoryHolder.h @@ -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/ObjectRegistry.h b/src/server/shared/Dynamic/ObjectRegistry.h index be7ce00ac05..e9e57415073 100644 --- a/src/server/shared/Dynamic/ObjectRegistry.h +++ b/src/server/shared/Dynamic/ObjectRegistry.h @@ -20,12 +20,10 @@ #define TRINITY_OBJECTREGISTRY_H #include "Define.h" -#include <ace/Singleton.h> #include <string> -#include <vector> #include <map> -#include <unordered_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 = new ObjectRegistry<T, Key>(); + return instance; + } /// Returns a registry item const T* GetRegistryItem(Key key) const diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp index 718c3a406f1..2b38f9886c3 100644 --- a/src/server/shared/Logging/Appender.cpp +++ b/src/server/shared/Logging/Appender.cpp @@ -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 84d0dc14eca..67213d0ddd0 100644 --- a/src/server/shared/Logging/Appender.h +++ b/src/server/shared/Logging/Appender.h @@ -18,10 +18,10 @@ #ifndef APPENDER_H #define APPENDER_H -#include "Define.h" -#include <time.h> #include <unordered_map> #include <string> +#include <time.h> +#include "Define.h" // Values assigned have their equivalent in enum ACE_Log_Priority enum LogLevel diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp index 14d434e35b8..8102d3b6021 100644 --- a/src/server/shared/Logging/AppenderConsole.cpp +++ b/src/server/shared/Logging/AppenderConsole.cpp @@ -15,11 +15,15 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <sstream> +#if PLATFORM == PLATFORM_WINDOWS + #include <windows.h> +#endif + #include "AppenderConsole.h" #include "Config.h" #include "Util.h" -#include <sstream> 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 1aaa74e96ec..b8f15b4fa0f 100644 --- a/src/server/shared/Logging/AppenderConsole.h +++ b/src/server/shared/Logging/AppenderConsole.h @@ -18,8 +18,8 @@ #ifndef APPENDERCONSOLE_H #define APPENDERCONSOLE_H -#include "Appender.h" #include <string> +#include "Appender.h" enum ColorTypes { diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp index f2532ad8bb8..3e79ac40c6f 100644 --- a/src/server/shared/Logging/AppenderFile.cpp +++ b/src/server/shared/Logging/AppenderFile.cpp @@ -45,7 +45,7 @@ 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) { diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index 1034b41f665..a600c92d152 100644 --- a/src/server/shared/Logging/AppenderFile.h +++ b/src/server/shared/Logging/AppenderFile.h @@ -18,8 +18,8 @@ #ifndef APPENDERFILE_H #define APPENDERFILE_H +#include <atomic> #include "Appender.h" -#include "ace/Atomic_Op.h" class AppenderFile: public Appender { @@ -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 dc9bda62bfb..65cf930a634 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -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 a118e6e8773..e739c9eaf4e 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -22,18 +22,17 @@ #include "Define.h" #include "Appender.h" #include "Logger.h" -#include "LogWorker.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 std::unordered_map<std::string, Logger> LoggerMap; private: @@ -41,6 +40,20 @@ class Log ~Log(); public: + + static Log* instance(boost::asio::io_service* ioService = nullptr) + { + static Log* instance = new Log(); + + 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,7 +131,7 @@ 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 PLATFORM != PLATFORM_WINDOWS #define TC_LOG_MESSAGE_BODY(filterType__, level__, ...) \ diff --git a/src/server/shared/Logging/LogWorker.cpp b/src/server/shared/Logging/LogWorker.cpp deleted file mode 100644 index b0c82b614f4..00000000000 --- a/src/server/shared/Logging/LogWorker.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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/>. - */ - -#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 25a57842e08..00000000000 --- a/src/server/shared/Logging/LogWorker.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 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/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h new file mode 100644 index 00000000000..d056731bb79 --- /dev/null +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -0,0 +1,65 @@ +/* +* 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 <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) + { + // 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(); + } + + // 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/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp index f446592e922..0a911492f85 100644 --- a/src/server/shared/Packets/ByteBuffer.cpp +++ b/src/server/shared/Packets/ByteBuffer.cpp @@ -20,7 +20,6 @@ #include "Common.h" #include "Log.h" -#include <ace/Stack_Trace.h> #include <sstream> ByteBufferPositionException::ByteBufferPositionException(bool add, size_t pos, diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 11e835566e9..81c6bcd977c 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -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> @@ -476,7 +476,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); } diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h index c48546bbf5c..b462fce25d5 100644 --- a/src/server/shared/Threading/Callback.h +++ b/src/server/shared/Threading/Callback.h @@ -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,7 +103,7 @@ class QueryCallback } private: - ACE_Future<Result> _result; + std::future<Result> _result; ParamType _param; uint8 _stage; @@ -121,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) @@ -200,7 +197,7 @@ class QueryCallback_2 } private: - ACE_Future<Result> _result; + std::future<Result> _result; ParamType1 _param_1; ParamType2 _param_2; uint8 _stage; @@ -209,4 +206,4 @@ class QueryCallback_2 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 5709724c9a2..bbd60cb7760 100644 --- a/src/server/shared/Threading/LockedQueue.h +++ b/src/server/shared/Threading/LockedQueue.h @@ -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..cd116ccbbc8 --- /dev/null +++ b/src/server/shared/Threading/ProcessPriority.h @@ -0,0 +1,100 @@ +/* +* 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) +{ +#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..3fefd27ba6e --- /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> + +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) + { + _queueLock.lock(); + + _queue.push(std::move(value)); + + _queueLock.unlock(); + + _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()) + return false; + + value = _queue.front(); + + _queue.pop(); + + return true; + } + + void WaitAndPop(T& value) + { + std::unique_lock<std::mutex> lock(_queueLock); + + while (_queue.empty() && !_shutdown) + { + _condition.wait(lock); + } + + if (_queue.empty()) + return; + + value = _queue.front(); + + _queue.pop(); + } + + void Cancel() + { + _queueLock.lock(); + + while (!_queue.empty()) + { + T& value = _queue.front(); + + delete &value; + + _queue.pop(); + } + + _shutdown = true; + + _queueLock.unlock(); + + _condition.notify_all(); + } +}; + +#endif + + diff --git a/src/server/shared/Threading/Threading.cpp b/src/server/shared/Threading/Threading.cpp deleted file mode 100644 index f67a985943a..00000000000 --- a/src/server/shared/Threading/Threading.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* - * 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 - * 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 9d416109e9f..00000000000 --- a/src/server/shared/Threading/Threading.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 - * 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/ServiceWin32.cpp b/src/server/shared/Utilities/ServiceWin32.cpp index ec472b33f40..f4a0339d9e6 100644 --- a/src/server/shared/Utilities/ServiceWin32.cpp +++ b/src/server/shared/Utilities/ServiceWin32.cpp @@ -60,7 +60,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 +119,8 @@ bool WinServiceInstall() } CloseServiceHandle(serviceControlManager); } + + printf("Service installed\n"); return true; } @@ -143,6 +145,8 @@ bool WinServiceUninstall() CloseServiceHandle(serviceControlManager); } + + printf("Service uninstalled\n"); return true; } diff --git a/src/server/shared/Utilities/SignalHandler.h b/src/server/shared/Utilities/SignalHandler.h deleted file mode 100644 index 41e867c3d1a..00000000000 --- a/src/server/shared/Utilities/SignalHandler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2008-2014 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 c809a59c20f..7c62de5f5ed 100644 --- a/src/server/shared/Utilities/Timer.h +++ b/src/server/shared/Utilities/Timer.h @@ -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 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 28bbe831a69..a65f54f87fc 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -21,42 +21,54 @@ #include "utf8.h" #include "SFMT.h" #include "Errors.h" // for ASSERT -#include <ace/TSS_T.h> +#include <boost/thread/tss.hpp> -typedef ACE_TSS<SFMTRand> SFMTRandTSS; -static SFMTRandTSS sfmtRand; +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() { - return int32(sfmtRand->BRandom()); + return int32(GetRng()->BRandom()); } double rand_norm(void) { - return sfmtRand->Random(); + return GetRng()->Random(); } double rand_chance(void) { - return sfmtRand->Random() * 100.0; + return GetRng()->Random() * 100.0; } Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve) @@ -127,6 +139,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 +236,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 +259,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) { diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index 648edf39abe..c384a6eeaed 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -27,7 +27,6 @@ #include <vector> #include <list> #include <map> -#include <ace/INET_Addr.h> // Searcher for map of structs template<typename T, class S> struct Finder @@ -71,6 +70,8 @@ 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); @@ -347,12 +348,6 @@ 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); diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 78a29dbedf6..80c76352b36 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -11,7 +11,6 @@ file(GLOB_RECURSE sources_CommandLine CommandLine/*.cpp CommandLine/*.h) file(GLOB_RECURSE sources_RemoteAccess RemoteAccess/*.cpp RemoteAccess/*.h) file(GLOB_RECURSE sources_TCSoap TCSoap/*.cpp TCSoap/*.h) -file(GLOB_RECURSE sources_WorldThread WorldThread/*.cpp WorldThread/*.h) file(GLOB sources_localdir *.cpp *.h) if (USE_COREPCH) @@ -24,7 +23,6 @@ set(worldserver_SRCS ${sources_CommandLine} ${sources_RemoteAccess} ${sources_TCSoap} - ${sources_WorldThread} ${sources_localdir} ) @@ -62,6 +60,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic ${CMAKE_SOURCE_DIR}/src/server/shared/Logging + ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities @@ -137,8 +136,6 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/CommandLine ${CMAKE_CURRENT_SOURCE_DIR}/RemoteAccess ${CMAKE_CURRENT_SOURCE_DIR}/TCSoap - ${CMAKE_CURRENT_SOURCE_DIR}/WorldThread - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) @@ -173,11 +170,11 @@ target_link_libraries(worldserver ${JEMALLOC_LIBRARY} ${READLINE_LIBRARY} ${TERMCAP_LIBRARY} - ${ACE_LIBRARY} ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} ) if( WIN32 ) diff --git a/src/server/worldserver/CommandLine/CliRunnable.cpp b/src/server/worldserver/CommandLine/CliRunnable.cpp index ac46b218305..295e63c696b 100644 --- a/src/server/worldserver/CommandLine/CliRunnable.cpp +++ b/src/server/worldserver/CommandLine/CliRunnable.cpp @@ -131,7 +131,7 @@ int kb_hit_return() #endif /// %Thread start -void CliRunnable::run() +void CliThread() { ///- Display the list of available CLI functions then beep //TC_LOG_INFO("server.worldserver", ""); diff --git a/src/server/worldserver/CommandLine/CliRunnable.h b/src/server/worldserver/CommandLine/CliRunnable.h index 5510173973e..7ed3a44995f 100644 --- a/src/server/worldserver/CommandLine/CliRunnable.h +++ b/src/server/worldserver/CommandLine/CliRunnable.h @@ -23,12 +23,7 @@ #ifndef __CLIRUNNABLE_H #define __CLIRUNNABLE_H -/// Command Line Interface handling thread -class CliRunnable : public ACE_Based::Runnable -{ - public: - void run() override; -}; +void CliThread(); #endif diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 75d9ca5145d..c28adbc7c21 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -22,19 +22,38 @@ #include <openssl/opensslv.h> #include <openssl/crypto.h> -#include <ace/Version.h> +#include <boost/asio/io_service.hpp> +#include <boost/asio/deadline_timer.hpp> +#include <boost/program_options.hpp> #include "Common.h" -#include "Database/DatabaseEnv.h" +#include "DatabaseEnv.h" +#include "AsyncAcceptor.h" +#include "RASession.h" #include "Configuration/Config.h" +#include "OpenSSLCrypto.h" +#include "ProcessPriority.h" +#include "BigNumber.h" +#include "RealmList.h" +#include "World.h" +#include "MapManager.h" +#include "ObjectAccessor.h" +#include "ScriptMgr.h" +#include "OutdoorPvP/OutdoorPvPMgr.h" +#include "BattlegroundMgr.h" +#include "TCSoap.h" +#include "CliRunnable.h" +#include "SystemConfig.h" +#include "WorldSocket.h" -#include "Log.h" -#include "Master.h" +using namespace boost::program_options; #ifndef _TRINITY_CORE_CONFIG -# define _TRINITY_CORE_CONFIG "worldserver.conf" + #define _TRINITY_CORE_CONFIG "worldserver.conf" #endif +#define WORLD_SLEEP_CONST 50 + #ifdef _WIN32 #include "ServiceWin32.h" char serviceName[] = "worldserver"; @@ -49,104 +68,508 @@ char serviceDescription[] = "TrinityCore World of Warcraft emulator world servic int m_ServiceStatus = -1; #endif +boost::asio::io_service _ioService; +boost::asio::deadline_timer _freezeCheckTimer(_ioService); +uint32 _worldLoopCounter(0); +uint32 _lastChangeMsTime(0); +uint32 _maxCoreStuckTimeInMs(0); + WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database - uint32 realmID; ///< Id of the realm -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - printf("Usage:\n"); - printf(" %s [<options>]\n", prog); - printf(" -c config_file use config_file as configuration file\n"); -#ifdef _WIN32 - printf(" Running as service functions:\n"); - printf(" --service run as service\n"); - printf(" -s install install service\n"); - printf(" -s uninstall uninstall service\n"); -#endif -} +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void FreezeDetectorHandler(const boost::system::error_code& error); +AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService); +bool StartDB(); +void StopDB(); +void WorldUpdateLoop(); +void ClearOnlineAccounts(); +variables_map GetConsoleArguments(int argc, char** argv, std::string& cfg_file, std::string& cfg_service); /// Launch the Trinity server extern int main(int argc, char** argv) { - ///- Command line parsing to get the configuration file name - char const* cfg_file = _TRINITY_CORE_CONFIG; - int c = 1; - while (c < argc) - { - if (!strcmp(argv[c], "-c")) - { - if (++c >= argc) - { - printf("Runtime-Error: -c option requires an input argument"); - usage(argv[0]); - return 1; - } - else - cfg_file = argv[c]; - } + std::string configFile = _TRINITY_CORE_CONFIG; + std::string configService; - #ifdef _WIN32 - if (strcmp(argv[c], "-s") == 0) // Services - { - if (++c >= argc) - { - printf("Runtime-Error: -s option requires an input argument"); - usage(argv[0]); - return 1; - } - - if (strcmp(argv[c], "install") == 0) - { - if (WinServiceInstall()) - printf("Installing service\n"); - return 1; - } - else if (strcmp(argv[c], "uninstall") == 0) - { - if (WinServiceUninstall()) - printf("Uninstalling service\n"); - return 1; - } - else - { - printf("Runtime-Error: unsupported option %s", argv[c]); - usage(argv[0]); - return 1; - } - } + auto vm = GetConsoleArguments(argc, argv, configFile, configService); + // exit if help is enabled + if (vm.count("help")) + return 0; - if (strcmp(argv[c], "--service") == 0) + if (!configService.empty()) + { + if (configService.compare("install") == 0) + return WinServiceInstall() == true ? 0 : 1; + else if (configService.compare("uninstall") == 0) + return WinServiceUninstall() == true ? 0 : 1; + else if (configService.compare("run") == 0) WinServiceRun(); - #endif - ++c; } - if (!sConfigMgr->LoadInitial(cfg_file)) + if (!sConfigMgr->LoadInitial(configFile)) { - printf("Invalid or missing configuration file : %s\n", cfg_file); + printf("Invalid or missing configuration file : %s\n", configFile.c_str()); printf("Verify that the file exists and has \'[worldserver]' written in the top of the file!\n"); return 1; } - TC_LOG_INFO("server.worldserver", "Using configuration file %s.", cfg_file); + if (sConfigMgr->GetBoolDefault("Log.Async.Enable", false)) + { + // If logs are supposed to be handled async then we need to pass the io_service into the Log singleton + Log::instance(&_ioService); + } + TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); + TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); + TC_LOG_INFO("server.worldserver", " ______ __"); + TC_LOG_INFO("server.worldserver", "/\\__ _\\ __ __/\\ \\__"); + TC_LOG_INFO("server.worldserver", "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __"); + TC_LOG_INFO("server.worldserver", " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); + TC_LOG_INFO("server.worldserver", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); + TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); + TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); + TC_LOG_INFO("server.worldserver", " C O R E /\\___/"); + TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n"); + TC_LOG_INFO("server.worldserver", "Using configuration file %s.", configFile.c_str()); TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); - TC_LOG_INFO("server.worldserver", "Using ACE version: %s", ACE_VERSION); + TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); + + OpenSSLCrypto::threadsSetup(); + + // Seed the OpenSSL's PRNG here. + // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login + BigNumber seed; + seed.SetRand(16 * 8); + + /// worldserver PID file creation + std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); + if (!pidFile.empty()) + { + if (uint32 pid = CreatePIDFile(pidFile)) + TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid); + else + { + TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str()); + return 1; + } + } + + // Set signal handlers (this must be done before starting io_service threads, because otherwise they would unblock and exit) + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); + signals.async_wait(SignalHandler); - ///- and run the 'Master' - /// @todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd? - int ret = sMaster->Run(); + // Start the Boost based thread pool + int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1); + std::vector<std::thread> threadPool; + + if (numThreads < 1) + numThreads = 1; + + for (int i = 0; i < numThreads; ++i) + threadPool.push_back(std::thread(boost::bind(&boost::asio::io_service::run, &_ioService))); + + // Set process priority according to configuration settings + SetProcessPriority("server.worldserver"); + + // Start the databases + if (!StartDB()) + return 1; + + // Set server offline (not connectable) + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); + + // Initialize the World + sWorld->SetInitialWorldSettings(); + + // Launch CliRunnable thread + std::thread* cliThread = nullptr; +#ifdef _WIN32 + if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) +#else + if (sConfigMgr->GetBoolDefault("Console.Enable", true)) +#endif + { + cliThread = new std::thread(CliThread); + } + + // Start the Remote Access port (acceptor) if enabled + AsyncAcceptor<RASession>* raAcceptor = nullptr; + if (sConfigMgr->GetBoolDefault("Ra.Enable", false)) + raAcceptor = StartRaSocketAcceptor(_ioService); + + // Start soap serving thread if enabled + std::thread* soapThread = nullptr; + if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) + { + soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); + } + + // Launch the worldserver listener socket + uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); + std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + bool tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); + + AsyncAcceptor<WorldSocket> worldAcceptor(_ioService, worldListener, worldPort, tcpNoDelay); + + sScriptMgr->OnStartup(); + + // Set server online (allow connecting now) + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); + + // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) + if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) + { + _maxCoreStuckTimeInMs = coreStuckTime * 1000; + _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(5)); + _freezeCheckTimer.async_wait(FreezeDetectorHandler); + TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", coreStuckTime); + } + + TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); + + WorldUpdateLoop(); + + // Shutdown starts here + + _ioService.stop(); + + for (auto& thread : threadPool) + { + thread.join(); + } + + sScriptMgr->OnShutdown(); + + sWorld->KickAll(); // save and kick all players + sWorld->UpdateSessions(1); // real players unload required UpdateSessions call + + // unload battleground templates before different singletons destroyed + sBattlegroundMgr->DeleteAllBattlegrounds(); + + sMapMgr->UnloadAll(); // unload all grids (including locked in memory) + sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world + sScriptMgr->Unload(); + sOutdoorPvPMgr->Die(); + + // set server offline + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); + + // Clean up threads if any + if (soapThread != nullptr) + { + soapThread->join(); + delete soapThread; + } + + if (raAcceptor != nullptr) + delete raAcceptor; + + ///- Clean database before leaving + ClearOnlineAccounts(); + + StopDB(); + + TC_LOG_INFO("server.worldserver", "Halting process..."); + + if (cliThread != nullptr) + { +#ifdef _WIN32 + + // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) + //_exit(1); + // send keyboard input to safely unblock the CLI thread + INPUT_RECORD b[4]; + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + b[0].EventType = KEY_EVENT; + b[0].Event.KeyEvent.bKeyDown = TRUE; + b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; + b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; + b[0].Event.KeyEvent.wRepeatCount = 1; + + b[1].EventType = KEY_EVENT; + b[1].Event.KeyEvent.bKeyDown = FALSE; + b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; + b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; + b[1].Event.KeyEvent.wRepeatCount = 1; + + b[2].EventType = KEY_EVENT; + b[2].Event.KeyEvent.bKeyDown = TRUE; + b[2].Event.KeyEvent.dwControlKeyState = 0; + b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; + b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + b[2].Event.KeyEvent.wRepeatCount = 1; + b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; + + b[3].EventType = KEY_EVENT; + b[3].Event.KeyEvent.bKeyDown = FALSE; + b[3].Event.KeyEvent.dwControlKeyState = 0; + b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; + b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; + b[3].Event.KeyEvent.wRepeatCount = 1; + DWORD numb; + WriteConsoleInput(hStdIn, b, 4, &numb); + + cliThread->join(); + +#endif + + delete cliThread; + } + + OpenSSLCrypto::threadsCleanup(); - // at sMaster return function exist with codes // 0 - normal shutdown // 1 - shutdown at error // 2 - restart command used, this code can be used by restarter for restart Trinityd - return ret; + return World::GetExitCode(); +} + + +void WorldUpdateLoop() +{ + uint32 realCurrTime = 0; + uint32 realPrevTime = getMSTime(); + + uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST + + ///- While we have not World::m_stopEvent, update the world + while (!World::IsStopped()) + { + ++World::m_worldLoopCounter; + realCurrTime = getMSTime(); + + uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime); + + sWorld->Update(diff); + realPrevTime = realCurrTime; + + // diff (D0) include time of previous sleep (d0) + tick time (t0) + // we want that next d1 + t1 == WORLD_SLEEP_CONST + // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement + // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 + if (diff <= WORLD_SLEEP_CONST + prevSleepTime) + { + prevSleepTime = WORLD_SLEEP_CONST + prevSleepTime - diff; + + std::this_thread::sleep_for(std::chrono::milliseconds(prevSleepTime)); + } + else + prevSleepTime = 0; + +#ifdef _WIN32 + if (m_ServiceStatus == 0) + World::StopNow(SHUTDOWN_EXIT_CODE); + + while (m_ServiceStatus == 2) + Sleep(1000); +#endif + } +} + +void SignalHandler(const boost::system::error_code& error, int signalNumber) +{ + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + World::StopNow(SHUTDOWN_EXIT_CODE); + break; + } + } +} + +void FreezeDetectorHandler(const boost::system::error_code& error) +{ + if (!error) + { + uint32 curtime = getMSTime(); + + uint32 worldLoopCounter = World::m_worldLoopCounter; + if (_worldLoopCounter != worldLoopCounter) + { + _lastChangeMsTime = curtime; + _worldLoopCounter = worldLoopCounter; + } + // possible freeze + else if (getMSTimeDiff(_lastChangeMsTime, curtime) > _maxCoreStuckTimeInMs) + { + TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!"); + ASSERT(false); + } + + _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(1)); + _freezeCheckTimer.async_wait(FreezeDetectorHandler); + } +} + +AsyncAcceptor<RASession>* StartRaSocketAcceptor(boost::asio::io_service& ioService) +{ + uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443)); + std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0"); + + return new AsyncAcceptor<RASession>(ioService, raListener, raPort); +} + +/// Initialize connection to the databases +bool StartDB() +{ + MySQL::Library_Init(); + + std::string dbString; + uint8 asyncThreads, synchThreads; + + dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", ""); + if (dbString.empty()) + { + TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file"); + return false; + } + + asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1)); + if (asyncThreads < 1 || asyncThreads > 32) + { + TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. " + "Please pick a value between 1 and 32."); + return false; + } + + synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1)); + ///- Initialize the world database + if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads)) + { + TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str()); + return false; + } + + ///- Get character database info from configuration file + dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", ""); + if (dbString.empty()) + { + TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file"); + return false; + } + + asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1)); + if (asyncThreads < 1 || asyncThreads > 32) + { + TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. " + "Please pick a value between 1 and 32."); + return false; + } + + synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2)); + + ///- Initialize the Character database + if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads)) + { + TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str()); + return false; + } + + ///- Get login database info from configuration file + dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); + if (dbString.empty()) + { + TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file"); + return false; + } + + asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1)); + if (asyncThreads < 1 || asyncThreads > 32) + { + TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. " + "Please pick a value between 1 and 32."); + return false; + } + + synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1)); + ///- Initialise the login database + if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads)) + { + TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str()); + return false; + } + + ///- Get the realm Id from the configuration file + realmID = sConfigMgr->GetIntDefault("RealmID", 0); + if (!realmID) + { + TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); + return false; + } + TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID); + + ///- Clean the database before starting + ClearOnlineAccounts(); + + ///- Insert version info into DB + WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query + + sWorld->LoadDBVersion(); + + TC_LOG_INFO("server.worldserver", "Using World DB: %s", sWorld->GetDBVersion()); + return true; +} + +void StopDB() +{ + CharacterDatabase.Close(); + WorldDatabase.Close(); + LoginDatabase.Close(); + + MySQL::Library_End(); +} + +/// Clear 'online' status for all accounts with characters in this realm +void ClearOnlineAccounts() +{ + // Reset online status for all accounts with characters on the current realm + LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmID); + + // Reset online status for all characters + CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0"); + + // Battleground instance ids reset at server restart + CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0"); } /// @} + +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService) +{ + options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_CORE_CONFIG), "use <arg> as configuration file") + ; +#ifdef _WIN32 + options_description win("Windows platform specific options"); + win.add_options() + ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]") + ; + + all.add(win); +#endif + variables_map vm; + try + { + store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm); + notify(vm); + } + catch (std::exception& e) { + std::cerr << e.what() << "\n"; + } + + if (vm.count("help")) { + std::cout << all << "\n"; + } + + return vm; +} diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp deleted file mode 100644 index 6e4214603cb..00000000000 --- a/src/server/worldserver/Master.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/** \file - \ingroup Trinityd -*/ - -#include <ace/Sig_Handler.h> - -#include "Common.h" -#include "SystemConfig.h" -#include "SignalHandler.h" -#include "World.h" -#include "WorldRunnable.h" -#include "WorldSocket.h" -#include "WorldSocketMgr.h" -#include "Configuration/Config.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseWorkerPool.h" - -#include "CliRunnable.h" -#include "Log.h" -#include "Master.h" -#include "RARunnable.h" -#include "TCSoap.h" -#include "Timer.h" -#include "Util.h" -#include "AuthSocket.h" -#include "RealmList.h" - -#include "BigNumber.h" -#include "OpenSSLCrypto.h" - -#ifdef _WIN32 -#include "ServiceWin32.h" -extern int m_ServiceStatus; -#endif - -#ifdef __linux__ -#include <sched.h> -#include <sys/resource.h> -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif - -/// Handle worldservers's termination signals -class WorldServerSignalHandler : public Trinity::SignalHandler -{ - public: - virtual void HandleSignal(int sigNum) - { - switch (sigNum) - { - case SIGINT: - World::StopNow(RESTART_EXIT_CODE); - break; - case SIGTERM: -#ifdef _WIN32 - case SIGBREAK: - if (m_ServiceStatus != 1) -#endif - World::StopNow(SHUTDOWN_EXIT_CODE); - break; - } - } -}; - -class FreezeDetectorRunnable : public ACE_Based::Runnable -{ -private: - uint32 _loops; - uint32 _lastChange; - uint32 _delaytime; -public: - FreezeDetectorRunnable() - { - _loops = 0; - _lastChange = 0; - _delaytime = 0; - } - - void SetDelayTime(uint32 t) { _delaytime = t; } - - void run() override - { - if (!_delaytime) - return; - - TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", _delaytime/1000); - _loops = 0; - _lastChange = 0; - while (!World::IsStopped()) - { - ACE_Based::Thread::Sleep(1000); - uint32 curtime = getMSTime(); - // normal work - uint32 worldLoopCounter = World::m_worldLoopCounter.value(); - if (_loops != worldLoopCounter) - { - _lastChange = curtime; - _loops = worldLoopCounter; - } - // possible freeze - else if (getMSTimeDiff(_lastChange, curtime) > _delaytime) - { - TC_LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!"); - ASSERT(false); - } - } - TC_LOG_INFO("server.worldserver", "Anti-freeze thread exiting without problems."); - } -}; - -/// Main function -int Master::Run() -{ - OpenSSLCrypto::threadsSetup(); - BigNumber seed1; - seed1.SetRand(16 * 8); - - TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); - TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); - - TC_LOG_INFO("server.worldserver", " ______ __"); - TC_LOG_INFO("server.worldserver", "/\\__ _\\ __ __/\\ \\__"); - TC_LOG_INFO("server.worldserver", "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\, _\\ __ __"); - TC_LOG_INFO("server.worldserver", " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); - TC_LOG_INFO("server.worldserver", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); - TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); - TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); - TC_LOG_INFO("server.worldserver", " C O R E /\\___/"); - TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n"); - - /// worldserver PID file creation - std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); - if (!pidFile.empty()) - { - if (uint32 pid = CreatePIDFile(pidFile)) - TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid); - else - { - TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str()); - return 1; - } - } - - ///- Start the databases - if (!_StartDB()) - return 1; - - // set server offline (not connectable) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); - - ///- Initialize the World - sWorld->SetInitialWorldSettings(); - - ///- Initialize the signal handlers - WorldServerSignalHandler signalINT, signalTERM; - #ifdef _WIN32 - WorldServerSignalHandler signalBREAK; - #endif /* _WIN32 */ - - ///- Register worldserver's signal handlers - ACE_Sig_Handler handle; - handle.register_handler(SIGINT, &signalINT); - handle.register_handler(SIGTERM, &signalTERM); -#ifdef _WIN32 - handle.register_handler(SIGBREAK, &signalBREAK); -#endif - - ///- Launch WorldRunnable thread - ACE_Based::Thread worldThread(new WorldRunnable); - worldThread.setPriority(ACE_Based::Highest); - - ACE_Based::Thread* cliThread = NULL; - -#ifdef _WIN32 - if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) -#else - if (sConfigMgr->GetBoolDefault("Console.Enable", true)) -#endif - { - ///- Launch CliRunnable thread - cliThread = new ACE_Based::Thread(new CliRunnable); - } - - ACE_Based::Thread rarThread(new RARunnable); - -#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)) - { - ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors - - if (!currentAffinity) - TC_LOG_ERROR("server.worldserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff); - else if (SetProcessAffinityMask(hProcess, currentAffinity)) - TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %x", currentAffinity); - else - TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x", currentAffinity); - } - } - - if (highPriority) - { - if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) - TC_LOG_INFO("server.worldserver", "worldserver process priority class set to HIGH"); - else - TC_LOG_ERROR("server.worldserver", "Can't set worldserver 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("server.worldserver", "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("server.worldserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); - } - } - - if (highPriority) - { - if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) - TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class, error: %s", strerror(errno)); - else - TC_LOG_INFO("server.worldserver", "worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); - } - -#endif -#endif - - //Start soap serving thread - ACE_Based::Thread* soapThread = NULL; - - if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) - { - TCSoapRunnable* runnable = new TCSoapRunnable(); - runnable->SetListenArguments(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); - soapThread = new ACE_Based::Thread(runnable); - } - - ///- Start up freeze catcher thread - if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) - { - FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); - fdr->SetDelayTime(freezeDelay * 1000); - ACE_Based::Thread freezeThread(fdr); - freezeThread.setPriority(ACE_Based::Highest); - } - - ///- Launch the world listener socket - uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); - std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - - if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1) - { - TC_LOG_ERROR("server.worldserver", "Failed to start network"); - World::StopNow(ERROR_EXIT_CODE); - // go down and shutdown the server - } - - // set server online (allow connecting now) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); - - TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); - - // when the main thread closes the singletons get unloaded - // since worldrunnable uses them, it will crash if unloaded after master - worldThread.wait(); - rarThread.wait(); - - if (soapThread) - { - soapThread->wait(); - soapThread->destroy(); - delete soapThread; - } - - // set server offline - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); - - ///- Clean database before leaving - ClearOnlineAccounts(); - - _StopDB(); - - TC_LOG_INFO("server.worldserver", "Halting process..."); - - if (cliThread) - { - #ifdef _WIN32 - - // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) - //_exit(1); - // send keyboard input to safely unblock the CLI thread - INPUT_RECORD b[4]; - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - b[0].EventType = KEY_EVENT; - b[0].Event.KeyEvent.bKeyDown = TRUE; - b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; - b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; - b[0].Event.KeyEvent.wRepeatCount = 1; - - b[1].EventType = KEY_EVENT; - b[1].Event.KeyEvent.bKeyDown = FALSE; - b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; - b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; - b[1].Event.KeyEvent.wRepeatCount = 1; - - b[2].EventType = KEY_EVENT; - b[2].Event.KeyEvent.bKeyDown = TRUE; - b[2].Event.KeyEvent.dwControlKeyState = 0; - b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; - b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - b[2].Event.KeyEvent.wRepeatCount = 1; - b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; - - b[3].EventType = KEY_EVENT; - b[3].Event.KeyEvent.bKeyDown = FALSE; - b[3].Event.KeyEvent.dwControlKeyState = 0; - b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; - b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; - b[3].Event.KeyEvent.wRepeatCount = 1; - DWORD numb; - WriteConsoleInput(hStdIn, b, 4, &numb); - - cliThread->wait(); - - #else - - cliThread->destroy(); - - #endif - - delete cliThread; - } - - // for some unknown reason, unloading scripts here and not in worldrunnable - // fixes a memory leak related to detaching threads from the module - //UnloadScriptingModule(); - - OpenSSLCrypto::threadsCleanup(); - // Exit the process with specified return value - return World::GetExitCode(); -} - -/// Initialize connection to the databases -bool Master::_StartDB() -{ - MySQL::Library_Init(); - - std::string dbString; - uint8 asyncThreads, synchThreads; - - dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1)); - ///- Initialize the world database - if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str()); - return false; - } - - ///- Get character database info from configuration file - dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2)); - - ///- Initialize the Character database - if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str()); - return false; - } - - ///- Get login database info from configuration file - dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); - if (dbString.empty()) - { - TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file"); - return false; - } - - asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1)); - if (asyncThreads < 1 || asyncThreads > 32) - { - TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. " - "Please pick a value between 1 and 32."); - return false; - } - - synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1)); - ///- Initialise the login database - if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads)) - { - TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str()); - return false; - } - - ///- Get the realm Id from the configuration file - realmID = sConfigMgr->GetIntDefault("RealmID", 0); - if (!realmID) - { - TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); - return false; - } - TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID); - - ///- Clean the database before starting - ClearOnlineAccounts(); - - ///- Insert version info into DB - WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query - - sWorld->LoadDBVersion(); - - TC_LOG_INFO("server.worldserver", "Using World DB: %s", sWorld->GetDBVersion()); - return true; -} - -void Master::_StopDB() -{ - CharacterDatabase.Close(); - WorldDatabase.Close(); - LoginDatabase.Close(); - - MySQL::Library_End(); -} - -/// Clear 'online' status for all accounts with characters in this realm -void Master::ClearOnlineAccounts() -{ - // Reset online status for all accounts with characters on the current realm - LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmID); - - // Reset online status for all characters - CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0"); - - // Battleground instance ids reset at server restart - CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0"); -} diff --git a/src/server/worldserver/Master.h b/src/server/worldserver/Master.h deleted file mode 100644 index 9ee94a44acb..00000000000 --- a/src/server/worldserver/Master.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _MASTER_H -#define _MASTER_H - -#include "Common.h" - -/// Start the server -class Master -{ - public: - int Run(); - - private: - bool _StartDB(); - void _StopDB(); - - void ClearOnlineAccounts(); -}; - -#define sMaster ACE_Singleton<Master, ACE_Null_Mutex>::instance() - -#endif - -/// @} diff --git a/src/server/worldserver/PrecompiledHeaders/worldPCH.h b/src/server/worldserver/PrecompiledHeaders/worldPCH.h index f94dd953bba..6407485f70b 100644 --- a/src/server/worldserver/PrecompiledHeaders/worldPCH.h +++ b/src/server/worldserver/PrecompiledHeaders/worldPCH.h @@ -1,5 +1,3 @@ -#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it - #include "Common.h" #include "World.h" #include "Log.h" diff --git a/src/server/worldserver/RemoteAccess/RARunnable.cpp b/src/server/worldserver/RemoteAccess/RARunnable.cpp deleted file mode 100644 index 44b07163294..00000000000 --- a/src/server/worldserver/RemoteAccess/RARunnable.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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/>. - */ - -/** \file - \ingroup Trinityd - */ - -#include "Common.h" -#include "Config.h" -#include "Log.h" -#include "RARunnable.h" -#include "World.h" - -#include <ace/Reactor_Impl.h> -#include <ace/TP_Reactor.h> -#include <ace/Dev_Poll_Reactor.h> -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "RASocket.h" - -RARunnable::RARunnable() -{ - ACE_Reactor_Impl* imp; - -#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - imp = new ACE_Dev_Poll_Reactor(); - imp->max_notify_iterations (128); - imp->restart (1); -#else - imp = new ACE_TP_Reactor(); - imp->max_notify_iterations (128); -#endif - - m_Reactor = new ACE_Reactor (imp, 1); -} - -RARunnable::~RARunnable() -{ - delete m_Reactor; -} - -void RARunnable::run() -{ - if (!sConfigMgr->GetBoolDefault("Ra.Enable", false)) - return; - - ACE_Acceptor<RASocket, ACE_SOCK_ACCEPTOR> acceptor; - - uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443)); - std::string stringIp = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0"); - ACE_INET_Addr listenAddress(raPort, stringIp.c_str()); - - if (acceptor.open(listenAddress, m_Reactor) == -1) - { - TC_LOG_ERROR("server.worldserver", "Trinity RA can not bind to port %d on %s", raPort, stringIp.c_str()); - return; - } - - TC_LOG_INFO("server.worldserver", "Starting Trinity RA on port %d on %s", raPort, stringIp.c_str()); - - while (!World::IsStopped()) - { - ACE_Time_Value interval(0, 100000); - if (m_Reactor->run_reactor_event_loop(interval) == -1) - break; - } - - TC_LOG_DEBUG("server.worldserver", "Trinity RA thread exiting"); -} diff --git a/src/server/worldserver/RemoteAccess/RARunnable.h b/src/server/worldserver/RemoteAccess/RARunnable.h deleted file mode 100644 index 540ac762f30..00000000000 --- a/src/server/worldserver/RemoteAccess/RARunnable.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _TRINITY_RARUNNABLE_H_ -#define _TRINITY_RARUNNABLE_H_ - -#include "Common.h" - -#include <ace/Reactor.h> - -class RARunnable : public ACE_Based::Runnable -{ -public: - RARunnable(); - virtual ~RARunnable(); - void run() override; - -private: - ACE_Reactor* m_Reactor; - -}; - -#endif /* _TRINITY_RARUNNABLE_H_ */ - -/// @} diff --git a/src/server/worldserver/RemoteAccess/RASession.cpp b/src/server/worldserver/RemoteAccess/RASession.cpp new file mode 100644 index 00000000000..898491274dc --- /dev/null +++ b/src/server/worldserver/RemoteAccess/RASession.cpp @@ -0,0 +1,222 @@ +/* +* 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 +* 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 <memory> +#include <boost/asio/write.hpp> +#include <boost/asio/read_until.hpp> +#include <boost/array.hpp> +#include "RASession.h" +#include "AccountMgr.h" +#include "Log.h" +#include "DatabaseEnv.h" +#include "World.h" +#include "Config.h" + +using boost::asio::ip::tcp; + +void RASession::Start() +{ + boost::asio::socket_base::bytes_readable command(true); + _socket.io_control(command); + std::size_t bytes_readable = command.get(); + + // Check if there are bytes available, if they are, then the client is requesting the negotiation + if (bytes_readable > 0) + { + // Handle subnegotiation + boost::array<char, 1024> buf; + _socket.read_some(boost::asio::buffer(buf)); + + // Send the end-of-negotiation packet + uint8 const reply[2] = { 0xFF, 0xF0 }; + _socket.write_some(boost::asio::buffer(reply)); + } + + Send("Authentication Required\r\n"); + Send("Username: "); + + std::string username = ReadString(); + + if (username.empty()) + return; + + TC_LOG_INFO("commands.ra", "Accepting RA connection from user %s (IP: %s)", username.c_str(), GetRemoteIpAddress().c_str()); + + Send("Password: "); + + std::string password = ReadString(); + if (password.empty()) + return; + + if (!CheckAccessLevel(username) || !CheckPassword(username, password)) + { + Send("Authentication failed\r\n"); + _socket.close(); + return; + } + + TC_LOG_INFO("commands.ra", "User %s (IP: %s) authenticated correctly to RA", username.c_str(), GetRemoteIpAddress().c_str()); + + // Authentication successful, send the motd + Send(std::string(std::string(sWorld->GetMotd()) + "\r\n").c_str()); + + // Read commands + while (true) + { + Send("TC>"); + std::string command = ReadString(); + + if (ProcessCommand(command)) + break; + } + + _socket.close(); +} + +int RASession::Send(const char* data) +{ + std::ostream os(&_writeBuffer); + os << data; + size_t written = _socket.send(_writeBuffer.data()); + _writeBuffer.consume(written); + return written; +} + +std::string RASession::ReadString() +{ + boost::system::error_code error; + size_t read = boost::asio::read_until(_socket, _readBuffer, "\r\n", error); + if (!read) + { + _socket.close(); + return ""; + } + + std::string line; + std::istream is(&_readBuffer); + std::getline(is, line); + + if (*line.rbegin() == '\r') + line.erase(line.length() - 1); + + return line; +} + +bool RASession::CheckAccessLevel(const std::string& user) +{ + std::string safeUser = user; + + AccountMgr::normalizeString(safeUser); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); + stmt->setString(0, safeUser); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (!result) + { + TC_LOG_INFO("commands.ra", "User %s does not exist in database", user.c_str()); + return false; + } + + Field* fields = result->Fetch(); + + if (fields[1].GetUInt8() < sConfigMgr->GetIntDefault("RA.MinLevel", 3)) + { + TC_LOG_INFO("commands.ra", "User %s has no privilege to login", user.c_str()); + return false; + } + else if (fields[2].GetInt32() != -1) + { + TC_LOG_INFO("commands.ra", "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); + return false; + } + + return true; +} + +bool RASession::CheckPassword(const std::string& user, const std::string& pass) +{ + std::string safe_user = user; + std::transform(safe_user.begin(), safe_user.end(), safe_user.begin(), ::toupper); + AccountMgr::normalizeString(safe_user); + + std::string safe_pass = pass; + AccountMgr::normalizeString(safe_pass); + std::transform(safe_pass.begin(), safe_pass.end(), safe_pass.begin(), ::toupper); + + std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); + + stmt->setString(0, safe_user); + stmt->setString(1, hash); + + PreparedQueryResult result = LoginDatabase.Query(stmt); + + if (!result) + { + TC_LOG_INFO("commands.ra", "Wrong password for user: %s", user.c_str()); + return false; + } + + return true; +} + +bool RASession::ProcessCommand(std::string& command) +{ + if (command.length() == 0) + return true; + + TC_LOG_INFO("commands.ra", "Received command: %s", command.c_str()); + + // handle quit, exit and logout commands to terminate connection + if (command == "quit" || command == "exit" || command == "logout") + { + Send("Bye\r\n"); + return true; + } + + // Obtain a new promise per command + if (_commandExecuting != nullptr) + delete _commandExecuting; + + _commandExecuting = new std::promise<void>(); + + CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASession::CommandPrint, &RASession::CommandFinished); + sWorld->QueueCliCommand(cmd); + + // Wait for the command to finish + _commandExecuting->get_future().wait(); + + return false; +} + +void RASession::CommandPrint(void* callbackArg, const char* text) +{ + if (!text || !*text) + return; + + RASession* session = static_cast<RASession*>(callbackArg); + session->Send(text); +} + +void RASession::CommandFinished(void* callbackArg, bool /*success*/) +{ + RASession* session = static_cast<RASession*>(callbackArg); + session->_commandExecuting->set_value(); +} diff --git a/src/server/worldserver/RemoteAccess/RASession.h b/src/server/worldserver/RemoteAccess/RASession.h new file mode 100644 index 00000000000..61156a0fa53 --- /dev/null +++ b/src/server/worldserver/RemoteAccess/RASession.h @@ -0,0 +1,63 @@ +/* +* 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 +* 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 __RASESSION_H__ +#define __RASESSION_H__ + +#include <memory> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/streambuf.hpp> +#include "Common.h" + +#include <future> + +using boost::asio::ip::tcp; + +const size_t bufferSize = 4096; + +#define BUFFER_SIZE 4096 + +class RASession : public std::enable_shared_from_this <RASession> +{ +public: + RASession(tcp::socket&& socket) : _socket(std::move(socket)), _commandExecuting(nullptr) + { + } + + void Start(); + + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); } + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } + +private: + int Send(const char* data); + std::string ReadString(); + bool CheckAccessLevel(const std::string& user); + bool CheckPassword(const std::string& user, const std::string& pass); + bool ProcessCommand(std::string& command); + + static void CommandPrint(void* callbackArg, const char* text); + static void CommandFinished(void* callbackArg, bool); + + tcp::socket _socket; + boost::asio::streambuf _readBuffer; + boost::asio::streambuf _writeBuffer; + std::promise<void>* _commandExecuting; +}; + +#endif diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp deleted file mode 100644 index 6e621ddfffe..00000000000 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/** \file - \ingroup Trinityd -*/ - -#include "Common.h" -#include "Configuration/Config.h" -#include "Database/DatabaseEnv.h" -#include "AccountMgr.h" -#include "Log.h" -#include "RASocket.h" -#include "Util.h" -#include "World.h" -#include "SHA1.h" - -RASocket::RASocket() -{ - _minLevel = uint8(sConfigMgr->GetIntDefault("RA.MinLevel", 3)); - _commandExecuting = false; -} - -int RASocket::open(void *) -{ - ACE_INET_Addr remoteAddress; - - if (peer().get_remote_addr(remoteAddress) == -1) - { - TC_LOG_ERROR("server.worldserver", "RASocket::open: peer().get_remote_addr error is %s", ACE_OS::strerror(errno)); - return -1; - } - - TC_LOG_INFO("commands.ra", "Incoming connection from %s", remoteAddress.get_host_addr()); - - return activate(); -} - -int RASocket::handle_close(ACE_HANDLE /*handle*/, ACE_Reactor_Mask /*mask*/) -{ - TC_LOG_INFO("commands.ra", "Closing connection"); - peer().close_reader(); - wait(); - // While the above wait() will wait for the ::svc() to finish, it will not wait for the async event - // RASocket::commandfinished to be completed. Calling destroy() before the latter function ends - // will lead to using a freed pointer -> crash. - while (_commandExecuting.value()) - ACE_OS::sleep(1); - - destroy(); - return 0; -} - -int RASocket::send(const std::string& line) -{ -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(line.c_str(), line.length(), MSG_NOSIGNAL); -#else - ssize_t n = peer().send(line.c_str(), line.length()); -#endif // MSG_NOSIGNAL - - return n == ssize_t(line.length()) ? 0 : -1; -} - -int RASocket::recv_line(ACE_Message_Block& buffer) -{ - char byte; - for (;;) - { - ssize_t n = peer().recv(&byte, sizeof(byte)); - - if (n < 0) - return -1; - - if (n == 0) - { - // EOF, connection was closed - errno = ECONNRESET; - return -1; - } - - ACE_ASSERT(n == sizeof(byte)); - - if (byte == '\n') - break; - else if (byte == '\r') /* Ignore CR */ - continue; - else if (buffer.copy(&byte, sizeof(byte)) == -1) - return -1; - } - - const char nullTerm = '\0'; - if (buffer.copy(&nullTerm, sizeof(nullTerm)) == -1) - return -1; - - return 0; -} - -int RASocket::recv_line(std::string& out_line) -{ - char buf[4096]; - - ACE_Data_Block db(sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - if (recv_line(message_block) == -1) - { - TC_LOG_DEBUG("commands.ra", "Recv error %s", ACE_OS::strerror(errno)); - return -1; - } - - out_line = message_block.rd_ptr(); - - return 0; -} - -int RASocket::process_command(const std::string& command) -{ - if (command.length() == 0) - return 0; - - TC_LOG_INFO("commands.ra", "Received command: %s", command.c_str()); - - // handle quit, exit and logout commands to terminate connection - if (command == "quit" || command == "exit" || command == "logout") { - (void) send("Bye\r\n"); - return -1; - } - - _commandExecuting = true; - CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished); - sWorld->QueueCliCommand(cmd); - - // wait for result - ACE_Message_Block* mb; - for (;;) - { - if (getq(mb) == -1) - return -1; - - if (mb->msg_type() == ACE_Message_Block::MB_BREAK) - { - mb->release(); - break; - } - - if (send(std::string(mb->rd_ptr(), mb->length())) == -1) - { - mb->release(); - return -1; - } - - mb->release(); - } - - return 0; -} - -int RASocket::check_access_level(const std::string& user) -{ - std::string safeUser = user; - - AccountMgr::normalizeString(safeUser); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); - stmt->setString(0, safeUser); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - if (!result) - { - TC_LOG_INFO("commands.ra", "User %s does not exist in database", user.c_str()); - return -1; - } - - Field* fields = result->Fetch(); - - if (fields[1].GetUInt8() < _minLevel) - { - TC_LOG_INFO("commands.ra", "User %s has no privilege to login", user.c_str()); - return -1; - } - else if (fields[2].GetInt32() != -1) - { - TC_LOG_INFO("commands.ra", "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); - return -1; - } - - return 0; -} - -int RASocket::check_password(const std::string& user, const std::string& pass) -{ - std::string safe_user = user; - AccountMgr::normalizeString(safe_user); - - std::string safe_pass = pass; - AccountMgr::normalizeString(safe_pass); - - std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); - - stmt->setString(0, safe_user); - stmt->setString(1, hash); - - PreparedQueryResult result = LoginDatabase.Query(stmt); - - if (!result) - { - TC_LOG_INFO("commands.ra", "Wrong password for user: %s", user.c_str()); - return -1; - } - - return 0; -} - -int RASocket::authenticate() -{ - if (send(std::string("Username: ")) == -1) - return -1; - - std::string user; - if (recv_line(user) == -1) - return -1; - - if (send(std::string("Password: ")) == -1) - return -1; - - std::string pass; - if (recv_line(pass) == -1) - return -1; - - TC_LOG_INFO("commands.ra", "Login attempt for user: %s", user.c_str()); - - if (check_access_level(user) == -1) - return -1; - - if (check_password(user, pass) == -1) - return -1; - - TC_LOG_INFO("commands.ra", "User login: %s", user.c_str()); - - return 0; -} - - -int RASocket::subnegotiate() -{ - char buf[1024]; - - ACE_Data_Block db(sizeof (buf), - ACE_Message_Block::MB_DATA, - buf, - 0, - 0, - ACE_Message_Block::DONT_DELETE, - 0); - - ACE_Message_Block message_block(&db, - ACE_Message_Block::DONT_DELETE, - 0); - - const size_t recv_size = message_block.space(); - - // Wait a maximum of 1000ms for negotiation packet - not all telnet clients may send it - ACE_Time_Value waitTime = ACE_Time_Value(1); - const ssize_t n = peer().recv(message_block.wr_ptr(), - recv_size, &waitTime); - - if (n <= 0) - return int(n); - - if (n >= 1024) - { - TC_LOG_DEBUG("commands.ra", "RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", uint32(n)); - return -1; - } - - buf[n] = '\0'; - - #ifdef _DEBUG - for (uint8 i = 0; i < n; ) - { - uint8 iac = buf[i]; - if (iac == 0xFF) // "Interpret as Command" (IAC) - { - uint8 command = buf[++i]; - std::stringstream ss; - switch (command) - { - case 0xFB: // WILL - ss << "WILL "; - break; - case 0xFC: // WON'T - ss << "WON'T "; - break; - case 0xFD: // DO - ss << "DO "; - break; - case 0xFE: // DON'T - ss << "DON'T "; - break; - default: - return -1; // not allowed - } - - uint8 param = buf[++i]; - ss << uint32(param); - TC_LOG_DEBUG("commands.ra", ss.str().c_str()); - } - ++i; - } - #endif - - //! Just send back end of subnegotiation packet - uint8 const reply[2] = {0xFF, 0xF0}; - -#ifdef MSG_NOSIGNAL - return int(peer().send(reply, 2, MSG_NOSIGNAL)); -#else - return int(peer().send(reply, 2)); -#endif // MSG_NOSIGNAL -} - -int RASocket::svc(void) -{ - //! Subnegotiation may differ per client - do not react on it - subnegotiate(); - - if (send("Authentication required\r\n") == -1) - return -1; - - if (authenticate() == -1) - { - (void) send("Authentication failed\r\n"); - return -1; - } - - // send motd - if (send(std::string(sWorld->GetMotd()) + "\r\n") == -1) - return -1; - - for (;;) - { - // show prompt - if (send("TC> ") == -1) - return -1; - - std::string line; - - if (recv_line(line) == -1) - return -1; - - if (process_command(line) == -1) - return -1; - } - - return 0; -} - -void RASocket::zprint(void* callbackArg, const char * szText) -{ - if (!szText || !callbackArg) - return; - - RASocket* socket = static_cast<RASocket*>(callbackArg); - size_t sz = strlen(szText); - - ACE_Message_Block* mb = new ACE_Message_Block(sz); - mb->copy(szText, sz); - - ACE_Time_Value tv = ACE_Time_Value::zero; - if (socket->putq(mb, &tv) == -1) - { - TC_LOG_DEBUG("commands.ra", "Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno)); - mb->release(); - } -} - -void RASocket::commandFinished(void* callbackArg, bool /*success*/) -{ - if (!callbackArg) - return; - - RASocket* socket = static_cast<RASocket*>(callbackArg); - - ACE_Message_Block* mb = new ACE_Message_Block(); - - mb->msg_type(ACE_Message_Block::MB_BREAK); - - // the message is 0 size control message to tell that command output is finished - // hence we don't put timeout, because it shouldn't increase queue size and shouldn't block - if (socket->putq(mb->duplicate()) == -1) - // getting here is bad, command can't be marked as complete - TC_LOG_DEBUG("commands.ra", "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno)); - - mb->release(); - - socket->_commandExecuting = false; -} diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h deleted file mode 100644 index 2cbb14b3578..00000000000 --- a/src/server/worldserver/RemoteAccess/RASocket.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _RASOCKET_H -#define _RASOCKET_H - -#include "Common.h" - -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/SOCK_Acceptor.h> - -/// Remote Administration socket -class RASocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> -{ - public: - RASocket(); - virtual ~RASocket() { } - - virtual int svc() override; - virtual int open(void* = 0) override; - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK) override; - - private: - int recv_line(std::string& outLine); - int recv_line(ACE_Message_Block& buffer); - int process_command(const std::string& command); - int authenticate(); - int subnegotiate(); ///< Used by telnet protocol RFC 854 / 855 - int check_access_level(const std::string& user); - int check_password(const std::string& user, const std::string& pass); - int send(const std::string& line); - - static void zprint(void* callbackArg, const char* szText); - static void commandFinished(void* callbackArg, bool success); - - private: - uint8 _minLevel; ///< Minimum security level required to connect - ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting; -}; - -#endif - -/// @} diff --git a/src/server/worldserver/TCSoap/TCSoap.cpp b/src/server/worldserver/TCSoap/TCSoap.cpp index 1549019352d..5122752f3a4 100644 --- a/src/server/worldserver/TCSoap/TCSoap.cpp +++ b/src/server/worldserver/TCSoap/TCSoap.cpp @@ -22,7 +22,7 @@ #include "AccountMgr.h" #include "Log.h" -void TCSoapRunnable::run() +void TCSoapThread(const std::string& host, uint16 port) { struct soap soap; soap_init(&soap); @@ -33,13 +33,13 @@ void TCSoapRunnable::run() soap.accept_timeout = 3; soap.recv_timeout = 5; soap.send_timeout = 5; - if (!soap_valid_socket(soap_bind(&soap, _host.c_str(), _port, 100))) + if (!soap_valid_socket(soap_bind(&soap, host.c_str(), port, 100))) { - TC_LOG_ERROR("network.soap", "Couldn't bind to %s:%d", _host.c_str(), _port); + TC_LOG_ERROR("network.soap", "Couldn't bind to %s:%d", host.c_str(), port); exit(-1); } - TC_LOG_INFO("network.soap", "Bound to http://%s:%d", _host.c_str(), _port); + TC_LOG_INFO("network.soap", "Bound to http://%s:%d", host.c_str(), port); while (!World::IsStopped()) { @@ -48,28 +48,21 @@ void TCSoapRunnable::run() TC_LOG_DEBUG("network.soap", "Accepted connection from IP=%d.%d.%d.%d", (int)(soap.ip>>24)&0xFF, (int)(soap.ip>>16)&0xFF, (int)(soap.ip>>8)&0xFF, (int)soap.ip&0xFF); struct soap* thread_soap = soap_copy(&soap);// make a safe copy - - ACE_Message_Block* mb = new ACE_Message_Block(sizeof(struct soap*)); - ACE_OS::memcpy(mb->wr_ptr(), &thread_soap, sizeof(struct soap*)); - process_message(mb); + process_message(thread_soap); } soap_done(&soap); } -void TCSoapRunnable::process_message(ACE_Message_Block* mb) +void process_message(struct soap* soap_message) { - ACE_TRACE (ACE_TEXT ("SOAPWorkingThread::process_message")); - - struct soap* soap; - ACE_OS::memcpy(&soap, mb->rd_ptr (), sizeof(struct soap*)); - mb->release(); + TC_LOG_TRACE("network.soap", "SOAPWorkingThread::process_message"); - soap_serve(soap); - soap_destroy(soap); // dealloc C++ data - soap_end(soap); // dealloc data and clean up - soap_done(soap); // detach soap struct - free(soap); + soap_serve(soap_message); + soap_destroy(soap_message); // dealloc C++ data + soap_end(soap_message); // dealloc data and clean up + soap_done(soap_message); // detach soap struct + free(soap_message); } /* Code used for generating stubs: @@ -112,19 +105,15 @@ int ns1__executeCommand(soap* soap, char* command, char** result) // commands are executed in the world thread. We have to wait for them to be completed { - // CliCommandHolder will be deleted from world, accessing after queueing is NOT save + // CliCommandHolder will be deleted from world, accessing after queueing is NOT safe CliCommandHolder* cmd = new CliCommandHolder(&connection, command, &SOAPCommand::print, &SOAPCommand::commandFinished); sWorld->QueueCliCommand(cmd); } - // wait for callback to complete command - - int acc = connection.pendingCommands.acquire(); - if (acc) - TC_LOG_ERROR("network.soap", "Error while acquiring lock, acc = %i, errno = %u", acc, errno); - - // alright, command finished + // Wait until the command has finished executing + connection.finishedPromise.get_future().wait(); + // The command has finished executing already char* printBuffer = soap_strdup(soap, connection.m_printBuffer.c_str()); if (connection.hasCommandSucceeded()) { @@ -139,7 +128,6 @@ void SOAPCommand::commandFinished(void* soapconnection, bool success) { SOAPCommand* con = (SOAPCommand*)soapconnection; con->setCommandSuccess(success); - con->pendingCommands.release(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/server/worldserver/TCSoap/TCSoap.h b/src/server/worldserver/TCSoap/TCSoap.h index 427d37ef0cc..999a03a9009 100644 --- a/src/server/worldserver/TCSoap/TCSoap.h +++ b/src/server/worldserver/TCSoap/TCSoap.h @@ -19,36 +19,17 @@ #define _TCSOAP_H #include "Define.h" +#include <mutex> +#include <future> -#include <ace/Semaphore.h> -#include <ace/Task.h> -#include <Threading.h> - -class TCSoapRunnable : public ACE_Based::Runnable -{ - public: - TCSoapRunnable() : _port(0) { } - - void run() override; - - void SetListenArguments(const std::string& host, uint16 port) - { - _host = host; - _port = port; - } - - private: - void process_message(ACE_Message_Block* mb); - - std::string _host; - uint16 _port; -}; +void process_message(struct soap* soap_message); +void TCSoapThread(const std::string& host, uint16 port); class SOAPCommand { public: SOAPCommand(): - pendingCommands(0, USYNC_THREAD, "pendingCommands"), m_success(false) + m_success(false) { } @@ -61,11 +42,10 @@ class SOAPCommand m_printBuffer += msg; } - ACE_Semaphore pendingCommands; - void setCommandSuccess(bool val) { m_success = val; + finishedPromise.set_value(); } bool hasCommandSucceeded() const @@ -82,6 +62,7 @@ class SOAPCommand bool m_success; std::string m_printBuffer; + std::promise<void> finishedPromise; }; #endif diff --git a/src/server/worldserver/WorldThread/WorldRunnable.cpp b/src/server/worldserver/WorldThread/WorldRunnable.cpp deleted file mode 100644 index 476007f6ea0..00000000000 --- a/src/server/worldserver/WorldThread/WorldRunnable.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/** \file - \ingroup Trinityd -*/ - -#include "Common.h" -#include "ObjectAccessor.h" -#include "World.h" -#include "WorldSocketMgr.h" -#include "Database/DatabaseEnv.h" -#include "ScriptMgr.h" -#include "BattlegroundMgr.h" -#include "MapManager.h" -#include "Timer.h" -#include "WorldRunnable.h" -#include "OutdoorPvPMgr.h" - -#define WORLD_SLEEP_CONST 50 - -#ifdef _WIN32 -#include "ServiceWin32.h" -extern int m_ServiceStatus; -#endif - -/// Heartbeat for the World -void WorldRunnable::run() -{ - uint32 realCurrTime = 0; - uint32 realPrevTime = getMSTime(); - - uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST - - sScriptMgr->OnStartup(); - - ///- While we have not World::m_stopEvent, update the world - while (!World::IsStopped()) - { - ++World::m_worldLoopCounter; - realCurrTime = getMSTime(); - - uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime); - - sWorld->Update( diff ); - realPrevTime = realCurrTime; - - // diff (D0) include time of previous sleep (d0) + tick time (t0) - // we want that next d1 + t1 == WORLD_SLEEP_CONST - // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement - // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 - if (diff <= WORLD_SLEEP_CONST+prevSleepTime) - { - prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff; - ACE_Based::Thread::Sleep(prevSleepTime); - } - else - prevSleepTime = 0; - - #ifdef _WIN32 - if (m_ServiceStatus == 0) - World::StopNow(SHUTDOWN_EXIT_CODE); - - while (m_ServiceStatus == 2) - Sleep(1000); - #endif - } - - sScriptMgr->OnShutdown(); - - sWorld->KickAll(); // save and kick all players - sWorld->UpdateSessions( 1 ); // real players unload required UpdateSessions call - - // unload battleground templates before different singletons destroyed - sBattlegroundMgr->DeleteAllBattlegrounds(); - - sWorldSocketMgr->StopNetwork(); - - sMapMgr->UnloadAll(); // unload all grids (including locked in memory) - sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world - sScriptMgr->Unload(); - sOutdoorPvPMgr->Die(); -} diff --git a/src/server/worldserver/WorldThread/WorldRunnable.h b/src/server/worldserver/WorldThread/WorldRunnable.h deleted file mode 100644 index dfc74dd1e3a..00000000000 --- a/src/server/worldserver/WorldThread/WorldRunnable.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 - * 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/>. - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef __WORLDRUNNABLE_H -#define __WORLDRUNNABLE_H - -/// Heartbeat thread for the World -class WorldRunnable : public ACE_Based::Runnable -{ - public: - void run() override; -}; - -#endif - -/// @} diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 90f330bac42..c4e3ad832a7 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -144,6 +144,14 @@ WorldServerPort = 8085 BindIP = "0.0.0.0" # +# ThreadPool +# Description: Number of threads to be used for the global thread pool +# The thread pool is currently used for the signal handler and remote access +# Default: 1 + +ThreadPool = 1 + +# ################################################################################################### ################################################################################################### @@ -161,7 +169,8 @@ UseProcessors = 0 # # ProcessPriority # Description: Process priority setting for Windows and Linux based systems. -# Details: On Linux, a nice value of -15 is used. (requires superuser). On Windows, process is set to HIGH class. +# Details: On Linux, a nice value of -15 is used. (requires superuser). +# On Windows, process is set to HIGH class. # Default: 0 - (Normal) # 1 - (High) @@ -1069,7 +1078,8 @@ Account.PasswordChangeSecurity = 0 # # BirthdayTime -# Description: Set to date of project's birth in UNIX time. By default the date when TrinityCore was started (Thu Oct 2, 2008) +# Description: Set to date of project's birth in UNIX time. By default the date when +# TrinityCore was started (Thu Oct 2, 2008) # Default: 1222964635 # # @@ -2627,8 +2637,10 @@ UI.ShowQuestLevelsInDialogs = 0 # 1 - Prefix Timestamp to the text # 2 - Prefix Log Level to the text # 4 - Prefix Log Filter type to the text -# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS (Only used with Type = 2) -# 16 - Make a backup of existing file before overwrite (Only used with Mode = w) +# 8 - Append timestamp to the log file name. Format: YYYY-MM-DD_HH-MM-SS +# (Only used with Type = 2) +# 16 - Make a backup of existing file before overwrite +# (Only used with Mode = w) # # Colors (read as optional1 if Type = Console) # Format: "fatal error warn info debug trace" @@ -2744,7 +2756,8 @@ Log.Async.Enable = 0 # # Allow.IP.Based.Action.Logging -# Description: Logs actions, e.g. account login and logout to name a few, based on IP of current session. +# Description: Logs actions, e.g. account login and logout to name a few, based on IP of +# current session. # Default: 0 - (Disabled) # 1 - (Enabled) diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index c0268680657..a2b729ca998 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -12,7 +12,6 @@ file(GLOB_RECURSE mmap_gen_sources *.cpp *.h) set(mmap_gen_Includes ${CMAKE_BINARY_DIR} - ${ACE_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/dep/libmpq ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/dep/bzip2 @@ -22,6 +21,8 @@ set(mmap_gen_Includes ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include ${CMAKE_SOURCE_DIR}/src/server/shared + ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/game/Conditions ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management @@ -45,9 +46,9 @@ target_link_libraries(mmaps_generator g3dlib Recast Detour - ${ACE_LIBRARY} ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} + ${Boost_LIBRARIES} ) if( UNIX ) diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 131041e0cd2..3b1516b3d11 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -27,7 +27,6 @@ #include "DetourCommon.h" #include "DisableMgr.h" -#include <ace/OS_NS_unistd.h> uint32 GetLiquidFlags(uint32 /*liquidType*/) { return 0; } namespace DisableMgr @@ -166,11 +165,28 @@ namespace MMAP } /**************************************************************************/ - void MapBuilder::buildAllMaps(int threads) + + void MapBuilder::WorkerThread() { - std::vector<BuilderThread*> _threads; + while (1) + { + uint32 mapId; + + _queue.WaitAndPop(mapId); + + if (_cancelationToken) + return; + + buildMap(mapId); + } + } - BuilderThreadPool* pool = threads > 0 ? new BuilderThreadPool() : NULL; + void MapBuilder::buildAllMaps(int threads) + { + for (size_t i = 0; i < threads; ++i) + { + _workerThreads.push_back(std::thread(&MapBuilder::WorkerThread, this)); + } m_tiles.sort([](MapTiles a, MapTiles b) { @@ -183,23 +199,25 @@ namespace MMAP if (!shouldSkipMap(mapID)) { if (threads > 0) - pool->Enqueue(new MapBuildRequest(mapID)); + _queue.Push(mapID); else buildMap(mapID); } } - for (int i = 0; i < threads; ++i) - _threads.push_back(new BuilderThread(this, pool->Queue())); - - // Free memory - for (std::vector<BuilderThread*>::iterator _th = _threads.begin(); _th != _threads.end(); ++_th) + while (!_queue.Empty()) { - (*_th)->wait(); - delete *_th; + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } - delete pool; + _cancelationToken = true; + + _queue.Cancel(); + + for (auto& thread : _workerThreads) + { + thread.join(); + } } /**************************************************************************/ @@ -349,7 +367,7 @@ namespace MMAP void MapBuilder::buildMap(uint32 mapID) { #ifndef __APPLE__ - printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID); + //printf("[Thread %u] Building map %03u:\n", uint32(ACE_Thread::self()), mapID); #endif std::set<uint32>* tiles = getTileList(mapID); diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h index 08b87324d01..4cd36602a4b 100644 --- a/src/tools/mmaps_generator/MapBuilder.h +++ b/src/tools/mmaps_generator/MapBuilder.h @@ -23,16 +23,15 @@ #include <set> #include <map> #include <list> +#include <atomic> +#include <thread> #include "TerrainBuilder.h" #include "IntermediateValues.h" #include "Recast.h" #include "DetourNavMesh.h" - -#include <ace/Task.h> -#include <ace/Activation_Queue.h> -#include <ace/Method_Request.h> +#include "ProducerConsumerQueue.h" using namespace VMAP; @@ -100,6 +99,8 @@ namespace MMAP // builds list of maps, then builds all of mmap tiles (based on the skip settings) void buildAllMaps(int threads); + void MapBuilder::WorkerThread(); + private: // detect maps and tiles void discoverTiles(); @@ -142,63 +143,10 @@ namespace MMAP // build performance - not really used for now rcContext* m_rcContext; - }; - - class MapBuildRequest : public ACE_Method_Request - { - public: - MapBuildRequest(uint32 mapId) : _mapId(mapId) {} - - virtual int call() - { - /// @ Actually a creative way of unabstracting the class and returning a member variable - return (int)_mapId; - } - - private: - uint32 _mapId; - }; - - class BuilderThread : public ACE_Task_Base - { - private: - MapBuilder* _builder; - ACE_Activation_Queue* _queue; - public: - BuilderThread(MapBuilder* builder, ACE_Activation_Queue* queue) : _builder(builder), _queue(queue) { activate(); } - - int svc() - { - /// @ Set a timeout for dequeue attempts (only used when the queue is empty) as it will never get populated after thread starts - ACE_Time_Value timeout(5); - ACE_Method_Request* request = NULL; - while ((request = _queue->dequeue(&timeout)) != NULL) - { - _builder->buildMap(request->call()); - delete request; - request = NULL; - } - - return 0; - } - }; - - class BuilderThreadPool - { - public: - BuilderThreadPool() : _queue(new ACE_Activation_Queue()) {} - ~BuilderThreadPool() { _queue->queue()->close(); delete _queue; } - - void Enqueue(MapBuildRequest* request) - { - _queue->enqueue(request); - } - - ACE_Activation_Queue* Queue() { return _queue; } - - private: - ACE_Activation_Queue* _queue; + std::vector<std::thread> _workerThreads; + ProducerConsumerQueue<uint32> _queue; + std::atomic<bool> _cancelationToken; }; } diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h index a035bea3b6f..8285fef74f2 100644 --- a/src/tools/mmaps_generator/PathCommon.h +++ b/src/tools/mmaps_generator/PathCommon.h @@ -21,9 +21,8 @@ #include <string> #include <vector> -#include <ace/OS_NS_sys_time.h> -#include "Define.h" +#include "Common.h" #ifndef _WIN32 #include <stddef.h> @@ -135,26 +134,6 @@ namespace MMAP return LISTFILE_OK; } - - inline uint32 getMSTime() - { - static const ACE_Time_Value ApplicationStartTime = ACE_OS::gettimeofday(); - return (ACE_OS::gettimeofday() - ApplicationStartTime).msec(); - } - - inline uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime) - { - // getMSTime() have limited data range and this is case when it overflow in this tick - if (oldMSTime > newMSTime) - return (0xFFFFFFFF - oldMSTime) + newMSTime; - else - return newMSTime - oldMSTime; - } - - inline uint32 GetMSTimeDiffToNow(uint32 oldMSTime) - { - return getMSTimeDiff(oldMSTime, getMSTime()); - } } #endif diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp index d88ab8ca16d..3e2025dace8 100644 --- a/src/tools/mmaps_generator/PathGenerator.cpp +++ b/src/tools/mmaps_generator/PathGenerator.cpp @@ -18,6 +18,7 @@ #include "PathCommon.h" #include "MapBuilder.h" +#include "Timer.h" using namespace MMAP; diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 7832cef18de..771275a1757 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -18,13 +18,11 @@ #include "TerrainBuilder.h" -#include "PathCommon.h" #include "MapBuilder.h" #include "VMapManager2.h" #include "MapTree.h" #include "ModelInstance.h" -#include <vector> // ****************************************** // Map file format defines |