From 35c2e972076b1f039ab17ddd35f2d08c125ce383 Mon Sep 17 00:00:00 2001 From: leak Date: Tue, 13 May 2014 22:41:59 +0200 Subject: Replace ACE signal handling with Boost --- src/server/authserver/Main.cpp | 44 ++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index d1b2b614037..0ccad3d1d8a 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -26,10 +26,9 @@ #include #include -#include -#include #include #include +#include #include "Common.h" #include "Database/DatabaseEnv.h" @@ -58,21 +57,20 @@ bool stopEvent = false; // Setting it to tru 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; - } - } -}; +void SignalHandler(const boost::system::error_code& error, int signalNumber) +{ + TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + stopEvent = true; + break; + } + } +} /// Print out the usage string for this program on the console. void usage(const char* prog) @@ -170,13 +168,11 @@ extern int main(int argc, char** argv) return 1; } - // Initialize the signal handlers - AuthServerSignalHandler SignalINT, SignalTERM; + boost::asio::io_service io_service; - // Register authservers's signal handlers - ACE_Sig_Handler Handler; - Handler.register_handler(SIGINT, &SignalINT); - Handler.register_handler(SIGTERM, &SignalTERM); + boost::asio::signal_set signals(io_service, SIGINT, SIGTERM); + + signals.async_wait(SignalHandler); #if defined(_WIN32) || defined(__linux__) @@ -259,6 +255,8 @@ extern int main(int argc, char** argv) if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; + io_service.run(); + if ((++loopCounter) == numLoops) { loopCounter = 0; -- cgit v1.2.3 From 5a363ee0e1556b58ad1d16ce2b78ae5f92e065ea Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 17 May 2014 20:27:39 +0200 Subject: Replace authserver ACE related code with Boost/C++11 --- cmake/macros/ConfigureBoost.cmake | 15 +- src/server/authserver/Main.cpp | 240 +++-- src/server/authserver/Server/AuthServer.cpp | 40 + src/server/authserver/Server/AuthServer.h | 44 + src/server/authserver/Server/AuthSession.cpp | 915 +++++++++++++++++++ src/server/authserver/Server/AuthSession.h | 85 ++ src/server/authserver/Server/AuthSocket.cpp | 1207 -------------------------- src/server/authserver/Server/AuthSocket.h | 83 -- src/server/authserver/Server/RealmAcceptor.h | 70 -- src/server/authserver/Server/RealmSocket.cpp | 291 ------- src/server/authserver/Server/RealmSocket.h | 80 -- src/server/worldserver/Master.cpp | 1 - 12 files changed, 1215 insertions(+), 1856 deletions(-) create mode 100644 src/server/authserver/Server/AuthServer.cpp create mode 100644 src/server/authserver/Server/AuthServer.h create mode 100644 src/server/authserver/Server/AuthSession.cpp create mode 100644 src/server/authserver/Server/AuthSession.h delete mode 100644 src/server/authserver/Server/AuthSocket.cpp delete mode 100644 src/server/authserver/Server/AuthSocket.h delete mode 100644 src/server/authserver/Server/RealmAcceptor.h delete mode 100644 src/server/authserver/Server/RealmSocket.cpp delete mode 100644 src/server/authserver/Server/RealmSocket.h (limited to 'src/server/authserver/Main.cpp') diff --git a/cmake/macros/ConfigureBoost.cmake b/cmake/macros/ConfigureBoost.cmake index 320a7cb30d4..c2cd7c43360 100644 --- a/cmake/macros/ConfigureBoost.cmake +++ b/cmake/macros/ConfigureBoost.cmake @@ -1,3 +1,13 @@ +macro(get_WIN32_WINNT version) + if (WIN32 AND CMAKE_SYSTEM_VERSION) + set(ver ${CMAKE_SYSTEM_VERSION}) + string(REPLACE "." "" ver ${ver}) + string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver}) + + set(${version} "0x${ver}") + endif() +endmacro() + if(WIN32) set(BOOST_DEBUG ON) if(DEFINED ENV{BOOST_ROOT}) @@ -12,9 +22,12 @@ if(WIN32) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) + + get_WIN32_WINNT(ver) + add_definitions(-D_WIN32_WINNT=${ver}) endif() -find_package(Boost 1.55 REQUIRED atomic chrono date_time exception system thread) +find_package(Boost 1.55 REQUIRED atomic chrono date_time exception regex system thread) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 0ccad3d1d8a..c8be23ca524 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -24,11 +24,13 @@ * authentication server */ -#include -#include #include #include -#include +#include +#include +#include +#include +#include #include "Common.h" #include "Database/DatabaseEnv.h" @@ -36,9 +38,9 @@ #include "Log.h" #include "SystemConfig.h" #include "Util.h" -#include "SignalHandler.h" #include "RealmList.h" -#include "RealmAcceptor.h" +#include "AuthServer.h" + #ifdef __linux__ #include @@ -52,24 +54,41 @@ bool StartDB(); void StopDB(); +void SetProcessPriority(); -bool stopEvent = false; // Setting it to true stops the server +boost::asio::io_service _ioService; +boost::asio::deadline_timer _dbPingTimer(_ioService); +uint32 _dbPingInterval; LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database -void SignalHandler(const boost::system::error_code& error, int signalNumber) -{ - TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); - if (!error) - { +using boost::asio::ip::tcp; + + +void SignalHandler(const boost::system::error_code& error, int signalNumber) +{ + TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); + if (!error) + { switch (signalNumber) { case SIGINT: case SIGTERM: - stopEvent = true; + _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)); + } } /// Print out the usage string for this program on the console. @@ -81,7 +100,7 @@ void usage(const char* prog) } /// 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; @@ -115,14 +134,6 @@ extern int main(int argc, char** argv) TC_LOG_WARN("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()); - // authserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); if (!pidFile.empty()) @@ -149,121 +160,32 @@ extern int main(int argc, char** argv) } // Launch the listening network socket - RealmAcceptor acceptor; - int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); - if (rmport < 0 || rmport > 0xFFFF) + 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 bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + std::string bindIp = 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; - } - - boost::asio::io_service io_service; - - boost::asio::signal_set signals(io_service, SIGINT, SIGTERM); + AuthServer authServer(_ioService, bindIp, port); + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); signals.async_wait(SignalHandler); -#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 + SetProcessPriority(); - // maximum counter for next ping - uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); - uint32 loopCounter = 0; - - // Wait for termination signal - while (!stopEvent) - { - // dont move this outside the loop, the reactor will modify it - ACE_Time_Value interval(0, 100000); - if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) - break; + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - io_service.run(); + _dbPingTimer.expires_from_now(boost::posix_time::seconds(_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 + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -272,6 +194,7 @@ extern int main(int argc, char** argv) return 0; } + /// Initialize connection to the database bool StartDB() { @@ -316,3 +239,74 @@ void StopDB() LoginDatabase.Close(); MySQL::Library_End(); } + +void SetProcessPriority() +{ +#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 +} \ No newline at end of file diff --git a/src/server/authserver/Server/AuthServer.cpp b/src/server/authserver/Server/AuthServer.cpp new file mode 100644 index 00000000000..a699734be79 --- /dev/null +++ b/src/server/authserver/Server/AuthServer.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 . + */ + +#include "AuthServer.h" +#include "AuthSession.h" + +#include +#include + +using boost::asio::ip::tcp; + +void AuthServer::AsyncAccept() +{ + _acceptor.async_accept(_socket, [this](boost::system::error_code error) + { + if (!error) + { + std::make_shared(std::move(_socket))->Start(); + } + + AsyncAccept(); + }); +} + + + diff --git a/src/server/authserver/Server/AuthServer.h b/src/server/authserver/Server/AuthServer.h new file mode 100644 index 00000000000..0496326ee7b --- /dev/null +++ b/src/server/authserver/Server/AuthServer.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008-2014 TrinityCore + * + * 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 . + */ + +#ifndef __AUTHSERVER_H__ +#define __AUTHSERVER_H__ + +#include + +using boost::asio::ip::tcp; + +class AuthServer +{ +public: + AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) + { + tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); + + _acceptor = tcp::acceptor(ioService, endpoint); + + AsyncAccept(); + }; + +private: + void AsyncAccept(); + + tcp::acceptor _acceptor; + tcp::socket _socket; +}; + +#endif /* __AUTHSERVER_H__ */ diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp new file mode 100644 index 00000000000..cb78336f2d3 --- /dev/null +++ b/src/server/authserver/Server/AuthSession.cpp @@ -0,0 +1,915 @@ +/* +* Copyright (C) 2008-2014 TrinityCore +* Copyright (C) 2005-2009 MaNGOS +* +* 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 . +*/ + +#include +#include +#include +#include +#include "ByteBuffer.h" +#include "AuthCodes.h" +#include "Database/DatabaseEnv.h" +#include "SHA1.h" +#include "openssl/crypto.h" +#include "Configuration/Config.h" +#include "RealmList.h" + +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 +}; + +enum eStatus +{ + STATUS_CONNECTED = 0, + STATUS_AUTHED +}; + +#pragma pack(push, 1) + +typedef struct AUTH_LOGON_CHALLENGE_C +{ + uint8 cmd; + uint8 error; + uint16 size; + uint8 gamename[4]; + uint8 version1; + uint8 version2; + uint8 version3; + uint16 build; + uint8 platform[4]; + uint8 os[4]; + uint8 country[4]; + uint32 timezone_bias; + uint32 ip; + uint8 I_len; + uint8 I[1]; +} sAuthLogonChallenge_C; + +typedef struct AUTH_LOGON_PROOF_C +{ + uint8 cmd; + uint8 A[32]; + uint8 M1[20]; + uint8 crc_hash[20]; + uint8 number_of_keys; + uint8 securityFlags; +} sAuthLogonProof_C; + +typedef struct AUTH_LOGON_PROOF_S +{ + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk1; + uint32 unk2; + uint16 unk3; +} sAuthLogonProof_S; + +typedef struct AUTH_LOGON_PROOF_S_OLD +{ + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk2; +} sAuthLogonProof_S_Old; + +typedef struct AUTH_RECONNECT_PROOF_C +{ + uint8 cmd; + uint8 R1[16]; + uint8 R2[20]; + uint8 R3[20]; + uint8 number_of_keys; +} sAuthReconnectProof_C; + +#pragma pack(pop) + + +typedef struct AuthHandler +{ + eAuthCmd cmd; + uint32 status; + size_t packetSize; + bool (AuthSession::*handler)(); +} AuthHandler; + +#define BYTE_SIZE 32 +#define REALMLIST_SKIP_PACKETS 5 + +const AuthHandler table[] = +{ + { 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 } +}; + +void AuthSession::AsyncReadHeader() +{ + auto self(shared_from_this()); + + _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 + + AsyncReadData(entry.handler, (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 AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) +{ + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes > 0) + { + if (!(*this.*handler)()) + { + _socket.close(); + return; + } + + AsyncReadHeader(); + } + else + { + _socket.close(); + } + }); +} + +void AuthSession::AsyncWrite(std::size_t length) +{ + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); +} + +bool AuthSession::_HandleLogonChallenge() +{ + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //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.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*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + 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, 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!", ipAddress.c_str(), port); + } + else + { + // Get the account details from the account table + // No SQL injection (prepared statement) + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); + stmt->setString(0, _login); + + PreparedQueryResult res2 = LoginDatabase.Query(stmt); + if (res2) + { + Field* fields = res2->Fetch(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + bool locked = false; + 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'", ipAddress.c_str()); + + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); + pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); + } + else + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ipAddress.c_str()); + EndianConvertReverse(ip); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + stmt->setUInt32(0, ip); + 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()); + + if (loginCountry != accountCountry) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); + pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); + } + } + + if (!locked) + { + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmt->setUInt32(0, fields[1].GetUInt32()); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + 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!", 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!", + ipAddress.c_str(), port, _login.c_str()); + } + } + else + { + // Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = fields[0].GetString(); + + // Don't calculate (v, s) if there are already some in the database + std::string databaseV = fields[6].GetString(); + std::string databaseS = fields[7].GetString(); + + 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() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(19 * 8); + BigNumber gmod = g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16 * 8); + + // Fill the response packet with the result + if (AuthHelper::IsAcceptedClientBuild(_build)) + pkt << uint8(WOW_SUCCESS); + else + pkt << uint8(WOW_FAIL_VERSION_INVALID); + + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt << uint8(1); + pkt.append(g.AsByteArray().get(), 1); + pkt << uint8(32); + pkt.append(N.AsByteArray(32).get(), 32); + pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes + pkt.append(unk3.AsByteArray(16).get(), 16); + uint8 securityFlags = 0; + + // Check if token is used + _tokenKey = fields[8].GetString(); + if (!_tokenKey.empty()) + securityFlags = 4; + + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if (securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if (securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if (securityFlags & 0x04) // Security token input + pkt << uint8(1); + + uint8 secLevel = fields[5].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _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)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) + ); + } + } + } + else //no account + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + } + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + + return true; +} + +// Logon Proof command handler +bool AuthSession::_HandleLogonProof() +{ + + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); + // Read the packet + 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"); + return false; + } + + // Continue the SRP6 calculation based on data received from the client + BigNumber A; + + A.SetBinary(logonProof->A, 32); + + // SRP safeguard: abort if A == 0 + if (A.isZero()) + { + return false; + } + + SHA1Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + BigNumber u; + u.SetBinary(sha.GetDigest(), 20); + BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); + + uint8 t[32]; + uint8 t1[16]; + uint8 vK[40]; + memcpy(t, S.AsByteArray(32).get(), 32); + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2] = sha.GetDigest()[i]; + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2 + 1]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2 + 1] = sha.GetDigest()[i]; + + K.SetBinary(vK, 40); + + uint8 hash[20]; + + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), 20); + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + hash[i] ^= sha.GetDigest()[i]; + + BigNumber t3; + t3.SetBinary(hash, 20); + + sha.Initialize(); + sha.UpdateData(_login); + sha.Finalize(); + uint8 t4[SHA_DIGEST_LENGTH]; + memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); + + sha.Initialize(); + sha.UpdateBigNumbers(&t3, NULL); + sha.UpdateData(t4, SHA_DIGEST_LENGTH); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + BigNumber M; + M.SetBinary(sha.GetDigest(), 20); + + // Check if SRP6 results match (password is correct), else send an error + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) + { + 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 + const char *K_hex = K.AsHexStr(); + + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); + stmt->setString(0, K_hex); + stmt->setString(1, GetRemoteIpAddress().c_str()); + stmt->setUInt32(2, GetLocaleByName(_localizationName)); + stmt->setString(3, _os); + stmt->setString(4, _login); + LoginDatabase.DirectExecute(stmt); + + OPENSSL_free((void*)K_hex); + + // Finish SRP6 and send the final result to the client + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M, &K, NULL); + sha.Finalize(); + + // Check auth token + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) + { + // TODO To be fixed + + /* + uint8 size; + socket().recv((char*)&size, 1); + char* token = new char[size + 1]; + token[size] = '\0'; + socket().recv(token, size); + unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); + unsigned int incomingToken = atoi(token); + delete[] token; + if (validToken != incomingToken) + { + 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 + { + sAuthLogonProof_S proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.unk2 = 0x00; // SurveyId + proof.unk3 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + else + { + sAuthLogonProof_S_Old proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk2 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + + _isAuthenticated = true; + } + else + { + char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + + 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); + if (MaxWrongPassCount > 0) + { + //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); + stmt->setString(0, _login); + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); + stmt->setString(0, _login); + + if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) + { + uint32 failed_logins = (*loginfail)[1].GetUInt32(); + + if (failed_logins >= MaxWrongPassCount) + { + uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); + bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); + + if (WrongPassBanType) + { + uint32 acc_id = (*loginfail)[0].GetUInt32(); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); + stmt->setUInt32(0, acc_id); + stmt->setUInt32(1, WrongPassBanTime); + 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", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); + stmt->setString(0, GetRemoteIpAddress()); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + 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); + } + } + } + } + } + + return true; +} + +bool AuthSession::_HandleReconnectChallenge() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //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); + + _login.assign((const char*)challenge->I, challenge->I_len); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + // 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.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + return false; + } + + // Reinitialize build, expansion and the account securitylevel + _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*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + Field* fields = result->Fetch(); + uint8 secLevel = fields[2].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + K.SetHexStr((*result)[0].GetCString()); + + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_CHALLENGE); + pkt << uint8(0x00); + _reconnectProof.SetRand(16 * 8); + pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + + return true; +} +bool AuthSession::_HandleReconnectProof() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; + + if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + return false; + + BigNumber t1; + t1.SetBinary(reconnectProof->R1, 16); + + SHA1Hash sha; + sha.Initialize(); + sha.UpdateData(_login); + sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); + sha.Finalize(); + + 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 + 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.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } +} + +ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +{ + // 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; + } + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) + return realm.LocalAddress; + + // Return external IP + return realm.ExternalAddress; +} + + +bool AuthSession::_HandleRealmList() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); + + // Get the user id (else close the connection) + // No SQL injection (prepared statement) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); + stmt->setString(0, _login); + 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.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } + + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + // Update realm list if need + 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) + { + const Realm &realm = i->second; + // don't work with realms which not compatible with the client + bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); + + // No SQL injection. id of realm is controlled by the database. + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (!okBuild) + { + if (!buildInfo) + continue; + + flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + if (!buildInfo) + flag &= ~REALM_FLAG_SPECIFYBUILD; + + std::string name = i->first; + if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream ss; + ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; + name = ss.str(); + } + + // We don't need the port number from which client connects with but the realm's port + ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); + + uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + + uint8 AmountOfCharacters = 0; + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); + stmt->setUInt32(0, realm.m_ID); + stmt->setUInt32(1, id); + result = LoginDatabase.Query(stmt); + if (result) + AmountOfCharacters = (*result)[0].GetUInt8(); + + pkt << realm.icon; // realm type + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + pkt << lock; // if 1, then realm locked + pkt << uint8(flag); // RealmFlags + pkt << name; + pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << realm.populationLevel; + pkt << AmountOfCharacters; + pkt << realm.timezone; // realm category + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + pkt << uint8(0x2C); // unk, may be realm number/id? + else + pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients + + if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + pkt << uint8(buildInfo->MajorVersion); + pkt << uint8(buildInfo->MinorVersion); + pkt << uint8(buildInfo->BugfixVersion); + pkt << uint16(buildInfo->Build); + } + + ++RealmListSize; + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + pkt << uint8(0x10); + pkt << uint8(0x00); + } + else // 1.12.1 and 1.12.2 clients + { + pkt << uint8(0x00); + pkt << uint8(0x02); + } + + // make a ByteBuffer which stores the RealmList's size + ByteBuffer RealmListSizeBuffer; + RealmListSizeBuffer << uint32(0); + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + RealmListSizeBuffer << uint16(RealmListSize); + else + RealmListSizeBuffer << uint32(RealmListSize); + + ByteBuffer hdr; + hdr << uint8(REALM_LIST); + hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); + hdr.append(RealmListSizeBuffer); // append RealmList's size buffer + hdr.append(pkt); // append realms in the realmlist + + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(hdr.size()); + + return true; +} + +// Make the SRP6 calculation from hash in dB +void AuthSession::SetVSFields(const std::string& rI) +{ + s.SetRand(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); +} \ No newline at end of file diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h new file mode 100644 index 00000000000..205300e806a --- /dev/null +++ b/src/server/authserver/Server/AuthSession.h @@ -0,0 +1,85 @@ +/* +* Copyright (C) 2008-2014 TrinityCore +* Copyright (C) 2005-2009 MaNGOS +* +* 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 . +*/ + +#ifndef __AUTHSESSION_H__ +#define __AUTHSESSION_H__ + +#include +#include + +#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 \ No newline at end of file diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp deleted file mode 100644 index c7bb600024a..00000000000 --- a/src/server/authserver/Server/AuthSocket.cpp +++ /dev/null @@ -1,1207 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -#include -#include - -#include "Common.h" -#include "Database/DatabaseEnv.h" -#include "ByteBuffer.h" -#include "Configuration/Config.h" -#include "Log.h" -#include "RealmList.h" -#include "AuthSocket.h" -#include "AuthCodes.h" -#include "TOTP.h" -#include "SHA1.h" -#include "openssl/crypto.h" - -#define ChunkSize 2048 - -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 -}; - -enum eStatus -{ - 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 -{ - uint8 cmd; - uint8 error; - uint16 size; - uint8 gamename[4]; - uint8 version1; - uint8 version2; - uint8 version3; - uint16 build; - uint8 platform[4]; - uint8 os[4]; - uint8 country[4]; - uint32 timezone_bias; - uint32 ip; - uint8 I_len; - uint8 I[1]; -} sAuthLogonChallenge_C; - -typedef struct AUTH_LOGON_PROOF_C -{ - uint8 cmd; - uint8 A[32]; - uint8 M1[20]; - uint8 crc_hash[20]; - uint8 number_of_keys; - uint8 securityFlags; // 0x00-0x04 -} sAuthLogonProof_C; - -typedef struct AUTH_LOGON_PROOF_S -{ - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk1; - uint32 unk2; - uint16 unk3; -} sAuthLogonProof_S; - -typedef struct AUTH_LOGON_PROOF_S_OLD -{ - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk2; -} sAuthLogonProof_S_Old; - -typedef struct AUTH_RECONNECT_PROOF_C -{ - uint8 cmd; - uint8 R1[16]; - uint8 R2[20]; - uint8 R3[20]; - 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; - -typedef struct AuthHandler -{ - eAuthCmd cmd; - uint32 status; - bool (AuthSocket::*handler)(void); -} 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 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; -}; - -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 } -}; - -#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) -{ - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); -} - -// Close patch file descriptor before leaving -AuthSocket::~AuthSocket(void) { } - -// Accept the connection -void AuthSocket::OnAccept(void) -{ - TC_LOG_DEBUG("server.authserver", "'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); -} - -void AuthSocket::OnClose(void) -{ - TC_LOG_DEBUG("server.authserver", "AuthSocket::OnClose"); -} - -// 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) - { - if (!socket().recv_soft((char *)&_cmd, 1)) - return; - - if (_cmd == AUTH_LOGON_CHALLENGE) - { - ++challengesInARow; - if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) - { - 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(); - 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; - } - } - - // Report unknown packets in the error log - if (i == AUTH_TOTAL_COMMANDS) - { - TC_LOG_ERROR("server.authserver", "Got unknown packet from '%s'", socket().getRemoteAddress().c_str()); - socket().shutdown(); - return; - } - } -} - -// Make the SRP6 calculation from hash in dB -void AuthSocket::_SetVSFields(const std::string& rI) -{ - 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); -} - -// Logon Challenge command handler -bool AuthSocket::_HandleLogonChallenge() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonChallenge"); - 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 buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); - - EndianConvertPtr(&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(&ch->gamename[0]); - EndianConvert(ch->build); - EndianConvertPtr(&ch->platform[0]); - EndianConvertPtr(&ch->os[0]); - EndianConvertPtr(&ch->country[0]); - EndianConvert(ch->timezone_bias); - EndianConvert(ch->ip); - - ByteBuffer pkt; - - _login = (const char*)ch->I; - _build = ch->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; - - if (_os.size() > 4) - return false; - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - pkt << uint8(AUTH_LOGON_CHALLENGE); - pkt << uint8(0x00); - - // 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(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ip_address); - 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()); - } - else - { - // Get the account details from the account table - // No SQL injection (prepared statement) - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); - stmt->setString(0, _login); - - PreparedQueryResult res2 = LoginDatabase.Query(stmt); - if (res2) - { - Field* fields = res2->Fetch(); - - // If the IP is 'locked', check that the player comes indeed from the correct IP address - bool locked = false; - 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()); - - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); - pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); - } - else - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - 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()); - EndianConvertReverse(ip); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); - stmt->setUInt32(0, ip); - 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()); - if (loginCountry != accountCountry) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); - pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); - } - } - - if (!locked) - { - //set expired bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - // If the account is banned, reject the logon attempt - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); - stmt->setUInt32(0, fields[1].GetUInt32()); - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - if (banresult) - { - 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 ()); - } - 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 ()); - } - } - else - { - // Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = fields[0].GetString(); - - // Don't calculate (v, s) if there are already some in the database - std::string databaseV = fields[6].GetString(); - std::string databaseS = fields[7].GetString(); - - 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); - else - { - s.SetHexStr(databaseS.c_str()); - v.SetHexStr(databaseV.c_str()); - } - - b.SetRand(19 * 8); - BigNumber gmod = g.ModExp(b, N); - B = ((v * 3) + gmod) % N; - - ASSERT(gmod.GetNumBytes() <= 32); - - BigNumber unk3; - unk3.SetRand(16 * 8); - - // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) - pkt << uint8(WOW_SUCCESS); - else - pkt << uint8(WOW_FAIL_VERSION_INVALID); - - // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes - pkt << uint8(1); - pkt.append(g.AsByteArray().get(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[8].GetString(); - if (!_tokenKey.empty()) - securityFlags = 4; - - pkt << uint8(securityFlags); // security flags (0x0...0x04) - - if (securityFlags & 0x01) // PIN input - { - pkt << uint32(0); - pkt << uint64(0) << uint64(0); // 16 bytes hash? - } - - if (securityFlags & 0x02) // Matrix input - { - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint64(0); - } - - if (securityFlags & 0x04) // Security token input - pkt << uint8(1); - - uint8 secLevel = fields[5].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = ch->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) - ); - } - } - } - else //no account - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - } - - socket().send((char const*)pkt.contents(), pkt.size()); - return true; -} - -// Logon Proof command handler -bool AuthSocket::_HandleLogonProof() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); - // Read the packet - sAuthLogonProof_C lp; - - if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) - return false; - - // 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; - } - - // Continue the SRP6 calculation based on data received from the client - BigNumber A; - - A.SetBinary(lp.A, 32); - - // SRP safeguard: abort if A == 0 - if (A.isZero()) - { - socket().shutdown(); - return true; - } - - SHA1Hash sha; - sha.UpdateBigNumbers(&A, &B, NULL); - sha.Finalize(); - BigNumber u; - u.SetBinary(sha.GetDigest(), 20); - BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); - - uint8 t[32]; - uint8 t1[16]; - uint8 vK[40]; - memcpy(t, S.AsByteArray(32).get(), 32); - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2] = sha.GetDigest()[i]; - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2 + 1]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2 + 1] = sha.GetDigest()[i]; - - K.SetBinary(vK, 40); - - uint8 hash[20]; - - sha.Initialize(); - sha.UpdateBigNumbers(&N, NULL); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), 20); - sha.Initialize(); - sha.UpdateBigNumbers(&g, NULL); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - hash[i] ^= sha.GetDigest()[i]; - - BigNumber t3; - t3.SetBinary(hash, 20); - - sha.Initialize(); - sha.UpdateData(_login); - sha.Finalize(); - uint8 t4[SHA_DIGEST_LENGTH]; - memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); - - sha.Initialize(); - sha.UpdateBigNumbers(&t3, NULL); - sha.UpdateData(t4, SHA_DIGEST_LENGTH); - sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); - sha.Finalize(); - BigNumber M; - 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)) - { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().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 - const char *K_hex = K.AsHexStr(); - - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K_hex); - stmt->setString(1, socket().getRemoteAddress().c_str()); - stmt->setUInt32(2, GetLocaleByName(_localizationName)); - stmt->setString(3, _os); - stmt->setString(4, _login); - LoginDatabase.DirectExecute(stmt); - - OPENSSL_free((void*)K_hex); - - // Finish SRP6 and send the final result to the client - sha.Initialize(); - sha.UpdateBigNumbers(&A, &M, &K, NULL); - sha.Finalize(); - - // Check auth token - if ((lp.securityFlags & 0x04) || !_tokenKey.empty()) - { - uint8 size; - socket().recv((char*)&size, 1); - char* token = new char[size + 1]; - token[size] = '\0'; - socket().recv(token, size); - unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); - unsigned int incomingToken = atoi(token); - delete[] token; - if (validToken != incomingToken) - { - 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 - { - sAuthLogonProof_S proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - 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)); - } - else - { - sAuthLogonProof_S_Old proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk2 = 0x00; - socket().send((char *)&proof, sizeof(proof)); - } - - _authed = 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 ()); - - uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); - if (MaxWrongPassCount > 0) - { - //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); - stmt->setString(0, _login); - LoginDatabase.Execute(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); - stmt->setString(0, _login); - - if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) - { - uint32 failed_logins = (*loginfail)[1].GetUInt32(); - - if (failed_logins >= MaxWrongPassCount) - { - uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - uint32 acc_id = (*loginfail)[0].GetUInt32(); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); - stmt->setUInt32(0, acc_id); - stmt->setUInt32(1, WrongPassBanTime); - 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); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, socket().getRemoteAddress()); - 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); - } - } - } - } - } - - return true; -} - -// Reconnect Challenge command handler -bool AuthSocket::_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 buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); - - EndianConvertPtr(&buf[0]); - - 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; - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - // 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(); - return false; - } - - // Reinitialize build, expansion and the account securitylevel - _build = ch->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; - - if (_os.size() > 4) - return false; - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - Field* fields = result->Fetch(); - uint8 secLevel = fields[2].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - K.SetHexStr ((*result)[0].GetCString()); - - // Sending response - ByteBuffer pkt; - pkt << uint8(AUTH_RECONNECT_CHALLENGE); - pkt << uint8(0x00); - _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()); - return true; -} - -// Reconnect Proof command handler -bool AuthSocket::_HandleReconnectProof() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - // Read the packet - sAuthReconnectProof_C lp; - if (!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) - return false; - - if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) - return false; - - BigNumber t1; - t1.SetBinary(lp.R1, 16); - - SHA1Hash sha; - sha.Initialize(); - sha.UpdateData(_login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); - sha.Finalize(); - - if (!memcmp(sha.GetDigest(), lp.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; - 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(); - return false; - } -} - -ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) -{ - // 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; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; -} - -// Realm List command handler -bool AuthSocket::_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) - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, _login); - 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(); - return false; - } - - Field* fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - - // Update realm list if need - sRealmList->UpdateIfNeed(); - - ACE_INET_Addr clientAddr; - socket().peer().get_remote_addr(clientAddr); - - // 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) - { - const Realm &realm = i->second; - // don't work with realms which not compatible with the client - bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); - - // No SQL injection. id of realm is controlled by the database. - uint32 flag = realm.flag; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (!okBuild) - { - if (!buildInfo) - continue; - - flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for - } - - if (!buildInfo) - flag &= ~REALM_FLAG_SPECIFYBUILD; - - std::string name = i->first; - if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream ss; - ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; - 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; - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, id); - result = LoginDatabase.Query(stmt); - if (result) - AmountOfCharacters = (*result)[0].GetUInt8(); - - pkt << realm.icon; // realm type - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - pkt << lock; // if 1, then realm locked - pkt << uint8(flag); // RealmFlags - pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); - pkt << realm.populationLevel; - pkt << AmountOfCharacters; - pkt << realm.timezone; // realm category - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? - else - pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients - - if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - pkt << uint8(buildInfo->MajorVersion); - pkt << uint8(buildInfo->MinorVersion); - pkt << uint8(buildInfo->BugfixVersion); - pkt << uint16(buildInfo->Build); - } - - ++RealmListSize; - } - - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - { - pkt << uint8(0x10); - pkt << uint8(0x00); - } - else // 1.12.1 and 1.12.2 clients - { - pkt << uint8(0x00); - pkt << uint8(0x02); - } - - // make a ByteBuffer which stores the RealmList's size - ByteBuffer RealmListSizeBuffer; - RealmListSizeBuffer << uint32(0); - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - RealmListSizeBuffer << uint16(RealmListSize); - else - RealmListSizeBuffer << uint32(RealmListSize); - - ByteBuffer hdr; - hdr << uint8(REALM_LIST); - hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); - 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; - } - - // 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 -#include -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) -{ - // 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]; - - while (!feof(pPatch)) - { - size_t read = fread(buf, 1, 512 * 1024, pPatch); - MD5_Update(&ctx, buf, read); - } - - delete [] buf; - fclose(pPatch); - - // Store the result in the internal patch hash map - _patches[path] = new PATCH_INFO; - MD5_Final((uint8 *)&_patches[path]->md5, &ctx); -} - -// 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; - } - - return false; -} - -// Launch the patch hashing mechanism on object creation -Patcher::Patcher() -{ - LoadPatchesInfo(); -} - -// Empty and delete the patch map on termination -Patcher::~Patcher() -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - delete i->second; -} 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 - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -#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 - * Copyright (C) 2005-2010 MaNGOS - * - * 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 . - */ - -#ifndef __REALMACCEPTOR_H__ -#define __REALMACCEPTOR_H__ - -#include -#include - -#include "RealmSocket.h" -#include "AuthSocket.h" - -class RealmAcceptor : public ACE_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 - * Copyright (C) 2005-2010 MaNGOS - * - * 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 . - */ - -#include -#include -#include - -#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 - * Copyright (C) 2005-2010 MaNGOS - * - * 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 . - */ - -#ifndef __REALMSOCKET_H__ -#define __REALMSOCKET_H__ - -#include -#include -#include -#include -#include -#include "Common.h" - -class RealmSocket : public ACE_Svc_Handler -{ -private: - typedef ACE_Svc_Handler 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/worldserver/Master.cpp b/src/server/worldserver/Master.cpp index c5424374f5a..a5230b908ef 100644 --- a/src/server/worldserver/Master.cpp +++ b/src/server/worldserver/Master.cpp @@ -40,7 +40,6 @@ #include "TCSoap.h" #include "Timer.h" #include "Util.h" -#include "AuthSocket.h" #include "RealmList.h" #include "BigNumber.h" -- cgit v1.2.3 From b520f7da018aa0d771e6589b58081e71643bf860 Mon Sep 17 00:00:00 2001 From: leak Date: Fri, 30 May 2014 15:46:17 +0200 Subject: Damn you VS default settings.. --- src/server/authserver/Main.cpp | 168 +-- src/server/authserver/Realms/RealmList.h | 20 +- src/server/authserver/Server/AuthServer.cpp | 18 +- src/server/authserver/Server/AuthServer.h | 18 +- src/server/authserver/Server/AuthSession.cpp | 1572 +++++++++++++------------- src/server/authserver/Server/AuthSession.h | 78 +- 6 files changed, 937 insertions(+), 937 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index c8be23ca524..27834f50814 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -67,28 +67,28 @@ using boost::asio::ip::tcp; void SignalHandler(const boost::system::error_code& error, int signalNumber) { - TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); - if (!error) - { - switch (signalNumber) - { - case SIGINT: - case SIGTERM: - _ioService.stop(); - break; - } - } + TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); + 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(); + 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.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + } } /// Print out the usage string for this program on the console. @@ -170,22 +170,22 @@ int main(int argc, char** argv) std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - AuthServer authServer(_ioService, bindIp, port); + AuthServer authServer(_ioService, bindIp, port); - // Set signal handlers - boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); - signals.async_wait(SignalHandler); + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); + signals.async_wait(SignalHandler); - SetProcessPriority(); + SetProcessPriority(); - _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); - _dbPingTimer.async_wait(KeepDatabaseAliveHandler); + _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); - // Start the io service - _ioService.run(); + // Start the io service + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -244,69 +244,69 @@ void SetProcessPriority() { #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); + ///- 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."); - } + 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)); - } + 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 -} \ No newline at end of file +} diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1d76c39e4f0..88da30ea963 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -26,15 +26,15 @@ 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 @@ -73,7 +73,7 @@ public: uint32 size() const { return m_realms.size(); } private: - void UpdateRealms(bool init=false); + 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); RealmMap m_realms; diff --git a/src/server/authserver/Server/AuthServer.cpp b/src/server/authserver/Server/AuthServer.cpp index a699734be79..5c3ef247254 100644 --- a/src/server/authserver/Server/AuthServer.cpp +++ b/src/server/authserver/Server/AuthServer.cpp @@ -25,15 +25,15 @@ using boost::asio::ip::tcp; void AuthServer::AsyncAccept() { - _acceptor.async_accept(_socket, [this](boost::system::error_code error) - { - if (!error) - { - std::make_shared(std::move(_socket))->Start(); - } - - AsyncAccept(); - }); + _acceptor.async_accept(_socket, [this](boost::system::error_code error) + { + if (!error) + { + std::make_shared(std::move(_socket))->Start(); + } + + AsyncAccept(); + }); } diff --git a/src/server/authserver/Server/AuthServer.h b/src/server/authserver/Server/AuthServer.h index 0496326ee7b..985a48ad243 100644 --- a/src/server/authserver/Server/AuthServer.h +++ b/src/server/authserver/Server/AuthServer.h @@ -25,20 +25,20 @@ using boost::asio::ip::tcp; class AuthServer { public: - AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) - { - tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); + AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) + { + tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); - _acceptor = tcp::acceptor(ioService, endpoint); + _acceptor = tcp::acceptor(ioService, endpoint); - AsyncAccept(); - }; + AsyncAccept(); + }; private: - void AsyncAccept(); + void AsyncAccept(); - tcp::acceptor _acceptor; - tcp::socket _socket; + tcp::acceptor _acceptor; + tcp::socket _socket; }; #endif /* __AUTHSERVER_H__ */ diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index cb78336f2d3..6a3c145d08b 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -32,80 +32,80 @@ 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_AUTHED + STATUS_CONNECTED = 0, + STATUS_AUTHED }; #pragma pack(push, 1) typedef struct AUTH_LOGON_CHALLENGE_C { - uint8 cmd; - uint8 error; - uint16 size; - uint8 gamename[4]; - uint8 version1; - uint8 version2; - uint8 version3; - uint16 build; - uint8 platform[4]; - uint8 os[4]; - uint8 country[4]; - uint32 timezone_bias; - uint32 ip; - uint8 I_len; - uint8 I[1]; + uint8 cmd; + uint8 error; + uint16 size; + uint8 gamename[4]; + uint8 version1; + uint8 version2; + uint8 version3; + uint16 build; + uint8 platform[4]; + uint8 os[4]; + uint8 country[4]; + uint32 timezone_bias; + uint32 ip; + uint8 I_len; + uint8 I[1]; } sAuthLogonChallenge_C; typedef struct AUTH_LOGON_PROOF_C { - uint8 cmd; - uint8 A[32]; - uint8 M1[20]; - uint8 crc_hash[20]; - uint8 number_of_keys; - uint8 securityFlags; + uint8 cmd; + uint8 A[32]; + uint8 M1[20]; + uint8 crc_hash[20]; + uint8 number_of_keys; + uint8 securityFlags; } sAuthLogonProof_C; typedef struct AUTH_LOGON_PROOF_S { - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk1; - uint32 unk2; - uint16 unk3; + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk1; + uint32 unk2; + uint16 unk3; } sAuthLogonProof_S; typedef struct AUTH_LOGON_PROOF_S_OLD { - uint8 cmd; - uint8 error; - uint8 M2[20]; - uint32 unk2; + uint8 cmd; + uint8 error; + uint8 M2[20]; + uint32 unk2; } sAuthLogonProof_S_Old; typedef struct AUTH_RECONNECT_PROOF_C { - uint8 cmd; - uint8 R1[16]; - uint8 R2[20]; - uint8 R3[20]; - uint8 number_of_keys; + uint8 cmd; + uint8 R1[16]; + uint8 R2[20]; + uint8 R3[20]; + uint8 number_of_keys; } sAuthReconnectProof_C; #pragma pack(pop) @@ -113,10 +113,10 @@ typedef struct AUTH_RECONNECT_PROOF_C typedef struct AuthHandler { - eAuthCmd cmd; - uint32 status; - size_t packetSize; - bool (AuthSession::*handler)(); + eAuthCmd cmd; + uint32 status; + size_t packetSize; + bool (AuthSession::*handler)(); } AuthHandler; #define BYTE_SIZE 32 @@ -124,792 +124,792 @@ typedef struct AuthHandler const AuthHandler table[] = { - { 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 } + { 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 } }; void AuthSession::AsyncReadHeader() { - auto self(shared_from_this()); - - _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 - - AsyncReadData(entry.handler, (uint16)&_readBuffer[2], sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size - } - else - { - AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); - } - break; - } - } - } - else - { - _socket.close(); - } - }); + auto self(shared_from_this()); + + _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 + + AsyncReadData(entry.handler, (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 AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) { - auto self(shared_from_this()); - - _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) - { - if (!error && transferedBytes > 0) - { - if (!(*this.*handler)()) - { - _socket.close(); - return; - } - - AsyncReadHeader(); - } - else - { - _socket.close(); - } - }); + auto self(shared_from_this()); + + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes > 0) + { + if (!(*this.*handler)()) + { + _socket.close(); + return; + } + + AsyncReadHeader(); + } + else + { + _socket.close(); + } + }); } void AuthSession::AsyncWrite(std::size_t length) { - boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) - { - if (error) - { - _socket.close(); - } - }); + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); } bool AuthSession::_HandleLogonChallenge() { - sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - - //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.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*)challenge->os; - - if (_os.size() > 4) - return false; - - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); - - pkt << uint8(AUTH_LOGON_CHALLENGE); - pkt << uint8(0x00); - - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - - 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, 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!", ipAddress.c_str(), port); - } - else - { - // Get the account details from the account table - // No SQL injection (prepared statement) - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); - stmt->setString(0, _login); - - PreparedQueryResult res2 = LoginDatabase.Query(stmt); - if (res2) - { - Field* fields = res2->Fetch(); - - // If the IP is 'locked', check that the player comes indeed from the correct IP address - bool locked = false; - 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'", ipAddress.c_str()); - - if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); - pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); - } - else - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); - else if (!accountCountry.empty()) - { - uint32 ip = inet_addr(ipAddress.c_str()); - EndianConvertReverse(ip); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); - stmt->setUInt32(0, ip); - 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()); - - if (loginCountry != accountCountry) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); - pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); - } - } - - if (!locked) - { - //set expired bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - // If the account is banned, reject the logon attempt - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); - stmt->setUInt32(0, fields[1].GetUInt32()); - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - if (banresult) - { - 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!", 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!", - ipAddress.c_str(), port, _login.c_str()); - } - } - else - { - // Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = fields[0].GetString(); - - // Don't calculate (v, s) if there are already some in the database - std::string databaseV = fields[6].GetString(); - std::string databaseS = fields[7].GetString(); - - 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() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) - SetVSFields(rI); - else - { - s.SetHexStr(databaseS.c_str()); - v.SetHexStr(databaseV.c_str()); - } - - b.SetRand(19 * 8); - BigNumber gmod = g.ModExp(b, N); - B = ((v * 3) + gmod) % N; - - ASSERT(gmod.GetNumBytes() <= 32); - - BigNumber unk3; - unk3.SetRand(16 * 8); - - // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) - pkt << uint8(WOW_SUCCESS); - else - pkt << uint8(WOW_FAIL_VERSION_INVALID); - - // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes - pkt << uint8(1); - pkt.append(g.AsByteArray().get(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[8].GetString(); - if (!_tokenKey.empty()) - securityFlags = 4; - - pkt << uint8(securityFlags); // security flags (0x0...0x04) - - if (securityFlags & 0x01) // PIN input - { - pkt << uint32(0); - pkt << uint64(0) << uint64(0); // 16 bytes hash? - } - - if (securityFlags & 0x02) // Matrix input - { - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint64(0); - } - - if (securityFlags & 0x04) // Security token input - pkt << uint8(1); - - uint8 secLevel = fields[5].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _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)", - ipAddress.c_str(), port, _login.c_str(), - challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], - GetLocaleByName(_localizationName) - ); - } - } - } - else //no account - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - } - - std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); - - AsyncWrite(pkt.size()); - - return true; + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + + //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.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*)challenge->os; + + if (_os.size() > 4) + return false; + + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); + + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + 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, 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!", ipAddress.c_str(), port); + } + else + { + // Get the account details from the account table + // No SQL injection (prepared statement) + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); + stmt->setString(0, _login); + + PreparedQueryResult res2 = LoginDatabase.Query(stmt); + if (res2) + { + Field* fields = res2->Fetch(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + bool locked = false; + 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'", ipAddress.c_str()); + + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); + pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); + } + else + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); + else if (!accountCountry.empty()) + { + uint32 ip = inet_addr(ipAddress.c_str()); + EndianConvertReverse(ip); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); + stmt->setUInt32(0, ip); + 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()); + + if (loginCountry != accountCountry) + { + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); + pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); + locked = true; + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); + } + else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); + } + } + + if (!locked) + { + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); + stmt->setUInt32(0, fields[1].GetUInt32()); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + 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!", 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!", + ipAddress.c_str(), port, _login.c_str()); + } + } + else + { + // Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = fields[0].GetString(); + + // Don't calculate (v, s) if there are already some in the database + std::string databaseV = fields[6].GetString(); + std::string databaseS = fields[7].GetString(); + + 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() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(19 * 8); + BigNumber gmod = g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16 * 8); + + // Fill the response packet with the result + if (AuthHelper::IsAcceptedClientBuild(_build)) + pkt << uint8(WOW_SUCCESS); + else + pkt << uint8(WOW_FAIL_VERSION_INVALID); + + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt << uint8(1); + pkt.append(g.AsByteArray().get(), 1); + pkt << uint8(32); + pkt.append(N.AsByteArray(32).get(), 32); + pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes + pkt.append(unk3.AsByteArray(16).get(), 16); + uint8 securityFlags = 0; + + // Check if token is used + _tokenKey = fields[8].GetString(); + if (!_tokenKey.empty()) + securityFlags = 4; + + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if (securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if (securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if (securityFlags & 0x04) // Security token input + pkt << uint8(1); + + uint8 secLevel = fields[5].GetUInt8(); + _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _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)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) + ); + } + } + } + else //no account + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + } + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + + return true; } // Logon Proof command handler bool AuthSession::_HandleLogonProof() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); - // Read the packet - 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"); - return false; - } - - // Continue the SRP6 calculation based on data received from the client - BigNumber A; - - A.SetBinary(logonProof->A, 32); - - // SRP safeguard: abort if A == 0 - if (A.isZero()) - { - return false; - } - - SHA1Hash sha; - sha.UpdateBigNumbers(&A, &B, NULL); - sha.Finalize(); - BigNumber u; - u.SetBinary(sha.GetDigest(), 20); - BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); - - uint8 t[32]; - uint8 t1[16]; - uint8 vK[40]; - memcpy(t, S.AsByteArray(32).get(), 32); - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2] = sha.GetDigest()[i]; - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2 + 1]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2 + 1] = sha.GetDigest()[i]; - - K.SetBinary(vK, 40); - - uint8 hash[20]; - - sha.Initialize(); - sha.UpdateBigNumbers(&N, NULL); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), 20); - sha.Initialize(); - sha.UpdateBigNumbers(&g, NULL); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - hash[i] ^= sha.GetDigest()[i]; - - BigNumber t3; - t3.SetBinary(hash, 20); - - sha.Initialize(); - sha.UpdateData(_login); - sha.Finalize(); - uint8 t4[SHA_DIGEST_LENGTH]; - memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); - - sha.Initialize(); - sha.UpdateBigNumbers(&t3, NULL); - sha.UpdateData(t4, SHA_DIGEST_LENGTH); - sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); - sha.Finalize(); - BigNumber M; - M.SetBinary(sha.GetDigest(), 20); - - // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) - { - 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 - const char *K_hex = K.AsHexStr(); - - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K_hex); - stmt->setString(1, GetRemoteIpAddress().c_str()); - stmt->setUInt32(2, GetLocaleByName(_localizationName)); - stmt->setString(3, _os); - stmt->setString(4, _login); - LoginDatabase.DirectExecute(stmt); - - OPENSSL_free((void*)K_hex); - - // Finish SRP6 and send the final result to the client - sha.Initialize(); - sha.UpdateBigNumbers(&A, &M, &K, NULL); - sha.Finalize(); - - // Check auth token - if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) - { - // TODO To be fixed - - /* - uint8 size; - socket().recv((char*)&size, 1); - char* token = new char[size + 1]; - token[size] = '\0'; - socket().recv(token, size); - unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); - unsigned int incomingToken = atoi(token); - delete[] token; - if (validToken != incomingToken) - { - 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 - { - sAuthLogonProof_S proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) - proof.unk2 = 0x00; // SurveyId - proof.unk3 = 0x00; - - std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); - AsyncWrite(sizeof(proof)); - } - else - { - sAuthLogonProof_S_Old proof; - memcpy(proof.M2, sha.GetDigest(), 20); - proof.cmd = AUTH_LOGON_PROOF; - proof.error = 0; - proof.unk2 = 0x00; - - std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); - AsyncWrite(sizeof(proof)); - } - - _isAuthenticated = true; - } - else - { - char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - - 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); - if (MaxWrongPassCount > 0) - { - //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP - PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); - stmt->setString(0, _login); - LoginDatabase.Execute(stmt); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); - stmt->setString(0, _login); - - if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) - { - uint32 failed_logins = (*loginfail)[1].GetUInt32(); - - if (failed_logins >= MaxWrongPassCount) - { - uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - uint32 acc_id = (*loginfail)[0].GetUInt32(); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); - stmt->setUInt32(0, acc_id); - stmt->setUInt32(1, WrongPassBanTime); - 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", - GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, GetRemoteIpAddress()); - stmt->setUInt32(1, WrongPassBanTime); - LoginDatabase.Execute(stmt); - - 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); - } - } - } - } - } - - return true; + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); + // Read the packet + 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"); + return false; + } + + // Continue the SRP6 calculation based on data received from the client + BigNumber A; + + A.SetBinary(logonProof->A, 32); + + // SRP safeguard: abort if A == 0 + if (A.isZero()) + { + return false; + } + + SHA1Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + BigNumber u; + u.SetBinary(sha.GetDigest(), 20); + BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); + + uint8 t[32]; + uint8 t1[16]; + uint8 vK[40]; + memcpy(t, S.AsByteArray(32).get(), 32); + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2] = sha.GetDigest()[i]; + + for (int i = 0; i < 16; ++i) + t1[i] = t[i * 2 + 1]; + + sha.Initialize(); + sha.UpdateData(t1, 16); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + vK[i * 2 + 1] = sha.GetDigest()[i]; + + K.SetBinary(vK, 40); + + uint8 hash[20]; + + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), 20); + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < 20; ++i) + hash[i] ^= sha.GetDigest()[i]; + + BigNumber t3; + t3.SetBinary(hash, 20); + + sha.Initialize(); + sha.UpdateData(_login); + sha.Finalize(); + uint8 t4[SHA_DIGEST_LENGTH]; + memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); + + sha.Initialize(); + sha.UpdateBigNumbers(&t3, NULL); + sha.UpdateData(t4, SHA_DIGEST_LENGTH); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + BigNumber M; + M.SetBinary(sha.GetDigest(), 20); + + // Check if SRP6 results match (password is correct), else send an error + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) + { + 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 + const char *K_hex = K.AsHexStr(); + + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); + stmt->setString(0, K_hex); + stmt->setString(1, GetRemoteIpAddress().c_str()); + stmt->setUInt32(2, GetLocaleByName(_localizationName)); + stmt->setString(3, _os); + stmt->setString(4, _login); + LoginDatabase.DirectExecute(stmt); + + OPENSSL_free((void*)K_hex); + + // Finish SRP6 and send the final result to the client + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M, &K, NULL); + sha.Finalize(); + + // Check auth token + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) + { + // TODO To be fixed + + /* + uint8 size; + socket().recv((char*)&size, 1); + char* token = new char[size + 1]; + token[size] = '\0'; + socket().recv(token, size); + unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str()); + unsigned int incomingToken = atoi(token); + delete[] token; + if (validToken != incomingToken) + { + 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 + { + sAuthLogonProof_S proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.unk2 = 0x00; // SurveyId + proof.unk3 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + else + { + sAuthLogonProof_S_Old proof; + memcpy(proof.M2, sha.GetDigest(), 20); + proof.cmd = AUTH_LOGON_PROOF; + proof.error = 0; + proof.unk2 = 0x00; + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); + } + + _isAuthenticated = true; + } + else + { + char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + + 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); + if (MaxWrongPassCount > 0) + { + //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP + PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); + stmt->setString(0, _login); + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); + stmt->setString(0, _login); + + if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) + { + uint32 failed_logins = (*loginfail)[1].GetUInt32(); + + if (failed_logins >= MaxWrongPassCount) + { + uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); + bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); + + if (WrongPassBanType) + { + uint32 acc_id = (*loginfail)[0].GetUInt32(); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); + stmt->setUInt32(0, acc_id); + stmt->setUInt32(1, WrongPassBanTime); + 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", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); + stmt->setString(0, GetRemoteIpAddress()); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + 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); + } + } + } + } + } + + return true; } bool AuthSession::_HandleReconnectChallenge() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - //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); + //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); - _login.assign((const char*)challenge->I, challenge->I_len); + _login.assign((const char*)challenge->I, challenge->I_len); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); + stmt->setString(0, _login); + PreparedQueryResult result = LoginDatabase.Query(stmt); - // 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.", - GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); - return false; - } + // 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.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); + return false; + } - // Reinitialize build, expansion and the account securitylevel - _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*)challenge->os; + // Reinitialize build, expansion and the account securitylevel + _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*)challenge->os; - if (_os.size() > 4) - return false; + if (_os.size() > 4) + return false; - // Restore string order as its byte order is reversed - std::reverse(_os.begin(), _os.end()); + // Restore string order as its byte order is reversed + std::reverse(_os.begin(), _os.end()); - Field* fields = result->Fetch(); - uint8 secLevel = fields[2].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + Field* fields = result->Fetch(); + 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; - pkt << uint8(AUTH_RECONNECT_CHALLENGE); - pkt << uint8(0x00); - _reconnectProof.SetRand(16 * 8); - pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random - pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros + // Sending response + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_CHALLENGE); + pkt << uint8(0x00); + _reconnectProof.SetRand(16 * 8); + pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); - AsyncWrite(pkt.size()); + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); - return true; + return true; } bool AuthSession::_HandleReconnectProof() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; - - if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) - return false; - - BigNumber t1; - t1.SetBinary(reconnectProof->R1, 16); - - SHA1Hash sha; - sha.Initialize(); - sha.UpdateData(_login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); - sha.Finalize(); - - 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 - 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.", GetRemoteIpAddress().c_str(), - GetRemotePort(), _login.c_str()); - return false; - } + TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; + + if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + return false; + + BigNumber t1; + t1.SetBinary(reconnectProof->R1, 16); + + SHA1Hash sha; + sha.Initialize(); + sha.UpdateData(_login); + sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); + sha.Finalize(); + + 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 + 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.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } } ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) { - // 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; - } - - // Check if connecting client is in the same network - if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) - return realm.LocalAddress; - - // Return external IP - return realm.ExternalAddress; + // 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; + } + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) + return realm.LocalAddress; + + // Return external IP + return realm.ExternalAddress; } bool AuthSession::_HandleRealmList() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - - // Get the user id (else close the connection) - // No SQL injection (prepared statement) - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, _login); - 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.", GetRemoteIpAddress().c_str(), - GetRemotePort(), _login.c_str()); - return false; - } - - Field* fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); - - // Update realm list if need - 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) - { - const Realm &realm = i->second; - // don't work with realms which not compatible with the client - bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); - - // No SQL injection. id of realm is controlled by the database. - uint32 flag = realm.flag; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (!okBuild) - { - if (!buildInfo) - continue; - - flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for - } - - if (!buildInfo) - flag &= ~REALM_FLAG_SPECIFYBUILD; - - std::string name = i->first; - if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream ss; - ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; - name = ss.str(); - } - - // We don't need the port number from which client connects with but the realm's port - ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); - - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - - uint8 AmountOfCharacters = 0; - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, id); - result = LoginDatabase.Query(stmt); - if (result) - AmountOfCharacters = (*result)[0].GetUInt8(); - - pkt << realm.icon; // realm type - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - pkt << lock; // if 1, then realm locked - pkt << uint8(flag); // RealmFlags - pkt << name; - pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); - pkt << realm.populationLevel; - pkt << AmountOfCharacters; - pkt << realm.timezone; // realm category - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? - else - pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients - - if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) - { - pkt << uint8(buildInfo->MajorVersion); - pkt << uint8(buildInfo->MinorVersion); - pkt << uint8(buildInfo->BugfixVersion); - pkt << uint16(buildInfo->Build); - } - - ++RealmListSize; - } - - if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - { - pkt << uint8(0x10); - pkt << uint8(0x00); - } - else // 1.12.1 and 1.12.2 clients - { - pkt << uint8(0x00); - pkt << uint8(0x02); - } - - // make a ByteBuffer which stores the RealmList's size - ByteBuffer RealmListSizeBuffer; - RealmListSizeBuffer << uint32(0); - if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - RealmListSizeBuffer << uint16(RealmListSize); - else - RealmListSizeBuffer << uint32(RealmListSize); - - ByteBuffer hdr; - hdr << uint8(REALM_LIST); - hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); - hdr.append(RealmListSizeBuffer); // append RealmList's size buffer - hdr.append(pkt); // append realms in the realmlist - - std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); - AsyncWrite(hdr.size()); - - return true; + TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); + + // Get the user id (else close the connection) + // No SQL injection (prepared statement) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); + stmt->setString(0, _login); + 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.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); + return false; + } + + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + + // Update realm list if need + 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) + { + const Realm &realm = i->second; + // don't work with realms which not compatible with the client + bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild)); + + // No SQL injection. id of realm is controlled by the database. + uint32 flag = realm.flag; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (!okBuild) + { + if (!buildInfo) + continue; + + flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + if (!buildInfo) + flag &= ~REALM_FLAG_SPECIFYBUILD; + + std::string name = i->first; + if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream ss; + ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')'; + name = ss.str(); + } + + // We don't need the port number from which client connects with but the realm's port + ACE_INET_Addr clientAddr(realm.ExternalAddress.get_port_number(), GetRemoteIpAddress().c_str(), AF_INET); + + uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + + uint8 AmountOfCharacters = 0; + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); + stmt->setUInt32(0, realm.m_ID); + stmt->setUInt32(1, id); + result = LoginDatabase.Query(stmt); + if (result) + AmountOfCharacters = (*result)[0].GetUInt8(); + + pkt << realm.icon; // realm type + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + pkt << lock; // if 1, then realm locked + pkt << uint8(flag); // RealmFlags + pkt << name; + pkt << GetAddressString(GetAddressForClient(realm, clientAddr)); + pkt << realm.populationLevel; + pkt << AmountOfCharacters; + pkt << realm.timezone; // realm category + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + pkt << uint8(0x2C); // unk, may be realm number/id? + else + pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients + + if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD) + { + pkt << uint8(buildInfo->MajorVersion); + pkt << uint8(buildInfo->MinorVersion); + pkt << uint8(buildInfo->BugfixVersion); + pkt << uint16(buildInfo->Build); + } + + ++RealmListSize; + } + + if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients + { + pkt << uint8(0x10); + pkt << uint8(0x00); + } + else // 1.12.1 and 1.12.2 clients + { + pkt << uint8(0x00); + pkt << uint8(0x02); + } + + // make a ByteBuffer which stores the RealmList's size + ByteBuffer RealmListSizeBuffer; + RealmListSizeBuffer << uint32(0); + if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients + RealmListSizeBuffer << uint16(RealmListSize); + else + RealmListSizeBuffer << uint32(RealmListSize); + + ByteBuffer hdr; + hdr << uint8(REALM_LIST); + hdr << uint16(pkt.size() + RealmListSizeBuffer.size()); + hdr.append(RealmListSizeBuffer); // append RealmList's size buffer + hdr.append(pkt); // append realms in the realmlist + + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(hdr.size()); + + return true; } // Make the SRP6 calculation from hash in dB void AuthSession::SetVSFields(const std::string& rI) { - s.SetRand(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); -} \ No newline at end of file + s.SetRand(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); +} diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 205300e806a..79b1e568aa6 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -34,52 +34,52 @@ const size_t bufferSize = 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(); } + 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 AsyncReadHeader(); + void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset); + void AsyncWrite(size_t length); - void SetVSFields(const std::string& rI); + void SetVSFields(const std::string& rI); - BigNumber N, s, g, v; - BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; + BigNumber N, s, g, v; + BigNumber b, B; + BigNumber K; + BigNumber _reconnectProof; - tcp::socket _socket; - char _readBuffer[BUFFER_SIZE]; - char _writeBuffer[BUFFER_SIZE]; + 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; + bool _isAuthenticated; + std::string _tokenKey; + std::string _login; + std::string _localizationName; + std::string _os; + uint16 _build; + uint8 _expversion; - AccountTypes _accountSecurityLevel; + AccountTypes _accountSecurityLevel; }; -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From bf6e58b8d44d3a4b78e9473df029caac74c68220 Mon Sep 17 00:00:00 2001 From: leak Date: Sat, 31 May 2014 15:58:59 +0200 Subject: Ditched ACE_Singleton in favor of C++11 like Singleton --- src/server/authserver/Main.cpp | 5 +++-- src/server/authserver/Realms/RealmList.h | 16 ++++++++++------ src/server/authserver/Server/AuthSession.cpp | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 27834f50814..2427c47a438 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -152,8 +152,9 @@ 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(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + + if (sRealmList.size() == 0) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); return 1; diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 88da30ea963..29b6aca07d3 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,8 +19,6 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include -#include #include #include "Common.h" @@ -59,8 +57,11 @@ class RealmList public: typedef std::map RealmMap; - RealmList(); - ~RealmList() { } + static RealmList& instance() + { + static RealmList *instance = new RealmList(); + return *instance; + } void Initialize(uint32 updateInterval); @@ -73,13 +74,16 @@ public: uint32 size() const { return m_realms.size(); } private: + RealmList(); + 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); + 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); RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; }; -#define sRealmList ACE_Singleton::instance() +#define sRealmList RealmList::instance() #endif diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index a366f7d11f7..627e1fc470d 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -772,13 +772,13 @@ bool AuthSession::_HandleRealmList() uint32 id = fields[0].GetUInt32(); // Update realm list if need - sRealmList->UpdateIfNeed(); + 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 -- cgit v1.2.3 From eb36acd1522a2e5b8a7d2b4b4a67fc34fc777f03 Mon Sep 17 00:00:00 2001 From: leak Date: Mon, 30 Jun 2014 14:44:52 +0200 Subject: Replaced ACE_Task_Base based LogWorker with ProducerConsumerQueue --- src/server/authserver/Main.cpp | 1 - src/server/shared/Configuration/Config.cpp | 6 +- src/server/shared/Logging/Log.cpp | 2 +- src/server/shared/Logging/Log.h | 1 + src/server/shared/Logging/LogWorker.cpp | 34 ++++--- src/server/shared/Logging/LogWorker.h | 27 +++--- .../shared/Threading/ProducerConsumerQueue.h | 102 +++++++++++++++++++++ 7 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 src/server/shared/Threading/ProducerConsumerQueue.h (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 2427c47a438..3901480c70d 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -67,7 +67,6 @@ using boost::asio::ip::tcp; void SignalHandler(const boost::system::error_code& error, int signalNumber) { - TC_LOG_ERROR("server.authserver", "SIGNAL HANDLER WORKING"); if (!error) { switch (signalNumber) diff --git a/src/server/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index 9e0e57eb198..b6690d02155 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -71,7 +71,7 @@ bool ConfigMgr::GetBoolDefault(const char* name, bool def) { try { - std::string val = _config.get(name); + std::string val = _config.get(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"); } @@ -83,12 +83,12 @@ bool ConfigMgr::GetBoolDefault(const char* name, bool def) int ConfigMgr::GetIntDefault(const char* name, int def) { - return _config.get(name, def); + return _config.get(ptree::path_type(name, '/'), def); } float ConfigMgr::GetFloatDefault(const char* name, float def) { - return _config.get(name, def); + return _config.get(ptree::path_type(name, '/'), def); } std::string const& ConfigMgr::GetFilename() diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index fd7aa84c0e9..57d8797e61e 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -273,7 +273,7 @@ void Log::write(LogMessage* msg) const msg->text.append("\n"); if (worker) - worker->enqueue(new LogOperation(logger, msg)); + worker->Enqueue(new LogOperation(logger, msg)); else { logger->write(*msg); diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index c3a47d14e9e..8d2fd33d886 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -23,6 +23,7 @@ #include "Appender.h" #include "Logger.h" #include "LogWorker.h" +#include #include #include diff --git a/src/server/shared/Logging/LogWorker.cpp b/src/server/shared/Logging/LogWorker.cpp index b0c82b614f4..ab0f41bf105 100644 --- a/src/server/shared/Logging/LogWorker.cpp +++ b/src/server/shared/Logging/LogWorker.cpp @@ -16,35 +16,41 @@ */ #include "LogWorker.h" +#include LogWorker::LogWorker() - : m_queue(HIGH_WATERMARK, LOW_WATERMARK) { - ACE_Task_Base::activate(THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, 1); + _cancelationToken = false; + _workerThread = std::thread(&LogWorker::WorkerThread, this); } LogWorker::~LogWorker() { - m_queue.deactivate(); - wait(); + _cancelationToken = true; + + _queue.Cancel(); + + _workerThread.join(); } -int LogWorker::enqueue(LogOperation* op) +void LogWorker::Enqueue(LogOperation* op) { - return m_queue.enqueue(op); + return _queue.Push(op); } -int LogWorker::svc() +void LogWorker::WorkerThread() { while (1) { - LogOperation* request; - if (m_queue.dequeue(request) == -1) - break; + LogOperation* operation = nullptr; + + _queue.WaitAndPop(operation); - request->call(); - delete request; - } + if (_cancelationToken) + return; - return 0; + operation->call(); + + delete operation; + } } diff --git a/src/server/shared/Logging/LogWorker.h b/src/server/shared/Logging/LogWorker.h index 25a57842e08..b2680b12c34 100644 --- a/src/server/shared/Logging/LogWorker.h +++ b/src/server/shared/Logging/LogWorker.h @@ -18,30 +18,29 @@ #ifndef LOGWORKER_H #define LOGWORKER_H -#include "LogOperation.h" +#include +#include -#include -#include +#include "LogOperation.h" +#include "ProducerConsumerQueue.h" -class LogWorker: protected ACE_Task_Base +class LogWorker { public: LogWorker(); ~LogWorker(); - typedef ACE_Message_Queue_Ex LogMessageQueueType; + void Enqueue(LogOperation *op); - enum - { - HIGH_WATERMARK = 8 * 1024 * 1024, - LOW_WATERMARK = 8 * 1024 * 1024 - }; + private: + ProducerConsumerQueue _queue; - int enqueue(LogOperation *op); + void WorkerThread(); + std::thread _workerThread; - private: - virtual int svc(); - LogMessageQueueType m_queue; + std::atomic_bool _cancelationToken; }; + + #endif diff --git a/src/server/shared/Threading/ProducerConsumerQueue.h b/src/server/shared/Threading/ProducerConsumerQueue.h new file mode 100644 index 00000000000..961cb9f9c82 --- /dev/null +++ b/src/server/shared/Threading/ProducerConsumerQueue.h @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2008-2014 TrinityCore +* +* 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 . +*/ + +#ifndef _PCQ_H +#define _PCQ_H + +#include +#include +#include + +template +class ProducerConsumerQueue +{ +private: + std::mutex _queueLock; + std::queue _queue; + std::condition_variable _condition; + +public: + + void Push(const T& value) + { + _queueLock.lock(); + + _queue.push(std::move(value)); + + _queueLock.unlock(); + + _condition.notify_one(); + } + + bool Empty() const + { + std::lock_guard lock(_queueLock); + + return _queue.empty(); + } + + bool Pop(T& value) + { + std::lock_guard lock(_queueLock); + + if (_queue.empty()) + return false; + + value = _queue.front(); + + _queue.pop(); + + return true; + } + + void WaitAndPop(T& value) + { + std::unique_lock lock(_queueLock); + + _condition.wait(lock, [this](){ return !_queue.empty(); }); + + if (_queue.empty()) + return; + + value = _queue.front(); + + _queue.pop(); + } + + void Cancel() + { + _queueLock.lock(); + + while (!_queue.empty()) + { + T& value = _queue.front(); + + delete &value; + + _queue.pop(); + } + + _queueLock.unlock(); + + _condition.notify_all(); + } +}; + +#endif + + -- cgit v1.2.3 From 029bad6698df6ac9556fe308342e616f4a7a8cc7 Mon Sep 17 00:00:00 2001 From: leak Date: Tue, 1 Jul 2014 00:54:09 +0200 Subject: Replaced all remaining ACE based Singletons Replaced ACE base AutoPtr class with shared_ptr Note: worldserver currently broken due to MapUpdater threading failure (ACE ofc, what else could it be) --- src/server/authserver/Main.cpp | 1 - src/server/collision/Management/VMapManager2.cpp | 2 - src/server/game/AI/SmartScripts/SmartScriptMgr.h | 28 +++++++---- src/server/game/Accounts/AccountMgr.h | 11 +++-- src/server/game/Achievements/AchievementMgr.h | 10 ++-- src/server/game/AuctionHouse/AuctionHouseMgr.h | 11 +++-- src/server/game/Battlefield/BattlefieldMgr.h | 17 ++++--- src/server/game/Battlegrounds/ArenaTeam.h | 1 - src/server/game/Battlegrounds/ArenaTeamMgr.h | 10 +++- src/server/game/Battlegrounds/BattlegroundMgr.h | 11 +++-- src/server/game/Calendar/CalendarMgr.h | 11 +++-- src/server/game/Chat/Channels/ChannelMgr.cpp | 6 +-- src/server/game/Chat/Channels/ChannelMgr.h | 14 ++++-- src/server/game/Conditions/ConditionMgr.h | 12 +++-- src/server/game/DataStores/DBCStructure.h | 10 ++-- src/server/game/DungeonFinding/LFGMgr.h | 11 +++-- src/server/game/Entities/Creature/CreatureGroups.h | 13 +++-- src/server/game/Entities/Item/Item.cpp | 4 +- src/server/game/Entities/Player/Player.cpp | 6 +-- src/server/game/Entities/Player/SocialMgr.h | 11 +++-- src/server/game/Events/GameEventMgr.h | 11 +++-- src/server/game/Globals/ObjectMgr.h | 10 ++-- src/server/game/Groups/GroupMgr.h | 9 +++- src/server/game/Guilds/GuildMgr.h | 10 ++-- src/server/game/Handlers/AddonHandler.cpp | 4 -- src/server/game/Handlers/AddonHandler.h | 19 ++++---- src/server/game/Maps/MapManager.h | 14 +++--- src/server/game/Maps/TransportMgr.h | 10 ++-- src/server/game/Movement/MovementGenerator.h | 1 - .../game/Movement/Waypoints/WaypointManager.h | 13 ++--- src/server/game/OutdoorPvP/OutdoorPvPMgr.h | 11 +++-- src/server/game/Pools/PoolMgr.h | 11 +++-- src/server/game/Scripting/ScriptMgr.h | 10 ++-- src/server/game/Scripting/ScriptSystem.h | 11 +++-- src/server/game/Server/Protocol/PacketLog.h | 11 +++-- src/server/game/Server/WorldSession.cpp | 2 +- src/server/game/Server/WorldSocketMgr.h | 12 +++-- src/server/game/Spells/SpellMgr.h | 12 +++-- src/server/game/Texts/CreatureTextMgr.h | 14 ++++-- src/server/game/Tickets/TicketMgr.h | 11 +++-- src/server/game/Warden/WardenCheckMgr.h | 14 ++++-- src/server/game/Weather/WeatherMgr.cpp | 2 +- src/server/game/World/World.cpp | 4 +- src/server/game/World/World.h | 17 ++++--- src/server/shared/Cryptography/ARC4.h | 2 +- src/server/shared/Cryptography/BigNumber.h | 1 - src/server/shared/Database/DatabaseWorkerPool.h | 10 +--- src/server/shared/Database/MySQLConnection.h | 8 ++-- src/server/shared/Database/QueryResult.h | 8 ++-- src/server/shared/Database/Transaction.h | 2 +- src/server/shared/Debugging/Errors.cpp | 11 ++--- src/server/shared/Logging/Appender.h | 4 +- src/server/shared/Logging/AppenderConsole.h | 2 +- src/server/shared/Logging/AppenderFile.h | 2 +- src/server/shared/Threading/Callback.h | 6 +-- src/server/shared/Threading/DelayExecutor.cpp | 18 ++++++- src/server/shared/Threading/DelayExecutor.h | 2 - src/server/worldserver/Master.cpp | 55 ++++++++-------------- src/server/worldserver/Master.h | 8 +++- .../worldserver/WorldThread/WorldRunnable.cpp | 4 +- src/server/worldserver/WorldThread/WorldRunnable.h | 4 +- 61 files changed, 347 insertions(+), 243 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 3901480c70d..ad04a52c7db 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -178,7 +178,6 @@ int main(int argc, char** argv) SetProcessPriority(); - _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp index 2aa3b6ab40d..00381cb1205 100644 --- a/src/server/collision/Management/VMapManager2.cpp +++ b/src/server/collision/Management/VMapManager2.cpp @@ -26,8 +26,6 @@ #include "ModelInstance.h" #include "WorldModel.h" #include -#include -#include #include "DisableMgr.h" #include "DBCStores.h" #include "Log.h" 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 ObjectListMap; class SmartWaypointMgr { - friend class ACE_Singleton; - 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; - 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::instance() -#define sSmartWaypointMgr ACE_Singleton::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 enum AccountOpResult { @@ -51,13 +50,17 @@ typedef std::map RBACDefaultPermissionsCon class AccountMgr { - friend class ACE_Singleton; - 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::instance() +#define sAccountMgr AccountMgr::instance() #endif 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 #include "Common.h" -#include #include "DatabaseEnv.h" #include "DBCEnums.h" #include "DBCStores.h" @@ -305,11 +304,16 @@ class AchievementMgr class AchievementGlobalMgr { - friend class ACE_Singleton; 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::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 - #include "Common.h" #include "DatabaseEnv.h" #include "DBCStructure.h" @@ -137,13 +135,16 @@ class AuctionHouseObject class AuctionHouseMgr { - friend class ACE_Singleton; - private: AuctionHouseMgr(); ~AuctionHouseMgr(); public: + static AuctionHouseMgr* instance() + { + static AuctionHouseMgr* instance = new AuctionHouseMgr(); + return instance; + } typedef std::unordered_map ItemMap; @@ -193,6 +194,6 @@ class AuctionHouseMgr ItemMap mAitems; }; -#define sAuctionMgr ACE_Singleton::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 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 BattlefieldSet; typedef std::map BattlefieldMap; // contains all initiated battlefield events @@ -64,6 +67,6 @@ class BattlefieldMgr uint32 _updateTimer; }; -#define sBattlefieldMgr ACE_Singleton::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 cd9e2be4318..85372c35daa 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 #include #include 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; +private: ArenaTeamMgr(); ~ArenaTeamMgr(); public: + static ArenaTeamMgr* instance() + { + static ArenaTeamMgr* instance = new ArenaTeamMgr(); + return instance; + } + typedef std::unordered_map ArenaTeamContainer; ArenaTeam* GetArenaTeamById(uint32 arenaTeamId) const; @@ -50,6 +56,6 @@ protected: ArenaTeamContainer ArenaTeamStore; }; -#define sArenaTeamMgr ACE_Singleton::instance() +#define sArenaTeamMgr ArenaTeamMgr::instance() #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 786e664c3f3..046e2588ad3 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 typedef std::map BattlegroundContainer; typedef std::set BattlegroundClientIdsContainer; @@ -64,13 +63,17 @@ struct BattlegroundData class BattlegroundMgr { - friend class ACE_Singleton; - private: BattlegroundMgr(); ~BattlegroundMgr(); public: + static BattlegroundMgr* instance() + { + static BattlegroundMgr* instance = new BattlegroundMgr(); + return instance; + } + void Update(uint32 diff); /* Packet Building */ @@ -158,5 +161,5 @@ class BattlegroundMgr BattleMastersMap mBattleMastersMap; }; -#define sBattlegroundMgr ACE_Singleton::instance() +#define sBattlegroundMgr BattlegroundMgr::instance() #endif 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 #include "Common.h" #include "DatabaseEnv.h" #include "WorldPacket.h" @@ -268,8 +267,6 @@ typedef std::map CalendarEventInvite class CalendarMgr { - friend class ACE_Singleton; - 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::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::instance(); // cross-faction + return AllianceChannelMgr::instance(); // cross-faction if (team == ALLIANCE) - return ACE_Singleton::instance(); + return AllianceChannelMgr::instance(); if (team == HORDE) - return ACE_Singleton::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 #include #include @@ -31,12 +30,17 @@ class ChannelMgr { typedef std::map 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 #include #include @@ -223,13 +222,18 @@ typedef std::map ConditionReferenceContainer;//only used class ConditionMgr { - friend class ACE_Singleton; - 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::instance() +#define sConditionMgr ConditionMgr::instance() #endif diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 5d6c8c7aa89..ec9d2dafbd2 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 @@ -2047,12 +2047,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 #include "DBCStructure.h" #include "Field.h" #include "LFG.h" @@ -292,13 +291,17 @@ struct LFGDungeonData class LFGMgr { - friend class ACE_Singleton; - 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::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 CreatureGro class FormationMgr { - friend class ACE_Singleton; - 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::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 9733c0f2b52..f2823cc1435 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7326,7 +7326,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); @@ -7342,7 +7342,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); @@ -19769,7 +19769,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 #include "DatabaseEnv.h" #include "Common.h" @@ -123,13 +122,17 @@ class PlayerSocial class SocialMgr { - friend class ACE_Singleton; - 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::instance() +#define sSocialMgr SocialMgr::instance() #endif 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 #define max_ge_check_delay DAY // 1 day in seconds @@ -95,13 +94,17 @@ class Quest; class GameEventMgr { - friend class ACE_Singleton; - private: GameEventMgr(); ~GameEventMgr() { }; public: + static GameEventMgr* instance() + { + static GameEventMgr* instance = new GameEventMgr(); + return instance; + } + typedef std::set ActiveEvents; typedef std::vector GameEventDataMap; ActiveEvents const& GetActiveEventList() const { return m_ActiveEvents; } @@ -180,7 +183,7 @@ class GameEventMgr GameEventGuidMap mGameEventGameobjectGuids; }; -#define sGameEventMgr ACE_Singleton::instance() +#define sGameEventMgr GameEventMgr::instance() bool IsHolidayActive(HolidayIds id); bool IsEventActive(uint16 event_id); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index ba5940d7e12..20941901731 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 #include "VehicleDefines.h" #include #include @@ -687,13 +686,18 @@ class PlayerDumpReader; class ObjectMgr { friend class PlayerDumpReader; - friend class ACE_Singleton; private: ObjectMgr(); ~ObjectMgr(); public: + static ObjectMgr* instance() + { + static ObjectMgr* instance = new ObjectMgr(); + return instance; + } + typedef std::unordered_map ItemMap; typedef std::unordered_map QuestMap; @@ -1442,6 +1446,6 @@ class ObjectMgr std::set _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template }; -#define sObjectMgr ACE_Singleton::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; private: GroupMgr(); ~GroupMgr(); public: + static GroupMgr* instance() + { + static GroupMgr* instance = new GroupMgr(); + return instance; + } + typedef std::map GroupContainer; typedef std::vector GroupDbContainer; @@ -53,6 +58,6 @@ protected: GroupDbContainer GroupDbStore; }; -#define sGroupMgr ACE_Singleton::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; - 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::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 #include "WorldPacket.h" class AddonHandler { - /* Construction */ - friend class ACE_Singleton; - 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::instance() +#define sAddOnHandler AddonHandler::instance() #endif diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 91becb88dfe..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 -#include - - class Transport; struct TransportCreatureProto; class MapManager { - friend class ACE_Singleton; - 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); @@ -150,5 +150,5 @@ class MapManager uint32 _nextInstanceId; MapUpdater m_updater; }; -#define sMapMgr ACE_Singleton::instance() +#define sMapMgr MapManager::instance() #endif 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 #include #include "Spline.h" #include "DBCStores.h" @@ -96,10 +95,15 @@ typedef std::map TransportAnimationContainer; class TransportMgr { - friend class ACE_Singleton; 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::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 5c74bef8d8c..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 #include "ObjectRegistry.h" #include "FactoryHolder.h" #include "Common.h" 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 -#include #include struct WaypointData @@ -38,9 +36,13 @@ typedef std::unordered_map WaypointPathContainer; class WaypointMgr { - friend class ACE_Singleton; - 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::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 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; - 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::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 #include "Creature.h" #include "GameObject.h" #include "QuestDef.h" @@ -104,13 +103,17 @@ typedef std::pair class PoolMgr { - friend class ACE_Singleton; - 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::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/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index ee95759c72e..4f6027bedec 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -20,7 +20,6 @@ #define SC_SCRIPTMGR_H #include "Common.h" -#include #include #include "DBCStores.h" @@ -869,20 +868,23 @@ class GroupScript : public ScriptObject }; // Placed here due to ScriptRegistry::AddScript dependency. -#define sScriptMgr ACE_Singleton::instance() +#define sScriptMgr ScriptMgr::instance() // Manages registration, loading, and execution of scripts. class ScriptMgr { - friend class ACE_Singleton; friend class ScriptObject; private: - ScriptMgr(); virtual ~ScriptMgr(); public: /* Initialization */ + static ScriptMgr* instance() + { + static ScriptMgr* instance = new ScriptMgr(); + return instance; + } void Initialize(); void LoadDatabase(); 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 #define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available @@ -48,11 +47,17 @@ typedef std::vector ScriptPointVector; class SystemMgr { - friend class ACE_Singleton; + private: SystemMgr() { } ~SystemMgr() { } public: + static SystemMgr* instance() + { + static SystemMgr* instance = new SystemMgr(); + return instance; + } + typedef std::unordered_map PointMoveMap; //Database @@ -75,6 +80,6 @@ class SystemMgr static ScriptPointVector const _empty; }; -#define sScriptSystemMgr ACE_Singleton::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 enum Direction { @@ -31,13 +30,17 @@ class WorldPacket; class PacketLog { - friend class ACE_Singleton; - 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::instance() +#define sPacketLog PacketLog::instance() #endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 0c391993c0b..7fbc398a4da 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -780,7 +780,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 = !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) diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index fb8ddb42b9e..2c91a164ff9 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -26,7 +26,6 @@ #define __WORLDSOCKETMGR_H #include -#include #include class WorldSocket; @@ -36,9 +35,14 @@ class ACE_Event_Handler; /// Manages all sockets connected to peers and network threads class WorldSocketMgr { -public: friend class WorldSocket; - friend class ACE_Singleton; + +public: + static WorldSocketMgr* instance() + { + static WorldSocketMgr* instance = new WorldSocketMgr(); + return instance; + } /// Start network, listen at address:port . int StartNetwork(ACE_UINT16 port, const char* address); @@ -68,7 +72,7 @@ private: class WorldSocketAcceptor* m_Acceptor; }; -#define sWorldSocketMgr ACE_Singleton::instance() +#define sWorldSocketMgr WorldSocketMgr::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 - #include "Define.h" #include "DBCStructure.h" #include "SharedDefines.h" @@ -603,7 +601,6 @@ bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group); class SpellMgr { - friend class ACE_Singleton; // 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::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 CreatureTextRepeatMa class CreatureTextMgr { - friend class ACE_Singleton; - 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::instance() +#define sCreatureTextMgr CreatureTextMgr::instance() template 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 -#include #include "ObjectMgr.h" @@ -174,13 +173,17 @@ typedef std::map GmTicketList; class TicketMgr { - friend class ACE_Singleton; - 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::instance() +#define sTicketMgr TicketMgr::instance() #endif // _TICKETMGR_H diff --git a/src/server/game/Warden/WardenCheckMgr.h b/src/server/game/Warden/WardenCheckMgr.h index 8f2fa37400d..1108c9a6521 100644 --- a/src/server/game/Warden/WardenCheckMgr.h +++ b/src/server/game/Warden/WardenCheckMgr.h @@ -48,11 +48,17 @@ struct WardenCheckResult class WardenCheckMgr { - friend class ACE_Singleton; - 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 CheckContainer; typedef std::map CheckResultContainer; @@ -73,6 +79,6 @@ class WardenCheckMgr CheckResultContainer CheckResultStore; }; -#define sWardenCheckMgr ACE_Singleton::instance() +#define sWardenCheckMgr WardenCheckMgr::instance() #endif diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp index 5cf5cde75fd..5274dcd358d 100644 --- a/src/server/game/Weather/WeatherMgr.cpp +++ b/src/server/game/Weather/WeatherMgr.cpp @@ -34,7 +34,7 @@ namespace WeatherMgr namespace { - typedef std::unordered_map > WeatherMap; + typedef std::unordered_map > WeatherMap; typedef std::unordered_map WeatherZoneMap; WeatherMap m_weathers; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 234a366b08e..4a46412dff7 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -668,7 +668,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); @@ -1255,8 +1255,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); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 4096dd7399a..f9528c793f7 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -25,9 +25,7 @@ #include "Common.h" #include "Timer.h" -#include #include -#include #include "SharedDefines.h" #include "QueryResult.h" #include "Callback.h" @@ -156,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 +517,13 @@ struct CharacterNameData class World { public: - static ACE_Atomic_Op m_worldLoopCounter; + static World* instance() + { + static World* instance = new World(); + return instance; + } - World(); - ~World(); + static ACE_Atomic_Op m_worldLoopCounter; WorldSession* FindSession(uint32 id) const; void AddSession(WorldSession* s); @@ -758,6 +758,9 @@ class World void ResetRandomBG(); void ResetGuildCap(); private: + World(); + ~World(); + static ACE_Atomic_Op m_stopEvent; static uint8 m_ExitCode; uint32 m_ShutdownTimer; @@ -845,6 +848,6 @@ class World extern uint32 realmID; -#define sWorld ACE_Singleton::instance() +#define sWorld World::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 +#include "Define.h" class ARC4 { diff --git a/src/server/shared/Cryptography/BigNumber.h b/src/server/shared/Cryptography/BigNumber.h index 848b3da3e2d..684a25e8801 100644 --- a/src/server/shared/Cryptography/BigNumber.h +++ b/src/server/shared/Cryptography/BigNumber.h @@ -22,7 +22,6 @@ #include #include "Define.h" - struct bignum_st; class BigNumber diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index e56dcc329cd..4b9e887f341 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 - #include "Common.h" #include "Callback.h" #include "MySQLConnection.h" @@ -51,7 +49,6 @@ class DatabaseWorkerPool /* Activity state */ DatabaseWorkerPool() : _connectionInfo(NULL) { - _messageQueue = new ACE_Message_Queue(8 * 1024 * 1024, 8 * 1024 * 1024); _queue = new ProducerConsumerQueue(); memset(_connectionCount, 0, sizeof(_connectionCount)); _connections.resize(IDX_SIZE); @@ -125,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()); @@ -410,7 +405,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); @@ -420,7 +415,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); @@ -517,7 +512,6 @@ class DatabaseWorkerPool IDX_SIZE }; - ACE_Message_Queue* _messageQueue; //! Message Queue used by ACE_Activation_Queue ProducerConsumerQueue* _queue; //! Queue shared by async worker threads. std::vector< std::vector > _connections; uint32 _connectionCount[2]; //! Counter of MySQL connections; diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h index 3b7efeb5846..61b3b37cbc2 100644 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -15,8 +15,6 @@ * with this program. If not, see . */ -#include - #include "DatabaseWorkerPool.h" #include "Transaction.h" #include "Util.h" @@ -100,13 +98,13 @@ class MySQLConnection { /// Tries to acquire lock. If lock is acquired by another thread /// the calling parent will just try another connection - return m_Mutex.tryacquire() != -1; + return m_Mutex.try_lock(); } void Unlock() { /// Called by parent databasepool. Will let other threads access this connection - m_Mutex.release(); + m_Mutex.unlock(); } MYSQL* GetHandle() { return m_Mysql; } @@ -131,7 +129,7 @@ class MySQLConnection 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/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 - +#include #include "Field.h" #ifdef _WIN32 @@ -60,7 +58,7 @@ class ResultSet ResultSet& operator=(ResultSet const& right) = delete; }; -typedef Trinity::AutoPtr QueryResult; +typedef std::shared_ptr QueryResult; class PreparedResultSet { @@ -107,7 +105,7 @@ class PreparedResultSet PreparedResultSet& operator=(PreparedResultSet const& right) = delete; }; -typedef Trinity::AutoPtr PreparedQueryResult; +typedef std::shared_ptr PreparedQueryResult; #endif 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 SQLTransaction; +typedef std::shared_ptr 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 -#include #include +#include 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/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 #include #include +#include +#include "Define.h" // Values assigned have their equivalent in enum ACE_Log_Priority enum LogLevel 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 +#include "Appender.h" enum ColorTypes { diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index 592742c2184..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 "Appender.h" #include +#include "Appender.h" class AppenderFile: public Appender { diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h index a6aa11b3958..5d9dc9a760d 100644 --- a/src/server/shared/Threading/Callback.h +++ b/src/server/shared/Threading/Callback.h @@ -26,10 +26,6 @@ typedef std::promise QueryResultPromise; typedef std::future PreparedQueryResultFuture; typedef std::promise PreparedQueryResultPromise; -/*! A simple template using ACE_Future to manage callbacks from the thread and object that - issued the request. is variable type of parameter that is used as parameter - for the callback function. -*/ #define CALLBACK_STAGE_INVALID uint8(-1) template @@ -210,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 index 0db45a8ff8f..ef3c028fd97 100644 --- a/src/server/shared/Threading/DelayExecutor.cpp +++ b/src/server/shared/Threading/DelayExecutor.cpp @@ -1,4 +1,20 @@ -#include +/* +* Copyright (C) 2008-2014 TrinityCore +* +* 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 . +*/ + #include #include diff --git a/src/server/shared/Threading/DelayExecutor.h b/src/server/shared/Threading/DelayExecutor.h index 5eaaacdb98b..2a3721263fc 100644 --- a/src/server/shared/Threading/DelayExecutor.h +++ b/src/server/shared/Threading/DelayExecutor.h @@ -8,7 +8,6 @@ class DelayExecutor : protected ACE_Task_Base { public: - DelayExecutor(); virtual ~DelayExecutor(); @@ -25,7 +24,6 @@ class DelayExecutor : protected ACE_Task_Base virtual int svc(); private: - ACE_Activation_Queue queue_; ACE_Method_Request* pre_svc_hook_; ACE_Method_Request* post_svc_hook_; diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp index 2a8fcdd431a..41060e37b38 100644 --- a/src/server/worldserver/Master.cpp +++ b/src/server/worldserver/Master.cpp @@ -22,8 +22,6 @@ #include -#include - #include "Common.h" #include "SystemConfig.h" #include "SignalHandler.h" @@ -46,6 +44,7 @@ #include "BigNumber.h" #include "OpenSSLCrypto.h" +#include #ifdef _WIN32 #include "ServiceWin32.h" @@ -58,27 +57,22 @@ extern int m_ServiceStatus; #define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 #endif -/// Handle worldservers's termination signals -class WorldServerSignalHandler : public Trinity::SignalHandler +boost::asio::io_service _ioService; + +void SignalHandler(const boost::system::error_code& error, int signalNumber) { - public: - virtual void HandleSignal(int sigNum) + if (!error) + { + switch (signalNumber) { - 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; - } + case SIGINT: + case SIGTERM: + _ioService.stop(); + break; } -}; + } +} + void FreezeDetectorThread(uint32 delayTime) { @@ -153,23 +147,12 @@ int Master::Run() ///- 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 + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); + signals.async_wait(SignalHandler); ///- Launch WorldRunnable thread - - std::thread worldThread(WorldThread); + std::thread worldThread(WorldThread, std::ref(_ioService)); std::thread* cliThread = nullptr; @@ -286,6 +269,8 @@ int Master::Run() TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); + _ioService.run(); + // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master worldThread.join(); diff --git a/src/server/worldserver/Master.h b/src/server/worldserver/Master.h index 9ee94a44acb..d2a51b85f4b 100644 --- a/src/server/worldserver/Master.h +++ b/src/server/worldserver/Master.h @@ -29,6 +29,12 @@ class Master { public: + static Master* instance() + { + static Master* instance = new Master(); + return instance; + } + int Run(); private: @@ -38,7 +44,7 @@ class Master void ClearOnlineAccounts(); }; -#define sMaster ACE_Singleton::instance() +#define sMaster Master::instance() #endif diff --git a/src/server/worldserver/WorldThread/WorldRunnable.cpp b/src/server/worldserver/WorldThread/WorldRunnable.cpp index 7722492b5a8..85c3e7a74b9 100644 --- a/src/server/worldserver/WorldThread/WorldRunnable.cpp +++ b/src/server/worldserver/WorldThread/WorldRunnable.cpp @@ -42,7 +42,7 @@ extern int m_ServiceStatus; #endif /// Heartbeat for the World -void WorldThread() +void WorldThread(boost::asio::io_service& ioService) { uint32 realCurrTime = 0; uint32 realPrevTime = getMSTime(); @@ -84,6 +84,8 @@ void WorldThread() #endif } + ioService.stop(); + sScriptMgr->OnShutdown(); sWorld->KickAll(); // save and kick all players diff --git a/src/server/worldserver/WorldThread/WorldRunnable.h b/src/server/worldserver/WorldThread/WorldRunnable.h index 915bd5b580a..3e2c07b8842 100644 --- a/src/server/worldserver/WorldThread/WorldRunnable.h +++ b/src/server/worldserver/WorldThread/WorldRunnable.h @@ -23,7 +23,9 @@ #ifndef __WORLDRUNNABLE_H #define __WORLDRUNNABLE_H -void WorldThread(); +#include + +void WorldThread(boost::asio::io_service& ioService); #endif -- cgit v1.2.3 From c31c6f3ba3bd0be5e157e63bfc65d38f7d3e7624 Mon Sep 17 00:00:00 2001 From: leak Date: Wed, 2 Jul 2014 18:05:30 +0200 Subject: Backported AsyncAcceptor generalization to authserver --- src/server/authserver/CMakeLists.txt | 1 + src/server/authserver/Main.cpp | 5 ++-- src/server/authserver/Server/AuthServer.cpp | 37 ------------------------ src/server/authserver/Server/AuthServer.h | 44 ----------------------------- 4 files changed, 4 insertions(+), 83 deletions(-) delete mode 100644 src/server/authserver/Server/AuthServer.cpp delete mode 100644 src/server/authserver/Server/AuthServer.h (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index bde75654c92..d6f0515a8e1 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -50,6 +50,7 @@ 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} diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index ad04a52c7db..988ee901139 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -39,7 +39,8 @@ #include "SystemConfig.h" #include "Util.h" #include "RealmList.h" -#include "AuthServer.h" +#include "AsyncAcceptor.h" +#include "AuthSession.h" #ifdef __linux__ @@ -170,7 +171,7 @@ int main(int argc, char** argv) std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - AuthServer authServer(_ioService, bindIp, port); + AsyncAcceptor authServer(_ioService, bindIp, port); // Set signal handlers boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); diff --git a/src/server/authserver/Server/AuthServer.cpp b/src/server/authserver/Server/AuthServer.cpp deleted file mode 100644 index c5a0cff186f..00000000000 --- a/src/server/authserver/Server/AuthServer.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * - * 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 . - */ - -#include "AuthServer.h" -#include "AuthSession.h" - -#include -#include - -using boost::asio::ip::tcp; - -void AuthServer::AsyncAccept() -{ - _acceptor.async_accept(_socket, [this](boost::system::error_code error) - { - if (!error) - { - std::make_shared(std::move(_socket))->Start(); - } - - AsyncAccept(); - }); -} diff --git a/src/server/authserver/Server/AuthServer.h b/src/server/authserver/Server/AuthServer.h deleted file mode 100644 index 985a48ad243..00000000000 --- a/src/server/authserver/Server/AuthServer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * - * 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 . - */ - -#ifndef __AUTHSERVER_H__ -#define __AUTHSERVER_H__ - -#include - -using boost::asio::ip::tcp; - -class AuthServer -{ -public: - AuthServer(boost::asio::io_service& ioService, std::string bindIp, int port) : _socket(ioService), _acceptor(ioService, tcp::endpoint(tcp::v4(), port)) - { - tcp::endpoint endpoint(boost::asio::ip::address::from_string(bindIp), port); - - _acceptor = tcp::acceptor(ioService, endpoint); - - AsyncAccept(); - }; - -private: - void AsyncAccept(); - - tcp::acceptor _acceptor; - tcp::socket _socket; -}; - -#endif /* __AUTHSERVER_H__ */ -- cgit v1.2.3 From 2874014443cff95e34a75ffa3bfe816ed7143803 Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 2 Jul 2014 11:50:03 -0500 Subject: Cleaned up the authserver includes a bit. Fixed authserver pch build --- src/server/authserver/Main.cpp | 2 -- src/server/authserver/PrecompiledHeaders/authPCH.h | 1 - src/server/authserver/Realms/RealmList.cpp | 1 - src/server/authserver/Realms/RealmList.h | 2 +- src/server/authserver/Server/AuthSession.cpp | 2 +- src/server/authserver/Server/AuthSession.h | 2 +- src/server/worldserver/WorldThread/WorldRunnable.h | 2 +- 7 files changed, 4 insertions(+), 8 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 988ee901139..1fdd01ad968 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include "Common.h" diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 61059ae91b0..ef757a656d5 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -3,5 +3,4 @@ #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "AuthServer.h" #include "AuthSession.h" diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 94d52fb3138..bf097abff9a 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,7 +16,6 @@ * with this program. If not, see . */ -#include #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index b96d5523da9..e8e94376c20 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,7 +19,7 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include +#include #include "Common.h" using namespace boost::asio; diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index ba31573cb4e..6646f1203b5 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -17,8 +17,8 @@ */ #include -#include #include +#include #include #include #include "ByteBuffer.h" diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 32e81d5240e..3aef4262786 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -20,7 +20,7 @@ #define __AUTHSESSION_H__ #include -#include +#include #include "Common.h" #include "BigNumber.h" diff --git a/src/server/worldserver/WorldThread/WorldRunnable.h b/src/server/worldserver/WorldThread/WorldRunnable.h index 3e2c07b8842..c6d00d269e7 100644 --- a/src/server/worldserver/WorldThread/WorldRunnable.h +++ b/src/server/worldserver/WorldThread/WorldRunnable.h @@ -23,7 +23,7 @@ #ifndef __WORLDRUNNABLE_H #define __WORLDRUNNABLE_H -#include +#include void WorldThread(boost::asio::io_service& ioService); -- cgit v1.2.3 From 021e18d152b68b9d2a0c5887bab7eb7b61ecd2ca Mon Sep 17 00:00:00 2001 From: leak Date: Fri, 4 Jul 2014 15:22:06 +0200 Subject: Refactored both world and auth main - Master/Worldrunable removed - World Update loop now running on main (which was doing nothing before) - Processpriority moved to shared - Added a preliminary thread pool for boost::asio::io_service --- src/server/authserver/Main.cpp | 160 ++----- src/server/shared/Threading/ProcessPriority.h | 100 +++++ src/server/worldserver/CMakeLists.txt | 3 - src/server/worldserver/Main.cpp | 487 +++++++++++++++++++-- src/server/worldserver/Master.cpp | 479 -------------------- src/server/worldserver/Master.h | 57 --- .../worldserver/WorldThread/WorldRunnable.cpp | 103 ----- src/server/worldserver/WorldThread/WorldRunnable.h | 32 -- src/server/worldserver/worldserver.conf.dist | 23 +- 9 files changed, 616 insertions(+), 828 deletions(-) create mode 100644 src/server/shared/Threading/ProcessPriority.h delete mode 100644 src/server/worldserver/Master.cpp delete mode 100644 src/server/worldserver/Master.h delete mode 100644 src/server/worldserver/WorldThread/WorldRunnable.cpp delete mode 100644 src/server/worldserver/WorldThread/WorldRunnable.h (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 4e39ae0aca1..c7f71edbd0c 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -24,28 +24,24 @@ * authentication server */ -#include -#include -#include #include #include +#include +#include +#include +#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 "RealmList.h" -#include "AsyncAcceptor.h" -#include "AuthSession.h" - -#ifdef __linux__ -#include -#include -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif +using boost::asio::ip::tcp; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" @@ -53,51 +49,15 @@ bool StartDB(); void StopDB(); -void SetProcessPriority(); +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void KeepDatabaseAliveHandler(const boost::system::error_code& error); +void usage(const char* prog); boost::asio::io_service _ioService; boost::asio::deadline_timer _dbPingTimer(_ioService); uint32 _dbPingInterval; +LoginDatabaseWorkerPool LoginDatabase; -LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database - -using boost::asio::ip::tcp; - - -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)); - } -} - -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - TC_LOG_INFO("server.authserver", "Usage: \n %s []\n" - " -c config_file use config_file as configuration file\n\r", - prog); -} - -/// Launch the auth server int main(int argc, char** argv) { // Command line parsing to get the configuration file name @@ -129,7 +89,6 @@ int main(int argc, char** argv) TC_LOG_INFO("server.authserver", "%s (authserver)", _FULLVERSION); TC_LOG_INFO("server.authserver", " 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)); // authserver PID file creation @@ -158,31 +117,30 @@ int main(int argc, char** argv) return 1; } - // Launch the listening network socket - + // 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 authServer(_ioService, bindIp, port); // Set signal handlers boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); signals.async_wait(SignalHandler); - SetProcessPriority(); + // Set process priority according to configuration settings + SetProcessPriority("server.authserver"); + // Enabled a timed callback for handling the database keep alive ping _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); _dbPingTimer.async_wait(KeepDatabaseAliveHandler); - // Start the io service + // Start the io service worker loop _ioService.run(); // Close the Database Pool and library @@ -238,73 +196,35 @@ void StopDB() MySQL::Library_End(); } -void SetProcessPriority() +void SignalHandler(const boost::system::error_code& error, int signalNumber) { -#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) + if (!error) { - ULONG_PTR appAff; - ULONG_PTR sysAff; - - if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) + switch (signalNumber) { - // 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); + case SIGINT: + case SIGTERM: + _ioService.stop(); + break; } } +} - 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) +void KeepDatabaseAliveHandler(const boost::system::error_code& error) +{ + if (!error) { - 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)); - } - } + TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + LoginDatabase.KeepAlive(); - 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)); + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); } +} -#endif -#endif +/// Print out the usage string for this program on the console. +void usage(const char* prog) +{ + TC_LOG_INFO("server.authserver", "Usage: \n %s []\n" + " -c config_file use config_file as configuration file\n\r", + prog); } 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 +* +* 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 . +*/ + +#ifndef _PROCESSPRIO_H +#define _PROCESSPRIO_H + +#include "Configuration/Config.h" + +#ifdef __linux__ +#include +#include +#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/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 9d2e859a7de..b7a158ab3ce 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} ) @@ -138,7 +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} diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index bcc058c7fb3..0fc2c1a7221 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -22,17 +22,30 @@ #include #include +#include #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 "WorldSocketMgr.h" +#include "OutdoorPvP/OutdoorPvPMgr.h" +#include "BattlegroundMgr.h" +#include "TCSoap.h" +#include "CliRunnable.h" +#include "SystemConfig.h" -#include "Log.h" -#include "Master.h" - -#ifndef _TRINITY_CORE_CONFIG -# define _TRINITY_CORE_CONFIG "worldserver.conf" -#endif +#define TRINITY_CORE_CONFIG "worldserver.conf" +#define WORLD_SLEEP_CONST 50 #ifdef _WIN32 #include "ServiceWin32.h" @@ -48,31 +61,26 @@ char serviceDescription[] = "TrinityCore World of Warcraft emulator world servic int m_ServiceStatus = -1; #endif +boost::asio::io_service _ioService; 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 []\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 usage(const char* prog); +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void FreezeDetectorThread(uint32 delayTime); +AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService); +bool StartDB(); +void StopDB(); +void WorldUpdateLoop(); +void ClearOnlineAccounts(); /// 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; + char const* cfg_file = TRINITY_CORE_CONFIG; int c = 1; while (c < argc) { @@ -131,21 +139,442 @@ extern int main(int argc, char** argv) return 1; } + TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); + TC_LOG_INFO("server.worldserver", " 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.", cfg_file); - 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: %s", BOOST_LIB_VERSION); + TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); + + OpenSSLCrypto::threadsSetup(); + BigNumber seed1; + seed1.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); + + // Start the Boost based thread pool + int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1); + std::vector 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* 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))); + } + + // Start up freeze catcher thread + std::thread* freezeDetectorThread = nullptr; + if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) + freezeDetectorThread = new std::thread(FreezeDetectorThread, freezeDelay); + + // Launch the worldserver 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"); + return ERROR_EXIT_CODE; + } - ///- 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(); + // 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); + + sScriptMgr->OnStartup(); + + 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(); + + 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(); + + // 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; + } + + delete freezeDetectorThread; + + 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 + } +} + +/// Print out the usage string for this program on the console. +void usage(const char* prog) +{ + printf("Usage:\n"); + printf(" %s []\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) +{ + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + World::StopNow(SHUTDOWN_EXIT_CODE); + break; + } + } +} + +void FreezeDetectorThread(uint32 delayTime) +{ + if (!delayTime) + return; + + TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", delayTime / 1000); + uint32 loops = 0; + uint32 lastChange = 0; + + while (!World::IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + uint32 curtime = getMSTime(); + // normal work + uint32 worldLoopCounter = World::m_worldLoopCounter; + 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."); +} + +AsyncAcceptor* 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(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"); } /// @} diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp deleted file mode 100644 index c529e6b6478..00000000000 --- a/src/server/worldserver/Master.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -/** \file - \ingroup Trinityd -*/ - -#include - -#include "Master.h" - -#include "SystemConfig.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 "TCSoap.h" -#include "Timer.h" -#include "Util.h" -#include "RealmList.h" -#include "BigNumber.h" -#include "OpenSSLCrypto.h" -#include "AsyncAcceptor.h" - -#ifdef _WIN32 -#include "ServiceWin32.h" -extern int m_ServiceStatus; -#endif - -#ifdef __linux__ -#include -#include -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif - -boost::asio::io_service _ioService; - -void SignalHandler(const boost::system::error_code& error, int signalNumber) -{ - if (!error) - { - switch (signalNumber) - { - case SIGINT: - case SIGTERM: - _ioService.stop(); - break; - } - } -} - - -void FreezeDetectorThread(uint32 delayTime) -{ - if (!delayTime) - return; - - TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", delayTime / 1000); - uint32 loops = 0; - uint32 lastChange = 0; - - while (!World::IsStopped()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - uint32 curtime = getMSTime(); - // normal work - uint32 worldLoopCounter = World::m_worldLoopCounter; - 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", " 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(); - - // Set signal handlers - boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); - signals.async_wait(SignalHandler); - - ///- Launch WorldRunnable thread - std::thread worldThread(WorldThread, std::ref(_ioService)); - - 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 - { - ///- Launch CliRunnable thread - cliThread = new std::thread(CliThread); - } - - AsyncAcceptor* raAcceptor = nullptr; - - if (sConfigMgr->GetBoolDefault("Ra.Enable", false)) - raAcceptor = StartRaSocketAcceptor(_ioService); - -#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 - 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))); - } - - std::thread* freezeDetectorThread = nullptr; - - ///- Start up freeze catcher thread - if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) - freezeDetectorThread = new std::thread(FreezeDetectorThread, freezeDelay); - - ///- 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); - - _ioService.run(); - - // when the main thread closes the singletons get unloaded - // since worldrunnable uses them, it will crash if unloaded after master - worldThread.join(); - - if (soapThread != nullptr) - { - soapThread->join(); - delete soapThread; - } - - if (raAcceptor != nullptr) - delete raAcceptor; - - // 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 != 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; - } - - delete freezeDetectorThread; - - // 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"); -} - -AsyncAcceptor* Master::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(ioService, raListener, raPort); -} diff --git a/src/server/worldserver/Master.h b/src/server/worldserver/Master.h deleted file mode 100644 index 86059e6417a..00000000000 --- a/src/server/worldserver/Master.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef _MASTER_H -#define _MASTER_H - -#include -#include "Common.h" -#include "RASession.h" - -template -class AsyncAcceptor; - -/// Start the server -class Master -{ - public: - static Master* instance() - { - static Master* instance = new Master(); - return instance; - } - - int Run(); - - private: - bool _StartDB(); - void _StopDB(); - - void ClearOnlineAccounts(); - AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService); -}; - -#define sMaster Master::instance() - -#endif - -/// @} diff --git a/src/server/worldserver/WorldThread/WorldRunnable.cpp b/src/server/worldserver/WorldThread/WorldRunnable.cpp deleted file mode 100644 index 85c3e7a74b9..00000000000 --- a/src/server/worldserver/WorldThread/WorldRunnable.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -/** \file - \ingroup Trinityd -*/ - -#include - -#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 WorldThread(boost::asio::io_service& ioService) -{ - 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; - - 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 - } - - ioService.stop(); - - 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 c6d00d269e7..00000000000 --- a/src/server/worldserver/WorldThread/WorldRunnable.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore - * Copyright (C) 2005-2009 MaNGOS - * - * 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 . - */ - -/// \addtogroup Trinityd -/// @{ -/// \file - -#ifndef __WORLDRUNNABLE_H -#define __WORLDRUNNABLE_H - -#include - -void WorldThread(boost::asio::io_service& ioService); - -#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 @@ -143,6 +143,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) -- cgit v1.2.3 From 59c8ffe4b3fec5979926d991c17cae84b41e46e2 Mon Sep 17 00:00:00 2001 From: leak Date: Sun, 6 Jul 2014 23:04:38 +0200 Subject: Change the freeze detector thread to be a periodic callback running on the thread pool --- src/server/authserver/Main.cpp | 3 ++- src/server/worldserver/Main.cpp | 48 ++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 23 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index c7f71edbd0c..39ad4b60dfe 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -137,7 +137,7 @@ int main(int argc, char** argv) // Enabled a timed callback for handling the database keep alive ping _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - _dbPingTimer.expires_from_now(boost::posix_time::seconds(_dbPingInterval)); + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); _dbPingTimer.async_wait(KeepDatabaseAliveHandler); // Start the io service worker loop @@ -218,6 +218,7 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) LoginDatabase.KeepAlive(); _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); } } diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 7ac60c631b3..db49d2492c0 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "Common.h" #include "DatabaseEnv.h" @@ -62,6 +63,11 @@ int m_ServiceStatus = -1; #endif boost::asio::io_service _ioService; +boost::asio::deadline_timer _freezeCheckTimer(_ioService); +uint32 _worldLoopCounter(0); +uint32 _lastChangeMsTime(0); +uint32 _maxCoreStuckTime(0); + WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database @@ -69,7 +75,7 @@ uint32 realmID; ///< Id of the realm void usage(const char* prog); void SignalHandler(const boost::system::error_code& error, int signalNumber); -void FreezeDetectorThread(uint32 delayTime); +void FreezeDetectorHandler(const boost::system::error_code& error); AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService); bool StartDB(); void StopDB(); @@ -219,11 +225,6 @@ extern int main(int argc, char** argv) soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); } - // Start up freeze catcher thread - std::thread* freezeDetectorThread = nullptr; - if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) - freezeDetectorThread = new std::thread(FreezeDetectorThread, freezeDelay); - // Launch the worldserver listener socket uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); @@ -235,6 +236,15 @@ extern int main(int argc, char** argv) // 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) + std::thread* freezeDetectorThread = nullptr; + if (_maxCoreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) + { + _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)...", _maxCoreStuckTime); + } + TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); WorldUpdateLoop(); @@ -408,34 +418,28 @@ void SignalHandler(const boost::system::error_code& error, int signalNumber) } } -void FreezeDetectorThread(uint32 delayTime) +void FreezeDetectorHandler(const boost::system::error_code& error) { - if (!delayTime) - return; - - TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", delayTime / 1000); - uint32 loops = 0; - uint32 lastChange = 0; - - while (!World::IsStopped()) + if (!error) { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); uint32 curtime = getMSTime(); - // normal work + uint32 worldLoopCounter = World::m_worldLoopCounter; - if (loops != worldLoopCounter) + if (_worldLoopCounter != worldLoopCounter) { - lastChange = curtime; - loops = worldLoopCounter; + _lastChangeMsTime = curtime; + _worldLoopCounter = worldLoopCounter; } // possible freeze - else if (getMSTimeDiff(lastChange, curtime) > delayTime) + else if (getMSTimeDiff(_lastChangeMsTime, curtime) > _maxCoreStuckTime) { 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); } - TC_LOG_INFO("server.worldserver", "Anti-freeze thread exiting without problems."); } AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService) -- cgit v1.2.3 From 110396447f2f414f8834c1b86c764d97704537b7 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 7 Jul 2014 14:25:17 -0500 Subject: Fixed the authserver not accepting clients. Fixed using hostnames in the realmlist table. --- src/server/authserver/Main.cpp | 2 +- src/server/authserver/Realms/RealmList.cpp | 45 ++++++++++++++++++++++++---- src/server/authserver/Realms/RealmList.h | 7 ++++- src/server/authserver/Server/AuthSession.cpp | 7 ++--- 4 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 39ad4b60dfe..1286e261a47 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -109,7 +109,7 @@ int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList.Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + sRealmList.Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 392d86b5621..4dd2ab96dd9 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,17 +16,23 @@ * with this program. If not, see . */ +#include #include "Common.h" #include "RealmList.h" #include "Database/DatabaseEnv.h" namespace boost { namespace asio { namespace ip { class address; } } } -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { } +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 @@ -85,12 +91,41 @@ void RealmList::UpdateRealms(bool init) { try { + boost::asio::ip::tcp::resolver::iterator end; + Field* fields = result->Fetch(); uint32 realmId = fields[0].GetUInt32(); std::string name = fields[1].GetString(); - ip::address externalAddress = ip::address::from_string(fields[2].GetString()); - ip::address localAddress = ip::address::from_string(fields[3].GetString()); - ip::address localSubmask = ip::address::from_string(fields[4].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()); diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index e8e94376c20..b1c77d5a4b5 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -20,6 +20,8 @@ #define _REALMLIST_H #include +#include +#include #include "Common.h" using namespace boost::asio; @@ -65,8 +67,10 @@ public: static RealmList *instance = new RealmList(); return *instance; } + + ~RealmList(); - void Initialize(uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); void UpdateIfNeed(); @@ -86,6 +90,7 @@ private: RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; + boost::asio::ip::tcp::resolver* _resolver; }; #define sRealmList RealmList::instance() diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index df90339222d..f518dc7593b 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include "ByteBuffer.h" @@ -137,7 +136,7 @@ void AuthSession::AsyncReadHeader() { auto self(shared_from_this()); - boost::asio::async_read(_socket, boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes == 1) { @@ -148,7 +147,7 @@ void AuthSession::AsyncReadHeader() // Handle dynamic size packet if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) { - boost::asio::read(_socket, boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size AsyncReadData(entry.handler, *reinterpret_cast(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size } @@ -171,7 +170,7 @@ void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, { auto self(shared_from_this()); - boost::asio::async_read(_socket, boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) { if (!error && transferedBytes > 0) { -- cgit v1.2.3 From 68398a559e2264b85d8765949989f44e39ce364d Mon Sep 17 00:00:00 2001 From: Chaplain Date: Tue, 15 Jul 2014 17:46:09 +0200 Subject: [Auth\Worldserver] Use boost to load console arguments. (Added a few style changes and cmake fix) Conflicts: src/server/worldserver/Main.cpp --- cmake/macros/ConfigureBoost.cmake | 2 +- src/server/authserver/Main.cpp | 60 ++++++++------ src/server/shared/Configuration/Config.cpp | 12 ++- src/server/shared/Configuration/Config.h | 10 +-- src/server/shared/Utilities/ServiceWin32.cpp | 6 +- src/server/worldserver/Main.cpp | 118 ++++++++++++--------------- 6 files changed, 101 insertions(+), 107 deletions(-) (limited to 'src/server/authserver/Main.cpp') diff --git a/cmake/macros/ConfigureBoost.cmake b/cmake/macros/ConfigureBoost.cmake index a06b1949964..aa64414afb7 100644 --- a/cmake/macros/ConfigureBoost.cmake +++ b/cmake/macros/ConfigureBoost.cmake @@ -27,7 +27,7 @@ if(WIN32) add_definitions(-D_WIN32_WINNT=${ver}) endif() -find_package(Boost 1.49 REQUIRED system thread) +find_package(Boost 1.49 REQUIRED system thread program_options) add_definitions(-DBOOST_DATE_TIME_NO_LIB) add_definitions(-DBOOST_REGEX_NO_LIB) add_definitions(-DBOOST_CHRONO_NO_LIB) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 1286e261a47..701f65c0c14 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include "Util.h" using boost::asio::ip::tcp; +using namespace boost::program_options; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" @@ -51,7 +53,7 @@ bool StartDB(); void StopDB(); void SignalHandler(const boost::system::error_code& error, int signalNumber); void KeepDatabaseAliveHandler(const boost::system::error_code& error); -void usage(const char* prog); +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); boost::asio::io_service _ioService; boost::asio::deadline_timer _dbPingTimer(_ioService); @@ -60,36 +62,24 @@ LoginDatabaseWorkerPool LoginDatabase; 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", " 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)); + 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", ""); @@ -222,10 +212,26 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) } } -/// Print out the usage string for this program on the console. -void usage(const char* prog) +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile) { - TC_LOG_INFO("server.authserver", "Usage: \n %s []\n" - " -c config_file use config_file as configuration file\n\r", - prog); + options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("config,c", value(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use 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/shared/Configuration/Config.cpp b/src/server/shared/Configuration/Config.cpp index fe61cde5594..5cd7ef52f82 100644 --- a/src/server/shared/Configuration/Config.cpp +++ b/src/server/shared/Configuration/Config.cpp @@ -25,10 +25,8 @@ using namespace boost::property_tree; -bool ConfigMgr::LoadInitial(char const* file) +bool ConfigMgr::LoadInitial(std::string const& file) { - ASSERT(file); - std::lock_guard lock(_configLock); _filename = file; @@ -57,7 +55,7 @@ bool ConfigMgr::Reload() return LoadInitial(_filename.c_str()); } -std::string ConfigMgr::GetStringDefault(const char* name, const std::string& def) +std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) { std::string value = _config.get(ptree::path_type(name, '/'), def); @@ -66,7 +64,7 @@ std::string ConfigMgr::GetStringDefault(const char* name, const std::string& def return value; } -bool ConfigMgr::GetBoolDefault(const char* name, bool def) +bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) { try { @@ -80,12 +78,12 @@ bool ConfigMgr::GetBoolDefault(const char* name, bool def) } } -int ConfigMgr::GetIntDefault(const char* name, int def) +int ConfigMgr::GetIntDefault(std::string const& name, int def) { return _config.get(ptree::path_type(name, '/'), def); } -float ConfigMgr::GetFloatDefault(const char* name, float def) +float ConfigMgr::GetFloatDefault(std::string const& name, float def) { return _config.get(ptree::path_type(name, '/'), def); } diff --git a/src/server/shared/Configuration/Config.h b/src/server/shared/Configuration/Config.h index d05a083d166..68daca5440f 100644 --- a/src/server/shared/Configuration/Config.h +++ b/src/server/shared/Configuration/Config.h @@ -31,7 +31,7 @@ class 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); static ConfigMgr* instance() { @@ -41,10 +41,10 @@ public: 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 GetKeysByString(std::string const& name); 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/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 967a31579fa..c28adbc7c21 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "Common.h" #include "DatabaseEnv.h" @@ -45,6 +46,8 @@ #include "SystemConfig.h" #include "WorldSocket.h" +using namespace boost::program_options; + #ifndef _TRINITY_CORE_CONFIG #define _TRINITY_CORE_CONFIG "worldserver.conf" #endif @@ -76,7 +79,6 @@ CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database uint32 realmID; ///< Id of the realm -void usage(const char* prog); void SignalHandler(const boost::system::error_code& error, int signalNumber); void FreezeDetectorHandler(const boost::system::error_code& error); AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService); @@ -84,66 +86,32 @@ 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; } @@ -165,7 +133,7 @@ extern int main(int argc, char** argv) 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.", cfg_file); + 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 Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); @@ -403,20 +371,6 @@ void WorldUpdateLoop() } } -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - printf("Usage:\n"); - printf(" %s []\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) { if (!error) @@ -587,3 +541,35 @@ void ClearOnlineAccounts() } /// @} + +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(&configFile)->default_value(_TRINITY_CORE_CONFIG), "use as configuration file") + ; +#ifdef _WIN32 + options_description win("Windows platform specific options"); + win.add_options() + ("service,s", value(&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; +} -- cgit v1.2.3