diff options
| author | Shauren <shauren.trinity@gmail.com> | 2014-07-19 03:38:57 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2014-07-19 03:51:11 +0200 |
| commit | 909acdbac3223d8c788b1b5dc42b6dfab8b604ab (patch) | |
| tree | 2a0ade312aad77ca032015c6957a4a9005aa0b94 /src/server/authserver | |
| parent | 5daf3d360686ea8ff2d97a48fca24f0bf42ef098 (diff) | |
| parent | 1866d8cc06e2b8c2722ccf69ee3f52ceda93bc27 (diff) | |
Merge remote-tracking branch 'origin/master' into 4.3.4
Conflicts:
src/server/authserver/Main.cpp
src/server/authserver/Realms/RealmList.cpp
src/server/authserver/Realms/RealmList.h
src/server/authserver/Server/AuthSession.cpp
src/server/authserver/Server/AuthSocket.h
src/server/authserver/Server/RealmAcceptor.h
src/server/game/Accounts/AccountMgr.h
src/server/game/Achievements/AchievementMgr.cpp
src/server/game/Achievements/AchievementMgr.h
src/server/game/Battlegrounds/ArenaTeamMgr.cpp
src/server/game/Conditions/ConditionMgr.cpp
src/server/game/DungeonFinding/LFGMgr.h
src/server/game/Entities/Object/Object.h
src/server/game/Entities/Player/Player.cpp
src/server/game/Entities/Player/Player.h
src/server/game/Entities/Unit/Unit.cpp
src/server/game/Handlers/BattleGroundHandler.cpp
src/server/game/Movement/Spline/MoveSplineFlag.h
src/server/game/Quests/QuestDef.cpp
src/server/game/Quests/QuestDef.h
src/server/game/Server/WorldSession.cpp
src/server/game/Server/WorldSession.h
src/server/game/Server/WorldSocket.cpp
src/server/game/Server/WorldSocket.h
src/server/game/Spells/Spell.cpp
src/server/scripts/Commands/cs_debug.cpp
src/server/scripts/OutdoorPvP/OutdoorPvPEP.cpp
src/server/scripts/Spells/spell_mage.cpp
src/server/scripts/Spells/spell_rogue.cpp
src/server/scripts/Spells/spell_shaman.cpp
src/server/scripts/Spells/spell_warrior.cpp
src/server/shared/Cryptography/BigNumber.h
src/server/worldserver/RemoteAccess/RASocket.cpp
src/server/worldserver/worldserver.conf.dist
Diffstat (limited to 'src/server/authserver')
| -rw-r--r-- | src/server/authserver/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/server/authserver/Main.cpp | 288 | ||||
| -rw-r--r-- | src/server/authserver/PrecompiledHeaders/authPCH.h | 4 | ||||
| -rw-r--r-- | src/server/authserver/Realms/RealmList.cpp | 100 | ||||
| -rw-r--r-- | src/server/authserver/Realms/RealmList.h | 54 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.cpp (renamed from src/server/authserver/Server/AuthSocket.cpp) | 770 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.h | 84 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSocket.h | 81 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmAcceptor.h | 72 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmSocket.cpp | 291 | ||||
| -rw-r--r-- | src/server/authserver/Server/RealmSocket.h | 80 |
11 files changed, 552 insertions, 1276 deletions
diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index 4391ac0450a..d6f0515a8e1 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -50,13 +50,13 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication ${CMAKE_SOURCE_DIR}/src/server/shared/Logging + ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Authentication ${CMAKE_CURRENT_SOURCE_DIR}/Realms ${CMAKE_CURRENT_SOURCE_DIR}/Server - ${ACE_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ) @@ -79,7 +79,7 @@ target_link_libraries(authserver ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - ${ACE_LIBRARY} + ${Boost_LIBRARIES} ) if( WIN32 ) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 2daf01c2fc8..732ed58a19c 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -24,28 +24,26 @@ * authentication server */ -#include <ace/Dev_Poll_Reactor.h> -#include <ace/TP_Reactor.h> -#include <ace/ACE.h> -#include <ace/Sig_Handler.h> +#include <cstdlib> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/program_options.hpp> +#include <iostream> #include <openssl/opensslv.h> #include <openssl/crypto.h> +#include "AsyncAcceptor.h" +#include "AuthSession.h" #include "Common.h" -#include "Database/DatabaseEnv.h" #include "Configuration/Config.h" +#include "Database/DatabaseEnv.h" #include "Log.h" +#include "ProcessPriority.h" +#include "RealmList.h" #include "SystemConfig.h" #include "Util.h" -#include "SignalHandler.h" -#include "RealmList.h" -#include "RealmAcceptor.h" -#ifdef __linux__ -#include <sched.h> -#include <sys/resource.h> -#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0 -#endif +using boost::asio::ip::tcp; +using namespace boost::program_options; #ifndef _TRINITY_REALM_CONFIG # define _TRINITY_REALM_CONFIG "authserver.conf" @@ -53,77 +51,35 @@ bool StartDB(); void StopDB(); +void SignalHandler(const boost::system::error_code& error, int signalNumber); +void KeepDatabaseAliveHandler(const boost::system::error_code& error); +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); -bool stopEvent = false; // Setting it to true stops the server - -LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database +boost::asio::io_service _ioService; +boost::asio::deadline_timer _dbPingTimer(_ioService); +uint32 _dbPingInterval; +LoginDatabaseWorkerPool LoginDatabase; -/// Handle authserver's termination signals -class AuthServerSignalHandler : public Trinity::SignalHandler +int main(int argc, char** argv) { -public: - virtual void HandleSignal(int sigNum) - { - switch (sigNum) - { - case SIGINT: - case SIGTERM: - stopEvent = true; - break; - } - } -}; - -/// Print out the usage string for this program on the console. -void usage(const char* prog) -{ - TC_LOG_INFO("server.authserver", "Usage: \n %s [<options>]\n" - " -c config_file use config_file as configuration file\n\r", - prog); -} - -/// Launch the auth server -extern int main(int argc, char** argv) -{ - // Command line parsing to get the configuration file name - char const* configFile = _TRINITY_REALM_CONFIG; - int count = 1; - while (count < argc) - { - if (strcmp(argv[count], "-c") == 0) - { - if (++count >= argc) - { - printf("Runtime-Error: -c option requires an input argument\n"); - usage(argv[0]); - return 1; - } - else - configFile = argv[count]; - } - ++count; - } + std::string configFile = _TRINITY_REALM_CONFIG; + auto vm = GetConsoleArguments(argc, argv, configFile); + // exit if help is enabled + if (vm.count("help")) + return 0; if (!sConfigMgr->LoadInitial(configFile)) { - printf("Invalid or missing configuration file : %s\n", configFile); + printf("Invalid or missing configuration file : %s\n", configFile.c_str()); printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n"); return 1; } TC_LOG_INFO("server.authserver", "%s (authserver)", _FULLVERSION); TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n"); - TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile); - - TC_LOG_INFO("server.authserver", "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); - -#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) - ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); -#else - ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); -#endif - - TC_LOG_DEBUG("server.authserver", "Max allowed open files is %d", ACE::max_handles()); + TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile.c_str()); + TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); // authserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); @@ -143,139 +99,42 @@ extern int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - if (sRealmList->size() == 0) + sRealmList.Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + + if (sRealmList.size() == 0) { TC_LOG_ERROR("server.authserver", "No valid realms specified."); return 1; } - // Launch the listening network socket - RealmAcceptor<AuthSocket> acceptor; - RealmAcceptor<Battlenet::Socket> bnetacceptor; - - int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); - if (rmport < 0 || rmport > 0xFFFF) + // Start the listening port (acceptor) for auth connections + int32 port = sConfigMgr->GetIntDefault("RealmServerPort", 3724); + if (port < 0 || port > 0xFFFF) { TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)"); return 1; } - std::string bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); - - ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str()); - - if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) - { - TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); - return 1; - } - - bind_addr.set_port_number(1119); - if (bnetacceptor.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(), 1119); - return 1; - } - - // Initialize the signal handlers - AuthServerSignalHandler SignalINT, SignalTERM; + std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + AsyncAcceptor<AuthSession> authServer(_ioService, bindIp, port); + AsyncAcceptor<Battlenet::Socket> bnetServer(_ioService, bindIp, 1119); - // Register authservers's signal handlers - ACE_Sig_Handler Handler; - Handler.register_handler(SIGINT, &SignalINT); - Handler.register_handler(SIGTERM, &SignalTERM); + // 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."); - } + // Set process priority according to configuration settings + SetProcessPriority("server.authserver"); -#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 + // Enabled a timed callback for handling the database keep alive ping + _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); sBattlenetMgr->Load(); - // 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; - - if ((++loopCounter) == numLoops) - { - loopCounter = 0; - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); - LoginDatabase.KeepAlive(); - } - } + // Start the io service worker loop + _ioService.run(); // Close the Database Pool and library StopDB(); @@ -284,6 +143,7 @@ extern int main(int argc, char** argv) return 0; } + /// Initialize connection to the database bool StartDB() { @@ -328,3 +188,53 @@ void StopDB() LoginDatabase.Close(); MySQL::Library_End(); } + +void SignalHandler(const boost::system::error_code& error, int signalNumber) +{ + if (!error) + { + switch (signalNumber) + { + case SIGINT: + case SIGTERM: + _ioService.stop(); + break; + } + } +} + +void KeepDatabaseAliveHandler(const boost::system::error_code& error) +{ + if (!error) + { + TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + LoginDatabase.KeepAlive(); + + _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); + _dbPingTimer.async_wait(KeepDatabaseAliveHandler); + } +} + +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile) +{ + options_description all("Allowed options"); + all.add_options() + ("help,h", "print usage message") + ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_REALM_CONFIG), "use <arg> as configuration file") + ; + variables_map variablesMap; + try + { + store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap); + notify(variablesMap); + } + catch (std::exception& e) { + std::cerr << e.what() << "\n"; + } + + if (variablesMap.count("help")) { + std::cout << all << "\n"; + } + + return variablesMap; +} diff --git a/src/server/authserver/PrecompiledHeaders/authPCH.h b/src/server/authserver/PrecompiledHeaders/authPCH.h index 5fc3b0a3416..ef757a656d5 100644 --- a/src/server/authserver/PrecompiledHeaders/authPCH.h +++ b/src/server/authserver/PrecompiledHeaders/authPCH.h @@ -1,6 +1,6 @@ +#include "Common.h" #include "Configuration/Config.h" #include "Database/DatabaseEnv.h" #include "Log.h" #include "RealmList.h" -#include "RealmSocket.h" -#include "Common.h" +#include "AuthSession.h" diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 48b7a178c2d..181bee31185 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -16,12 +16,14 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <boost/asio/ip/tcp.hpp> #include "Common.h" #include "RealmList.h" #include "BattlenetManager.h" #include "Database/DatabaseEnv.h" #include "Util.h" +namespace boost { namespace asio { namespace ip { class address; } } } ACE_INET_Addr const& Realm::GetAddressForClient(ACE_INET_Addr const& clientAddr) const { // Attempt to send best address for client @@ -42,16 +44,24 @@ 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 UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -62,12 +72,14 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co realm.flag = flag; realm.timezone = timezone; realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = popu; + realm.populationLevel = population; // Append port to IP address. + realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; + realm.port = port; realm.gamebuild = build; realm.Region = region; realm.Battlegroup = battlegroup; @@ -100,30 +112,64 @@ void RealmList::UpdateRealms(bool init) { do { - Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string externalAddress = fields[2].GetString(); - std::string localAddress = fields[3].GetString(); - std::string localSubmask = fields[4].GetString(); - uint16 port = fields[5].GetUInt16(); - uint8 icon = fields[6].GetUInt8(); - RealmFlags flag = RealmFlags(fields[7].GetUInt8()); - uint8 timezone = fields[8].GetUInt8(); - uint8 allowedSecurityLevel = fields[9].GetUInt8(); - float pop = fields[10].GetFloat(); - uint32 build = fields[11].GetUInt32(); - uint8 region = fields[12].GetUInt8(); - uint8 battlegroup = fields[13].GetUInt8(); - - ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); - ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); - ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); - - UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); - - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); + try + { + boost::asio::ip::tcp::resolver::iterator end; + + Field* fields = result->Fetch(); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(fields[2].GetString(), ""); + boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return; + } + + ip::address externalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(fields[3].GetString(), ""); + endPoint = _resolver->resolve(localAddressQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return; + } + + ip::address localAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(fields[4].GetString(), ""); + endPoint = _resolver->resolve(localSubmaskQuery); + if (endPoint == end) + { + TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return; + } + + ip::address localSubmask = (*endPoint).endpoint().address(); + + uint16 port = fields[5].GetUInt16(); + uint8 icon = fields[6].GetUInt8(); + RealmFlags flag = RealmFlags(fields[7].GetUInt8()); + uint8 timezone = fields[8].GetUInt8(); + uint8 allowedSecurityLevel = fields[9].GetUInt8(); + float pop = fields[10].GetFloat(); + uint32 build = fields[11].GetUInt32(); + uint8 region = fields[12].GetUInt8(); + uint8 battlegroup = fields[13].GetUInt8(); + + UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); + + if (init) + TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + } + catch (std::exception& ex) + { + TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + ASSERT(false); + } } while (result->NextRow()); } diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index c4a6b4eaa0b..7426d5b3f32 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -19,30 +19,33 @@ #ifndef _REALMLIST_H #define _REALMLIST_H -#include <ace/Singleton.h> -#include <ace/Null_Mutex.h> -#include <ace/INET_Addr.h> +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/io_service.hpp> #include "Common.h" +using namespace boost::asio; + enum RealmFlags { - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 + REALM_FLAG_NONE = 0x00, + REALM_FLAG_INVALID = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 }; // Storage object for a realm struct Realm { - ACE_INET_Addr ExternalAddress; - ACE_INET_Addr LocalAddress; - ACE_INET_Addr LocalSubnetMask; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 port; std::string name; uint8 icon; RealmFlags flag; @@ -68,10 +71,15 @@ class RealmList public: typedef std::map<std::string, Realm> RealmMap; - RealmList(); - ~RealmList() { } + static RealmList& instance() + { + static RealmList *instance = new RealmList(); + return *instance; + } + + ~RealmList(); - void Initialize(uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); void UpdateIfNeed(); @@ -83,13 +91,17 @@ public: Realm const* GetRealm(Battlenet::RealmId const& id) const; private: - void UpdateRealms(bool init=false); - void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup); + RealmList(); + + void UpdateRealms(bool init = false); + void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup); RealmMap m_realms; uint32 m_UpdateInterval; time_t m_NextUpdateTime; + boost::asio::ip::tcp::resolver* _resolver; }; -#define sRealmList ACE_Singleton<RealmList, ACE_Null_Mutex>::instance() +#define sRealmList RealmList::instance() #endif diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSession.cpp index f1cb3af3f51..b426b82e44d 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -1,64 +1,57 @@ /* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <algorithm> -#include <openssl/md5.h> - -#include "Common.h" -#include "Database/DatabaseEnv.h" +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <memory> +#include <boost/lexical_cast.hpp> +#include <boost/asio/write.hpp> +#include <AuthSession.h> +#include <Log.h> #include "ByteBuffer.h" -#include "Configuration/Config.h" -#include "Log.h" -#include "RealmList.h" -#include "AuthSocket.h" #include "AuthCodes.h" -#include "TOTP.h" +#include "Database/DatabaseEnv.h" #include "SHA1.h" #include "openssl/crypto.h" +#include "Configuration/Config.h" +#include "RealmList.h" -#define ChunkSize 2048 +using boost::asio::ip::tcp; enum eAuthCmd { - AUTH_LOGON_CHALLENGE = 0x00, - AUTH_LOGON_PROOF = 0x01, - AUTH_RECONNECT_CHALLENGE = 0x02, - AUTH_RECONNECT_PROOF = 0x03, - REALM_LIST = 0x10, - XFER_INITIATE = 0x30, - XFER_DATA = 0x31, - XFER_ACCEPT = 0x32, - XFER_RESUME = 0x33, - XFER_CANCEL = 0x34 + AUTH_LOGON_CHALLENGE = 0x00, + AUTH_LOGON_PROOF = 0x01, + AUTH_RECONNECT_CHALLENGE = 0x02, + AUTH_RECONNECT_PROOF = 0x03, + REALM_LIST = 0x10, + XFER_INITIATE = 0x30, + XFER_DATA = 0x31, + XFER_ACCEPT = 0x32, + XFER_RESUME = 0x33, + XFER_CANCEL = 0x34 }; enum eStatus { - STATUS_CONNECTED = 0, + STATUS_CONNECTED = 0, STATUS_AUTHED }; -// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some paltform -#if defined(__GNUC__) -#pragma pack(1) -#else #pragma pack(push, 1) -#endif typedef struct AUTH_LOGON_CHALLENGE_C { @@ -86,7 +79,7 @@ typedef struct AUTH_LOGON_PROOF_C uint8 M1[20]; uint8 crc_hash[20]; uint8 number_of_keys; - uint8 securityFlags; // 0x00-0x04 + uint8 securityFlags; } sAuthLogonProof_C; typedef struct AUTH_LOGON_PROOF_S @@ -116,237 +109,110 @@ typedef struct AUTH_RECONNECT_PROOF_C uint8 number_of_keys; } sAuthReconnectProof_C; -typedef struct XFER_INIT -{ - uint8 cmd; // XFER_INITIATE - uint8 fileNameLen; // strlen(fileName); - uint8 fileName[5]; // fileName[fileNameLen] - uint64 file_size; // file size (bytes) - uint8 md5[MD5_DIGEST_LENGTH]; // MD5 -} XFER_INIT; - -typedef struct XFER_DATA -{ - uint8 opcode; - uint16 data_size; - uint8 data[ChunkSize]; -} XFER_DATA_STRUCT; +#pragma pack(pop) + typedef struct AuthHandler { eAuthCmd cmd; uint32 status; - bool (AuthSocket::*handler)(void); + size_t packetSize; + bool (AuthSession::*handler)(); } AuthHandler; -// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform -#if defined(__GNUC__) -#pragma pack() -#else -#pragma pack(pop) -#endif - -// Launch a thread to transfer a patch to the client -class PatcherRunnable: public ACE_Based::Runnable -{ -public: - PatcherRunnable(class AuthSocket*); - void run(); - -private: - AuthSocket* mySocket; -}; - -typedef struct PATCH_INFO -{ - uint8 md5[MD5_DIGEST_LENGTH]; -} PATCH_INFO; - -// Caches MD5 hash of client patches present on the server -class Patcher -{ -public: - typedef std::map<std::string, PATCH_INFO*> Patches; - ~Patcher(); - Patcher(); - Patches::const_iterator begin() const { return _patches.begin(); } - Patches::const_iterator end() const { return _patches.end(); } - void LoadPatchMD5(char*); - bool GetHash(char * pat, uint8 mymd5[16]); - -private: - void LoadPatchesInfo(); - Patches _patches; -}; +#define BYTE_SIZE 32 +#define REALMLIST_SKIP_PACKETS 5 const AuthHandler table[] = { - { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleLogonChallenge }, - { AUTH_LOGON_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleLogonProof }, - { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, &AuthSocket::_HandleReconnectChallenge}, - { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, &AuthSocket::_HandleReconnectProof }, - { REALM_LIST, STATUS_AUTHED, &AuthSocket::_HandleRealmList }, - { XFER_ACCEPT, STATUS_CONNECTED, &AuthSocket::_HandleXferAccept }, - { XFER_RESUME, STATUS_CONNECTED, &AuthSocket::_HandleXferResume }, - { XFER_CANCEL, STATUS_CONNECTED, &AuthSocket::_HandleXferCancel } + { AUTH_LOGON_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleLogonChallenge }, + { AUTH_LOGON_PROOF, STATUS_CONNECTED, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::_HandleLogonProof }, + { AUTH_RECONNECT_CHALLENGE, STATUS_CONNECTED, sizeof(AUTH_LOGON_CHALLENGE_C), &AuthSession::_HandleReconnectChallenge }, + { AUTH_RECONNECT_PROOF, STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::_HandleReconnectProof }, + { REALM_LIST, STATUS_AUTHED, REALMLIST_SKIP_PACKETS, &AuthSession::_HandleRealmList } }; -#define AUTH_TOTAL_COMMANDS 8 - -// Holds the MD5 hash of client patches present on the server -Patcher PatchesCache; - -// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket(RealmSocket& socket) : - pPatch(NULL), socket_(socket), _authed(false), _build(0), - _expversion(0), _accountSecurityLevel(SEC_PLAYER) +void AuthSession::AsyncReadHeader() { - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); -} + auto self(shared_from_this()); -// Close patch file descriptor before leaving -AuthSocket::~AuthSocket(void) { } + _socket.async_read_some(boost::asio::buffer(_readBuffer, 1), [this, self](boost::system::error_code error, size_t transferedBytes) + { + if (!error && transferedBytes == 1) + { + for (const AuthHandler& entry : table) + { + if ((uint8)entry.cmd == _readBuffer[0] && (entry.status == STATUS_CONNECTED || (_isAuthenticated && entry.status == STATUS_AUTHED))) + { + // Handle dynamic size packet + if (_readBuffer[0] == AUTH_LOGON_CHALLENGE) + { + _socket.read_some(boost::asio::buffer(&_readBuffer[1], sizeof(uint8) + sizeof(uint16))); //error + size -// Accept the connection -void AuthSocket::OnAccept(void) -{ - TC_LOG_DEBUG("server.authserver", "'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + AsyncReadData(entry.handler, *reinterpret_cast<uint16*>(&_readBuffer[2]), sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size + } + else + { + AsyncReadData(entry.handler, entry.packetSize, sizeof(uint8)); + } + break; + } + } + } + else + { + _socket.close(); + } + }); } -void AuthSocket::OnClose(void) +void AuthSession::AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffSet) { - TC_LOG_DEBUG("server.authserver", "AuthSocket::OnClose"); -} + auto self(shared_from_this()); -// Read the packet from the client -void AuthSocket::OnRead() -{ - #define MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW 3 - uint32 challengesInARow = 0; - uint8 _cmd; - while (1) + _socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffSet], dataSize), [handler, this, self](boost::system::error_code error, size_t transferedBytes) { - if (!socket().recv_soft((char *)&_cmd, 1)) - return; - - if (_cmd == AUTH_LOGON_CHALLENGE) + if (!error && transferedBytes > 0) { - ++challengesInARow; - if (challengesInARow == MAX_AUTH_LOGON_CHALLENGES_IN_A_ROW) + if (!(*this.*handler)()) { - TC_LOG_WARN("server.authserver", "Got %u AUTH_LOGON_CHALLENGE in a row from '%s', possible ongoing DoS", challengesInARow, socket().getRemoteAddress().c_str()); - socket().shutdown(); + _socket.close(); return; } - } - - size_t i; - // Circle through known commands and call the correct command handler - for (i = 0; i < AUTH_TOTAL_COMMANDS; ++i) - { - if ((uint8)table[i].cmd == _cmd && (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED))) - { - TC_LOG_DEBUG("server.authserver", "Got data for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - - if (!(*this.*table[i].handler)()) - { - TC_LOG_DEBUG("server.authserver", "Command handler failed for cmd %u recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); - return; - } - break; - } + AsyncReadHeader(); } - - // Report unknown packets in the error log - if (i == AUTH_TOTAL_COMMANDS) + else { - TC_LOG_ERROR("server.authserver", "Got unknown packet from '%s'", socket().getRemoteAddress().c_str()); - socket().shutdown(); - return; + _socket.close(); } - } + }); } -// Make the SRP6 calculation from hash in dB -void AuthSocket::_SetVSFields(const std::string& rI) +void AuthSession::AsyncWrite(std::size_t length) { - s.SetRand(s_BYTE_SIZE * 8); - - BigNumber I; - I.SetHexStr(rI.c_str()); - - // In case of leading zeros in the rI hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memset(mDigest, 0, SHA_DIGEST_LENGTH); - if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) - memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); - - SHA1Hash sha; - sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); - sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); - sha.Finalize(); - BigNumber x; - x.SetBinary(sha.GetDigest(), sha.GetLength()); - v = g.ModExp(x, N); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); - stmt->setString(0, v.AsHexStr()); - stmt->setString(1, s.AsHexStr()); - stmt->setString(2, _login); - LoginDatabase.Execute(stmt); + boost::asio::async_write(_socket, boost::asio::buffer(_writeBuffer, length), [this](boost::system::error_code error, std::size_t /*length*/) + { + if (error) + { + _socket.close(); + } + }); } -// Logon Challenge command handler -bool AuthSocket::_HandleLogonChallenge() +bool AuthSession::_HandleLogonChallenge() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonChallenge"); - if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; - - // Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector<uint8> buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - EndianConvertPtr<uint16>(&buf[0]); - - uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got header, body is %#04x bytes", remaining); - - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) - return false; - - //No big fear of memory outage (size is int16, i.e. < 65536) - buf.resize(remaining + buf.size() + 1); - buf[buf.size() - 1] = 0; - sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; - - // Read the remaining of the packet - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); - - // BigEndian code, nop in little endian case - // size already converted - EndianConvertPtr<uint32>(&ch->gamename[0]); - EndianConvert(ch->build); - EndianConvertPtr<uint32>(&ch->platform[0]); - EndianConvertPtr<uint32>(&ch->os[0]); - EndianConvertPtr<uint32>(&ch->country[0]); - EndianConvert(ch->timezone_bias); - EndianConvert(ch->ip); + //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); ByteBuffer pkt; - _login = (const char*)ch->I; - _build = ch->build; + _login.assign((const char*)challenge->I, challenge->I_len); + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -360,14 +226,16 @@ bool AuthSocket::_HandleLogonChallenge() // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); - std::string const& ip_address = socket().getRemoteAddress(); + std::string const& ipAddress = _socket.remote_endpoint().address().to_string(); + unsigned short port = _socket.remote_endpoint().port(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ip_address); + stmt->setString(0, ipAddress); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); } else { @@ -386,9 +254,9 @@ bool AuthSocket::_HandleLogonChallenge() if (fields[2].GetUInt8() == 1) // if ip is locked { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ip_address.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); - if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); @@ -405,7 +273,7 @@ bool AuthSocket::_HandleLogonChallenge() TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); else if (!accountCountry.empty()) { - uint32 ip = inet_addr(ip_address.c_str()); + uint32 ip = inet_addr(ipAddress.c_str()); EndianConvertReverse(ip); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); @@ -413,7 +281,9 @@ bool AuthSocket::_HandleLogonChallenge() if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), accountCountry.c_str(), loginCountry.c_str()); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), + accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) { TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); @@ -442,12 +312,14 @@ bool AuthSocket::_HandleLogonChallenge() if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) { pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), + port, _login.c_str()); } else { pkt << uint8(WOW_FAIL_SUSPENDED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", + ipAddress.c_str(), port, _login.c_str()); } } else @@ -462,8 +334,8 @@ bool AuthSocket::_HandleLogonChallenge() TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); // multiply with 2 since bytes are stored as hexstring - if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2) - _SetVSFields(rI); + if (databaseV.size() != BYTE_SIZE * 2 || databaseS.size() != BYTE_SIZE * 2) + SetVSFields(rI); else { s.SetHexStr(databaseS.c_str()); @@ -527,10 +399,12 @@ bool AuthSocket::_HandleLogonChallenge() _localizationName.resize(4); for (int i = 0; i < 4; ++i) - _localizationName[i] = ch->country[4-i-1]; + _localizationName[i] = challenge->country[4 - i - 1]; - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(), - _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName) + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", + ipAddress.c_str(), port, _login.c_str(), + challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], + GetLocaleByName(_localizationName) ); } } @@ -539,39 +413,38 @@ bool AuthSocket::_HandleLogonChallenge() pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); } - socket().send((char const*)pkt.contents(), pkt.size()); + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + + AsyncWrite(pkt.size()); + return true; } // Logon Proof command handler -bool AuthSocket::_HandleLogonProof() +bool AuthSession::_HandleLogonProof() { + TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); // Read the packet - sAuthLogonProof_C lp; - - if (!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) - return false; + sAuthLogonProof_C *logonProof = (sAuthLogonProof_C*)&_readBuffer; // If the client has no valid version if (_expversion == NO_VALID_EXP_FLAG) { // Check if we have the appropriate patch on the disk TC_LOG_DEBUG("network", "Client with invalid version, patching is not implemented"); - socket().shutdown(); - return true; + return false; } // Continue the SRP6 calculation based on data received from the client BigNumber A; - A.SetBinary(lp.A, 32); + A.SetBinary(logonProof->A, 32); // SRP safeguard: abort if A == 0 if (A.isZero()) { - socket().shutdown(); - return true; + return false; } SHA1Hash sha; @@ -639,14 +512,14 @@ bool AuthSocket::_HandleLogonProof() M.SetBinary(sha.GetDigest(), 20); // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray().get(), lp.M1, 20)) + if (!memcmp(M.AsByteArray().get(), logonProof->M1, 20)) { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); stmt->setString(0, K.AsHexStr()); - stmt->setString(1, socket().getRemoteAddress().c_str()); + stmt->setString(1, GetRemoteIpAddress().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); stmt->setString(4, _login); @@ -658,8 +531,11 @@ bool AuthSocket::_HandleLogonProof() sha.Finalize(); // Check auth token - if ((lp.securityFlags & 0x04) || !_tokenKey.empty()) + if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) { + // TODO To be fixed + + /* uint8 size; socket().recv((char*)&size, 1); char* token = new char[size + 1]; @@ -670,10 +546,10 @@ bool AuthSocket::_HandleLogonProof() delete[] token; if (validToken != incomingToken) { - char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); - return false; - } + char data[] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; + socket().send(data, sizeof(data)); + return false; + }*/ } if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients @@ -685,7 +561,9 @@ bool AuthSocket::_HandleLogonProof() proof.unk1 = GAMEACCOUNT_FLAG_PROPASS_LOCK; proof.unk2 = 0x00; // SurveyId proof.unk3 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); } else { @@ -694,26 +572,31 @@ bool AuthSocket::_HandleLogonProof() proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk2 = 0x00; - socket().send((char *)&proof, sizeof(proof)); + + std::memcpy(_writeBuffer, (char *)&proof, sizeof(proof)); + AsyncWrite(sizeof(proof)); } - _authed = true; + _isAuthenticated = true; } else { char data[4] = { AUTH_LOGON_PROOF, WOW_FAIL_UNKNOWN_ACCOUNT, 3, 0 }; - socket().send(data, sizeof(data)); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); + std::memcpy(_writeBuffer, data, sizeof(data)); + AsyncWrite(sizeof(data)); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); // We can not include the failed account login hook. However, this is a workaround to still log this. - if (sConfigMgr->GetBoolDefault("Additional.IP.Based.Login.Logging", false)) + if (sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false)) { PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); logstmt->setString(0, _login); - logstmt->setString(1, socket().getRemoteAddress()); + logstmt->setString(1, GetRemoteIpAddress()); logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); LoginDatabase.Execute(logstmt); @@ -747,17 +630,17 @@ bool AuthSocket::_HandleLogonProof() LoginDatabase.Execute(stmt); TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); } else { stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, socket().getRemoteAddress()); + stmt->setString(0, GetRemoteIpAddress()); stmt->setUInt32(1, WrongPassBanTime); LoginDatabase.Execute(stmt); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP %s got banned for '%u' seconds because account %s failed to authenticate '%u' times", - socket().getRemoteAddress().c_str(), socket().getRemotePort(), socket().getRemoteAddress().c_str(), WrongPassBanTime, _login.c_str(), failed_logins); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", + GetRemoteIpAddress().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); } } } @@ -767,38 +650,15 @@ bool AuthSocket::_HandleLogonProof() return true; } -// Reconnect Challenge command handler -bool AuthSocket::_HandleReconnectChallenge() +bool AuthSession::_HandleReconnectChallenge() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) - return false; - - // Read the first 4 bytes (header) to get the length of the remaining of the packet - std::vector<uint8> buf; - buf.resize(4); - - socket().recv((char *)&buf[0], 4); - - EndianConvertPtr<uint16>(&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; + sAuthLogonChallenge_C *challenge = (sAuthLogonChallenge_C*)&_readBuffer; - // 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]; + //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); - // Read the remaining of the packet - socket().recv((char *)&buf[4], remaining); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got full packet, %#04x bytes", ch->size); - TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); - - _login = (const char*)ch->I; + _login.assign((const char*)challenge->I, challenge->I_len); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); stmt->setString(0, _login); @@ -807,15 +667,15 @@ bool AuthSocket::_HandleReconnectChallenge() // Stop if the account is not found if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", + GetRemoteIpAddress().c_str(), GetRemotePort(), _login.c_str()); return false; } // Reinitialize build, expansion and the account securitylevel - _build = ch->build; + _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)ch->os; + _os = (const char*)challenge->os; if (_os.size() > 4) return false; @@ -827,7 +687,7 @@ bool AuthSocket::_HandleReconnectChallenge() uint8 secLevel = fields[2].GetUInt8(); _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - K.SetHexStr ((*result)[0].GetCString()); + K.SetHexStr((*result)[0].GetCString()); // Sending response ByteBuffer pkt; @@ -836,24 +696,22 @@ bool AuthSocket::_HandleReconnectChallenge() _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros - socket().send((char const*)pkt.contents(), pkt.size()); + + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + return true; } - -// Reconnect Proof command handler -bool AuthSocket::_HandleReconnectProof() +bool AuthSession::_HandleReconnectProof() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); - // Read the packet - sAuthReconnectProof_C lp; - if (!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) - return false; + sAuthReconnectProof_C *reconnectProof = (sAuthReconnectProof_C*)&_readBuffer; if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; BigNumber t1; - t1.SetBinary(lp.R1, 16); + t1.SetBinary(reconnectProof->R1, 16); SHA1Hash sha; sha.Initialize(); @@ -861,33 +719,64 @@ bool AuthSocket::_HandleReconnectProof() sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); - if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) + if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) { // Sending response ByteBuffer pkt; pkt << uint8(AUTH_RECONNECT_PROOF); pkt << uint8(0x00); pkt << uint16(0x00); // 2 bytes zeros - socket().send((char const*)pkt.contents(), pkt.size()); - _authed = true; + std::memcpy(_writeBuffer, (char const*)pkt.contents(), pkt.size()); + AsyncWrite(pkt.size()); + _isAuthenticated = true; return true; } else { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); return false; } } -// Realm List command handler -bool AuthSocket::_HandleRealmList() +tcp::endpoint const GetAddressForClient(Realm const& realm, ip::address const& clientAddr) { - TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - if (socket().recv_len() < 5) - return false; + ip::address realmIp; + + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + realmIp = realm.LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong()) == + (realm.LocalAddress.to_v4().to_ulong() & realm.LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = realm.LocalAddress; + } + else + realmIp = realm.ExternalAddress; + } + + tcp::endpoint endpoint(realmIp, realm.port); - socket().recv_skip(5); + // Return external IP + return endpoint; +} + +bool AuthSession::_HandleRealmList() +{ + TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); // Get the user id (else close the connection) // No SQL injection (prepared statement) @@ -896,8 +785,8 @@ bool AuthSocket::_HandleRealmList() PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); - socket().shutdown(); + TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().c_str(), + GetRemotePort(), _login.c_str()); return false; } @@ -905,16 +794,13 @@ bool AuthSocket::_HandleRealmList() uint32 id = fields[0].GetUInt32(); // Update realm list if need - sRealmList->UpdateIfNeed(); - - ACE_INET_Addr clientAddr; - socket().peer().get_remote_addr(clientAddr); + sRealmList.UpdateIfNeed(); // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; size_t RealmListSize = 0; - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + for (RealmList::RealmMap::const_iterator i = sRealmList.begin(); i != sRealmList.end(); ++i) { const Realm &realm = i->second; // don't work with realms which not compatible with the client @@ -942,9 +828,6 @@ bool AuthSocket::_HandleRealmList() name = ss.str(); } - // We don't need the port number from which client connects with but the realm's port - clientAddr.set_port_number(realm.ExternalAddress.get_port_number()); - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; uint8 AmountOfCharacters = 0; @@ -960,7 +843,7 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << GetAddressString(realm.GetAddressForClient(clientAddr)); + pkt << boost::lexical_cast<std::string>(GetAddressForClient(realm, _socket.remote_endpoint().address())); pkt << realm.populationLevel; pkt << AmountOfCharacters; pkt << realm.timezone; // realm category @@ -1005,182 +888,47 @@ bool AuthSocket::_HandleRealmList() hdr.append(RealmListSizeBuffer); // append RealmList's size buffer hdr.append(pkt); // append realms in the realmlist - socket().send((char const*)hdr.contents(), hdr.size()); + std::memcpy(_writeBuffer, (char const*)hdr.contents(), hdr.size()); + AsyncWrite(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 <dirent.h> -#include <errno.h> -void Patcher::LoadPatchesInfo() -{ - DIR *dirp; - struct dirent *dp; - dirp = opendir("./patches/"); - - if (!dirp) - return; - - while (dirp) - { - errno = 0; - if ((dp = readdir(dirp)) != NULL) - { - int l = strlen(dp->d_name); - - if (l < 8) - continue; - - if (!memcmp(&dp->d_name[l - 4], ".mpq", 4)) - LoadPatchMD5(dp->d_name); - } - else - { - if (errno != 0) - { - closedir(dirp); - return; - } - break; - } - } - - if (dirp) - closedir(dirp); -} -#else -void Patcher::LoadPatchesInfo() -{ - WIN32_FIND_DATA fil; - HANDLE hFil = FindFirstFile("./patches/*.mpq", &fil); - if (hFil == INVALID_HANDLE_VALUE) - return; // no patches were found - - do - LoadPatchMD5(fil.cFileName); - while (FindNextFile(hFil, &fil)); -} -#endif - -// Calculate and store MD5 hash for a given patch file -void Patcher::LoadPatchMD5(char *szFileName) +// Make the SRP6 calculation from hash in dB +void AuthSession::SetVSFields(const std::string& rI) { - // Try to open the patch file - std::string path = "./patches/"; - path += szFileName; - FILE* pPatch = fopen(path.c_str(), "rb"); - TC_LOG_DEBUG("network", "Loading patch info from %s\n", path.c_str()); + s.SetRand(BYTE_SIZE * 8); - 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); - } + BigNumber I; + I.SetHexStr(rI.c_str()); - delete [] buf; - fclose(pPatch); + // In case of leading zeros in the rI hash, restore them + uint8 mDigest[SHA_DIGEST_LENGTH]; + memset(mDigest, 0, SHA_DIGEST_LENGTH); + if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) + memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes()); - // Store the result in the internal patch hash map - _patches[path] = new PATCH_INFO; - MD5_Final((uint8 *)&_patches[path]->md5, &ctx); -} + std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); -// Get cached MD5 hash for a given patch file -bool Patcher::GetHash(char * pat, uint8 mymd5[16]) -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - if (!stricmp(pat, i->first.c_str())) - { - memcpy(mymd5, i->second->md5, 16); - return true; - } + SHA1Hash sha; + sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes()); + sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); - return false; -} + // No SQL injection (username escaped) + char *v_hex, *s_hex; + v_hex = v.AsHexStr(); + s_hex = s.AsHexStr(); -// Launch the patch hashing mechanism on object creation -Patcher::Patcher() -{ - LoadPatchesInfo(); -} + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); + stmt->setString(0, v_hex); + stmt->setString(1, s_hex); + stmt->setString(2, _login); + LoginDatabase.Execute(stmt); -// Empty and delete the patch map on termination -Patcher::~Patcher() -{ - for (Patches::iterator i = _patches.begin(); i != _patches.end(); ++i) - delete i->second; + OPENSSL_free(v_hex); + OPENSSL_free(s_hex); } diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h new file mode 100644 index 00000000000..4ae33f44cb3 --- /dev/null +++ b/src/server/authserver/Server/AuthSession.h @@ -0,0 +1,84 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __AUTHSESSION_H__ +#define __AUTHSESSION_H__ + +#include <memory> +#include <boost/asio/ip/tcp.hpp> +#include "Common.h" +#include "BigNumber.h" + +using boost::asio::ip::tcp; + +const size_t bufferSize = 4096; + +#define BUFFER_SIZE 4096 + +class AuthSession : public std::enable_shared_from_this < AuthSession > +{ +public: + AuthSession(tcp::socket&& socket) : _socket(std::move(socket)) + { + N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword(7); + } + + void Start() + { + AsyncReadHeader(); + } + + bool _HandleLogonChallenge(); + bool _HandleLogonProof(); + bool _HandleReconnectChallenge(); + bool _HandleReconnectProof(); + bool _HandleRealmList(); + + const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; + unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); } + +private: + void AsyncReadHeader(); + void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset); + void AsyncWrite(size_t length); + + + void SetVSFields(const std::string& rI); + + BigNumber N, s, g, v; + BigNumber b, B; + BigNumber K; + BigNumber _reconnectProof; + + tcp::socket _socket; + char _readBuffer[BUFFER_SIZE]; + char _writeBuffer[BUFFER_SIZE]; + + bool _isAuthenticated; + std::string _tokenKey; + std::string _login; + std::string _localizationName; + std::string _os; + uint16 _build; + uint8 _expversion; + + AccountTypes _accountSecurityLevel; +}; + +#endif diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h deleted file mode 100644 index e81944389ef..00000000000 --- a/src/server/authserver/Server/AuthSocket.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _AUTHSOCKET_H -#define _AUTHSOCKET_H - -#include "Common.h" -#include "BigNumber.h" -#include "RealmSocket.h" - -class ACE_INET_Addr; -struct Realm; - -// Handle login commands -class AuthSocket: public RealmSocket::Session -{ -public: - const static int s_BYTE_SIZE = 32; - - AuthSocket(RealmSocket& socket); - virtual ~AuthSocket(void); - - virtual void OnRead(void); - virtual void OnAccept(void); - virtual void OnClose(void); - - 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 2089b0c7a22..00000000000 --- a/src/server/authserver/Server/RealmAcceptor.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __REALMACCEPTOR_H__ -#define __REALMACCEPTOR_H__ - -#include <ace/Acceptor.h> -#include <ace/SOCK_Acceptor.h> - -#include "RealmSocket.h" -#include "AuthSocket.h" -#include "BattlenetSocket.h" - -template<class LoginType> -class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor> -{ -public: - RealmAcceptor(void) { } - virtual ~RealmAcceptor(void) - { - if (reactor()) - reactor()->cancel_timer(this, 1); - } - -protected: - virtual int make_svc_handler(RealmSocket* &sh) - { - if (sh == 0) - ACE_NEW_RETURN(sh, RealmSocket, -1); - - sh->reactor(reactor()); - sh->set_session(new LoginType(*sh)); - return 0; - } - - virtual int handle_timeout(const ACE_Time_Value& /*current_time*/, const void* /*act = 0*/) - { - TC_LOG_DEBUG("server.authserver", "Resuming acceptor"); - reactor()->cancel_timer(this, 1); - return reactor()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); - } - - virtual int handle_accept_error(void) - { -#if defined(ENFILE) && defined(EMFILE) - if (errno == ENFILE || errno == EMFILE) - { - TC_LOG_ERROR("server.authserver", "Out of file descriptors, suspending incoming connections for 10 seconds"); - reactor()->remove_handler(this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); - reactor()->schedule_timer(this, NULL, ACE_Time_Value(10)); - } -#endif - return 0; - } -}; - -#endif diff --git a/src/server/authserver/Server/RealmSocket.cpp b/src/server/authserver/Server/RealmSocket.cpp deleted file mode 100644 index 1013639cc50..00000000000 --- a/src/server/authserver/Server/RealmSocket.cpp +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <ace/OS_NS_string.h> -#include <ace/INET_Addr.h> -#include <ace/SString.h> - -#include "RealmSocket.h" -#include "Log.h" - -RealmSocket::Session::Session(void) { } - -RealmSocket::Session::~Session(void) { } - -RealmSocket::RealmSocket(void) : - input_buffer_(4096), session_(NULL), - _remoteAddress(), _remotePort(0) -{ - reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED); - - msg_queue()->high_water_mark(8 * 1024 * 1024); - msg_queue()->low_water_mark(8 * 1024 * 1024); -} - -RealmSocket::~RealmSocket(void) -{ - if (msg_queue()) - msg_queue()->close(); - - // delete RealmSocketObject must never be called from our code. - closing_ = true; - - delete session_; - - peer().close(); -} - -int RealmSocket::open(void * arg) -{ - ACE_INET_Addr addr; - - if (peer().get_remote_addr(addr) == -1) - { - TC_LOG_ERROR("server.authserver", "Error %s while opening realm socket!", ACE_OS::strerror(errno)); - return -1; - } - - _remoteAddress = addr.get_host_addr(); - _remotePort = addr.get_port_number(); - - // Register with ACE Reactor - if (Base::open(arg) == -1) - return -1; - - if (session_) - session_->OnAccept(); - - // reactor takes care of the socket from now on - remove_reference(); - - return 0; -} - -int RealmSocket::close(u_long) -{ - shutdown(); - - closing_ = true; - - remove_reference(); - - return 0; -} - -const std::string& RealmSocket::getRemoteAddress(void) const -{ - return _remoteAddress; -} - -uint16 RealmSocket::getRemotePort(void) const -{ - return _remotePort; -} - -size_t RealmSocket::recv_len(void) const -{ - return input_buffer_.length(); -} - -bool RealmSocket::recv_soft(char *buf, size_t len) -{ - if (input_buffer_.length() < len) - return false; - - ACE_OS::memcpy(buf, input_buffer_.rd_ptr(), len); - - return true; -} - -bool RealmSocket::recv(char *buf, size_t len) -{ - bool ret = recv_soft(buf, len); - - if (ret) - recv_skip(len); - - return ret; -} - -void RealmSocket::recv_skip(size_t len) -{ - input_buffer_.rd_ptr(len); -} - -ssize_t RealmSocket::noblk_send(ACE_Message_Block &message_block) -{ - const size_t len = message_block.length(); - - if (len == 0) - return -1; - - // Try to send the message directly. -#ifdef MSG_NOSIGNAL - ssize_t n = peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); -#else - ssize_t n = peer().send(message_block.rd_ptr(), len); -#endif // MSG_NOSIGNAL - - if (n < 0) - { - if (errno == EWOULDBLOCK) // Blocking signal - return 0; - else // Error happened - return -1; - } - else if (n == 0) - { - // Can this happen ? - return -1; - } - - // return bytes transmitted - return n; -} - -bool RealmSocket::send(const char *buf, size_t len) -{ - if (buf == NULL || len == 0) - return true; - - ACE_Data_Block db(len, ACE_Message_Block::MB_DATA, (const char*)buf, 0, 0, ACE_Message_Block::DONT_DELETE, 0); - ACE_Message_Block message_block(&db, ACE_Message_Block::DONT_DELETE, 0); - - message_block.wr_ptr(len); - - if (msg_queue()->is_empty()) - { - // Try to send it directly. - ssize_t n = noblk_send(message_block); - - if (n < 0) - return false; - - size_t un = size_t(n); - if (un == len) - return true; - - // fall down - message_block.rd_ptr(un); - } - - ACE_Message_Block* mb = message_block.clone(); - - if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - { - mb->release(); - return false; - } - - if (reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1) - return false; - - return true; -} - -int RealmSocket::handle_output(ACE_HANDLE) -{ - if (closing_) - return -1; - - ACE_Message_Block* mb = 0; - - if (msg_queue()->is_empty()) - { - reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); - return 0; - } - - if (msg_queue()->dequeue_head(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1) - return -1; - - ssize_t n = noblk_send(*mb); - - if (n < 0) - { - mb->release(); - return -1; - } - else if (size_t(n) == mb->length()) - { - mb->release(); - return 1; - } - else - { - mb->rd_ptr(n); - - if (msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) - { - mb->release(); - return -1; - } - - return 0; - } - - ACE_NOTREACHED(return -1); -} - -int RealmSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask) -{ - // As opposed to WorldSocket::handle_close, we don't need locks here. - closing_ = true; - - if (h == ACE_INVALID_HANDLE) - peer().close_writer(); - - if (session_) - session_->OnClose(); - - reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK); - return 0; -} - -int RealmSocket::handle_input(ACE_HANDLE) -{ - if (closing_) - return -1; - - const ssize_t space = input_buffer_.space(); - - ssize_t n = peer().recv(input_buffer_.wr_ptr(), space); - - if (n < 0) - return errno == EWOULDBLOCK ? 0 : -1; - else if (n == 0) // EOF - return -1; - - input_buffer_.wr_ptr((size_t)n); - - if (session_ != NULL) - { - session_->OnRead(); - input_buffer_.crunch(); - } - - // return 1 in case there is more data to read from OS - return n == space ? 1 : 0; -} - -void RealmSocket::set_session(Session* session) -{ - delete session_; - - session_ = session; -} diff --git a/src/server/authserver/Server/RealmSocket.h b/src/server/authserver/Server/RealmSocket.h deleted file mode 100644 index c1190d638b3..00000000000 --- a/src/server/authserver/Server/RealmSocket.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __REALMSOCKET_H__ -#define __REALMSOCKET_H__ - -#include <ace/Synch_Traits.h> -#include <ace/Svc_Handler.h> -#include <ace/SOCK_Stream.h> -#include <ace/Message_Block.h> -#include <ace/Basic_Types.h> -#include "Common.h" - -class RealmSocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ -private: - typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Base; - -public: - class Session - { - public: - Session(void); - virtual ~Session(void); - - virtual void OnRead(void) = 0; - virtual void OnAccept(void) = 0; - virtual void OnClose(void) = 0; - }; - - RealmSocket(void); - virtual ~RealmSocket(void); - - size_t recv_len(void) const; - bool recv_soft(char *buf, size_t len); - bool recv(char *buf, size_t len); - void recv_skip(size_t len); - - bool send(const char *buf, size_t len); - - const std::string& getRemoteAddress(void) const; - - uint16 getRemotePort(void) const; - - virtual int open(void *); - - virtual int close(u_long); - - virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); - virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); - - virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); - - void set_session(Session* session); - -private: - ssize_t noblk_send(ACE_Message_Block &message_block); - - ACE_Message_Block input_buffer_; - Session* session_; - std::string _remoteAddress; - uint16 _remotePort; -}; - -#endif /* __REALMSOCKET_H__ */ |
