From a04393f5542cc02b1af0e4259d98cc40080972d1 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 10 Oct 2014 23:19:40 +0200 Subject: Core/Auth: Moved battle.net handling to separate project --- src/server/bnetserver/Authentication/AuthCodes.cpp | 55 ++ src/server/bnetserver/Authentication/AuthCodes.h | 128 +++ .../Authentication/BattlenetPacketCrypt.cpp | 42 + .../Authentication/BattlenetPacketCrypt.h | 36 + src/server/bnetserver/CMakeLists.txt | 115 +++ src/server/bnetserver/Main.cpp | 238 +++++ src/server/bnetserver/Packets/AchievementPackets.h | 42 + .../bnetserver/Packets/AuthenticationPackets.cpp | 319 +++++++ .../bnetserver/Packets/AuthenticationPackets.h | 196 ++++ src/server/bnetserver/Packets/BitStream.cpp | 30 + src/server/bnetserver/Packets/BitStream.h | 243 +++++ src/server/bnetserver/Packets/CachePackets.h | 43 + src/server/bnetserver/Packets/ChatPackets.h | 63 ++ .../bnetserver/Packets/ConnectionPackets.cpp | 54 ++ src/server/bnetserver/Packets/ConnectionPackets.h | 94 ++ src/server/bnetserver/Packets/FriendsPackets.cpp | 179 ++++ src/server/bnetserver/Packets/FriendsPackets.h | 162 ++++ src/server/bnetserver/Packets/PacketFactory.h | 83 ++ src/server/bnetserver/Packets/Packets.h | 32 + src/server/bnetserver/Packets/PacketsBase.cpp | 38 + src/server/bnetserver/Packets/PacketsBase.h | 120 +++ src/server/bnetserver/Packets/PresencePackets.cpp | 48 + src/server/bnetserver/Packets/PresencePackets.h | 65 ++ src/server/bnetserver/Packets/ProfilePackets.h | 44 + src/server/bnetserver/Packets/SupportPackets.h | 34 + src/server/bnetserver/Packets/WoWRealmPackets.cpp | 202 ++++ src/server/bnetserver/Packets/WoWRealmPackets.h | 173 ++++ .../bnetserver/PrecompiledHeaders/bnetPCH.cpp | 1 + src/server/bnetserver/PrecompiledHeaders/bnetPCH.h | 10 + src/server/bnetserver/Realms/RealmList.cpp | 207 ++++ src/server/bnetserver/Realms/RealmList.h | 113 +++ src/server/bnetserver/Server/ComponentManager.cpp | 55 ++ src/server/bnetserver/Server/ComponentManager.h | 61 ++ src/server/bnetserver/Server/ModuleManager.cpp | 57 ++ src/server/bnetserver/Server/ModuleManager.h | 94 ++ src/server/bnetserver/Server/Session.cpp | 1000 ++++++++++++++++++++ src/server/bnetserver/Server/Session.h | 128 +++ src/server/bnetserver/Server/SessionManager.cpp | 37 + src/server/bnetserver/Server/SessionManager.h | 71 ++ src/server/bnetserver/bnetserver.conf.dist | 257 +++++ src/server/bnetserver/bnetserver.ico | Bin 0 -> 136606 bytes src/server/bnetserver/bnetserver.rc | 94 ++ src/server/bnetserver/resource.h | 15 + 43 files changed, 5078 insertions(+) create mode 100644 src/server/bnetserver/Authentication/AuthCodes.cpp create mode 100644 src/server/bnetserver/Authentication/AuthCodes.h create mode 100644 src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp create mode 100644 src/server/bnetserver/Authentication/BattlenetPacketCrypt.h create mode 100644 src/server/bnetserver/CMakeLists.txt create mode 100644 src/server/bnetserver/Main.cpp create mode 100644 src/server/bnetserver/Packets/AchievementPackets.h create mode 100644 src/server/bnetserver/Packets/AuthenticationPackets.cpp create mode 100644 src/server/bnetserver/Packets/AuthenticationPackets.h create mode 100644 src/server/bnetserver/Packets/BitStream.cpp create mode 100644 src/server/bnetserver/Packets/BitStream.h create mode 100644 src/server/bnetserver/Packets/CachePackets.h create mode 100644 src/server/bnetserver/Packets/ChatPackets.h create mode 100644 src/server/bnetserver/Packets/ConnectionPackets.cpp create mode 100644 src/server/bnetserver/Packets/ConnectionPackets.h create mode 100644 src/server/bnetserver/Packets/FriendsPackets.cpp create mode 100644 src/server/bnetserver/Packets/FriendsPackets.h create mode 100644 src/server/bnetserver/Packets/PacketFactory.h create mode 100644 src/server/bnetserver/Packets/Packets.h create mode 100644 src/server/bnetserver/Packets/PacketsBase.cpp create mode 100644 src/server/bnetserver/Packets/PacketsBase.h create mode 100644 src/server/bnetserver/Packets/PresencePackets.cpp create mode 100644 src/server/bnetserver/Packets/PresencePackets.h create mode 100644 src/server/bnetserver/Packets/ProfilePackets.h create mode 100644 src/server/bnetserver/Packets/SupportPackets.h create mode 100644 src/server/bnetserver/Packets/WoWRealmPackets.cpp create mode 100644 src/server/bnetserver/Packets/WoWRealmPackets.h create mode 100644 src/server/bnetserver/PrecompiledHeaders/bnetPCH.cpp create mode 100644 src/server/bnetserver/PrecompiledHeaders/bnetPCH.h create mode 100644 src/server/bnetserver/Realms/RealmList.cpp create mode 100644 src/server/bnetserver/Realms/RealmList.h create mode 100644 src/server/bnetserver/Server/ComponentManager.cpp create mode 100644 src/server/bnetserver/Server/ComponentManager.h create mode 100644 src/server/bnetserver/Server/ModuleManager.cpp create mode 100644 src/server/bnetserver/Server/ModuleManager.h create mode 100644 src/server/bnetserver/Server/Session.cpp create mode 100644 src/server/bnetserver/Server/Session.h create mode 100644 src/server/bnetserver/Server/SessionManager.cpp create mode 100644 src/server/bnetserver/Server/SessionManager.h create mode 100644 src/server/bnetserver/bnetserver.conf.dist create mode 100644 src/server/bnetserver/bnetserver.ico create mode 100644 src/server/bnetserver/bnetserver.rc create mode 100644 src/server/bnetserver/resource.h (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Authentication/AuthCodes.cpp b/src/server/bnetserver/Authentication/AuthCodes.cpp new file mode 100644 index 00000000000..908bc30b719 --- /dev/null +++ b/src/server/bnetserver/Authentication/AuthCodes.cpp @@ -0,0 +1,55 @@ +/* + * 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 "AuthCodes.h" +#include + +namespace AuthHelper +{ + static RealmBuildInfo const PostBcAcceptedClientBuilds[] = + { + {15595, 4, 3, 4, ' '}, + {14545, 4, 2, 2, ' '}, + {13623, 4, 0, 6, 'a'}, + {13930, 3, 3, 5, 'a'}, // 3.3.5a China Mainland build + {12340, 3, 3, 5, 'a'}, + {11723, 3, 3, 3, 'a'}, + {11403, 3, 3, 2, ' '}, + {11159, 3, 3, 0, 'a'}, + {10505, 3, 2, 2, 'a'}, + {9947, 3, 1, 3, ' '}, + {8606, 2, 4, 3, ' '}, + {6141, 1, 12, 3, ' '}, + {6005, 1, 12, 2, ' '}, + {5875, 1, 12, 1, ' '}, + {0, 0, 0, 0, ' '} // terminator + }; + + RealmBuildInfo const* GetBuildInfo(int build) + { + for (int i = 0; PostBcAcceptedClientBuilds[i].Build; ++i) + if (PostBcAcceptedClientBuilds[i].Build == build) + return &PostBcAcceptedClientBuilds[i]; + + return nullptr; + } + + bool IsBuildSupportingBattlenet(int build) + { + return build >= 15595; + } +} diff --git a/src/server/bnetserver/Authentication/AuthCodes.h b/src/server/bnetserver/Authentication/AuthCodes.h new file mode 100644 index 00000000000..3c3b002551c --- /dev/null +++ b/src/server/bnetserver/Authentication/AuthCodes.h @@ -0,0 +1,128 @@ +/* + * 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 _AUTHCODES_H +#define _AUTHCODES_H + +enum GameAccountFlags +{ + GAMEACCOUNT_FLAG_GM = 0x00000001, + GAMEACCOUNT_FLAG_NOKICK = 0x00000002, + GAMEACCOUNT_FLAG_COLLECTOR = 0x00000004, + GAMEACCOUNT_FLAG_WOW_TRIAL = 0x00000008, + GAMEACCOUNT_FLAG_CANCELLED = 0x00000010, + GAMEACCOUNT_FLAG_IGR = 0x00000020, + GAMEACCOUNT_FLAG_WHOLESALER = 0x00000040, + GAMEACCOUNT_FLAG_PRIVILEGED = 0x00000080, + GAMEACCOUNT_FLAG_EU_FORBID_ELV = 0x00000100, + GAMEACCOUNT_FLAG_EU_FORBID_BILLING = 0x00000200, + GAMEACCOUNT_FLAG_WOW_RESTRICTED = 0x00000400, + GAMEACCOUNT_FLAG_REFERRAL = 0x00000800, + GAMEACCOUNT_FLAG_BLIZZARD = 0x00001000, + GAMEACCOUNT_FLAG_RECURRING_BILLING = 0x00002000, + GAMEACCOUNT_FLAG_NOELECTUP = 0x00004000, + GAMEACCOUNT_FLAG_KR_CERTIFICATE = 0x00008000, + GAMEACCOUNT_FLAG_EXPANSION_COLLECTOR = 0x00010000, + GAMEACCOUNT_FLAG_DISABLE_VOICE = 0x00020000, + GAMEACCOUNT_FLAG_DISABLE_VOICE_SPEAK = 0x00040000, + GAMEACCOUNT_FLAG_REFERRAL_RESURRECT = 0x00080000, + GAMEACCOUNT_FLAG_EU_FORBID_CC = 0x00100000, + GAMEACCOUNT_FLAG_OPENBETA_DELL = 0x00200000, + GAMEACCOUNT_FLAG_PROPASS = 0x00400000, + GAMEACCOUNT_FLAG_PROPASS_LOCK = 0x00800000, + GAMEACCOUNT_FLAG_PENDING_UPGRADE = 0x01000000, + GAMEACCOUNT_FLAG_RETAIL_FROM_TRIAL = 0x02000000, + GAMEACCOUNT_FLAG_EXPANSION2_COLLECTOR = 0x04000000, + GAMEACCOUNT_FLAG_OVERMIND_LINKED = 0x08000000, + GAMEACCOUNT_FLAG_DEMOS = 0x10000000, + GAMEACCOUNT_FLAG_DEATH_KNIGHT_OK = 0x20000000, +}; + +namespace Battlenet +{ + enum AuthResult + { + AUTH_OK = 0, + AUTH_INTERNAL_ERROR = 100, + AUTH_CORRUPTED_MODULE = 101, + AUTH_NO_BATTLETAGS = 102, + AUTH_BAD_SERVER_PROOF = 103, + AUTH_UNKNOWN_ACCOUNT = 104, + AUTH_CLOSED = 105, + AUTH_LOGIN_TIMEOUT = 106, + AUTH_NO_GAME_ACCOUNTS = 107, + AUTH_INVALID_TOKEN = 108, + AUTH_INVALID_PROGRAM = 109, + AUTH_INVALID_OS = 110, + AUTH_UNSUPPORTED_LANGUAGE = 111, + AUTH_REGION_BAD_VERSION = 112, + AUTH_TEMP_OUTAGE = 113, + AUTH_CANT_DOWNLOAD_MODULE = 114, + AUTH_DUPLICATE_LOGON = 115, + AUTH_BAD_CREDENTIALS_2 = 116, + AUTH_VERSION_CHECK_SUCCEEDED = 117, + AUTH_BAD_VERSION_HASH = 118, + AUTH_CANT_RETRIEVE_PORTAL_LIST = 119, + AUTH_DARK_PORTAL_DOES_NOT_EXIST = 120, + AUTH_DARK_PORTAL_FILE_CORRUPTED = 121, + AUTH_BATTLENET_MAINTENANCE = 122, + AUTH_LOGON_TOO_FAST = 123, + AUTH_USE_GRUNT_LOGON = 124, + AUTH_NO_GAME_ACCOUNTS_IN_REGION = 140, + AUTH_ACCOUNT_LOCKED = 141, + + LOGIN_SERVER_BUSY = 200, + LOGIN_NO_GAME_ACCOUNT = 201, + LOGIN_BANNED = 202, + LOGIN_SUSPENDED = 203, + LOGIN_GAME_ACCOUNT_LOCKED = 204, + LOGIN_ALREADY_ONLINE = 205, + LOGIN_NOTIME = 206, + LOGIN_EXPIRED = 207, + LOGIN_EXPIRED_2 = 208, + LOGIN_PARENTALCONTROL = 209, + LOGIN_TRIAL_EXPIRED = 210, + LOGIN_ANTI_INDULGENCE = 211, + LOGIN_INCORRECT_REGION = 212, + LOGIN_LOCKED_ENFORCED = 213, + LOGIN_CHARGEBACK = 214, + LOGIN_IGR_WITHOUT_BNET = 215, + LOGIN_UNLOCKABLE_LOCK = 216, + LOGIN_IGR_REQUIRED = 217, + LOGIN_PAYMENT_CHANGED = 218, + LOGIN_INVALID_PAYMENT = 219, + LOGIN_INVALID_ACCOUNT_STATE = 220 + }; +} + +struct RealmBuildInfo +{ + int Build; + int MajorVersion; + int MinorVersion; + int BugfixVersion; + int HotfixVersion; +}; + +namespace AuthHelper +{ + RealmBuildInfo const* GetBuildInfo(int build); + bool IsBuildSupportingBattlenet(int build); +} + +#endif diff --git a/src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp b/src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp new file mode 100644 index 00000000000..de4cf73f71c --- /dev/null +++ b/src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp @@ -0,0 +1,42 @@ +/* + * 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 "BattlenetPacketCrypt.h" +#include "Cryptography/HmacHash.h" +#include "Cryptography/BigNumber.h" + +Battlenet::PacketCrypt::PacketCrypt() : ::PacketCrypt(SHA256_DIGEST_LENGTH) +{ +} + +void Battlenet::PacketCrypt::Init(BigNumber* K) +{ + uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E }; + uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 }; + + HmacSha256 serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get()); + serverEncryptHmac.UpdateData(ServerEncryptionKey, SEED_KEY_SIZE); + serverEncryptHmac.Finalize(); + + HmacSha256 clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get()); + clientDecryptHmac.UpdateData(ClientDecryptionKey, SEED_KEY_SIZE); + clientDecryptHmac.Finalize(); + + _clientDecrypt.Init(clientDecryptHmac.GetDigest()); + _serverEncrypt.Init(serverEncryptHmac.GetDigest()); + _initialized = true; +} diff --git a/src/server/bnetserver/Authentication/BattlenetPacketCrypt.h b/src/server/bnetserver/Authentication/BattlenetPacketCrypt.h new file mode 100644 index 00000000000..a09d3417dfe --- /dev/null +++ b/src/server/bnetserver/Authentication/BattlenetPacketCrypt.h @@ -0,0 +1,36 @@ +/* + * 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 BattlenetPacketCrypt_h__ +#define BattlenetPacketCrypt_h__ + +#include "PacketCrypt.h" + +class BigNumber; + +namespace Battlenet +{ + class PacketCrypt : public ::PacketCrypt + { + public: + PacketCrypt(); + + void Init(BigNumber* K) override; + }; +} +#endif // BattlenetPacketCrypt_h__ + diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt new file mode 100644 index 00000000000..3fa4abf034a --- /dev/null +++ b/src/server/bnetserver/CMakeLists.txt @@ -0,0 +1,115 @@ +# Copyright (C) 2008-2014 TrinityCore +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +########### authserver ############### + +file(GLOB_RECURSE sources_authentication Authentication/*.cpp Authentication/*.h) +file(GLOB_RECURSE sources_realms Realms/*.cpp Realms/*.h) +file(GLOB_RECURSE sources_server Server/*.cpp Server/*.h) +file(GLOB_RECURSE sources_packets Packets/*.cpp Packets/*.h) +file(GLOB sources_localdir *.cpp *.h) + +if (USE_COREPCH) + set(bnetserver_PCH_HDR PrecompiledHeaders/bnetPCH.h) + set(bnetserver_PCH_SRC PrecompiledHeaders/bnetPCH.cpp) +endif() + +set(bnetserver_SRCS + ${bnetserver_SRCS} + ${sources_authentication} + ${sources_realms} + ${sources_server} + ${sources_packets} + ${sources_localdir} +) + +if( WIN32 ) + set(bnetserver_SRCS + ${bnetserver_SRCS} + ${sources_windows_Debugging} + ) + if ( MSVC ) + set(bnetserver_SRCS + ${bnetserver_SRCS} + bnetserver.rc + ) + endif () +endif() + +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/src/server/shared + ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration + ${CMAKE_SOURCE_DIR}/src/server/shared/Database + ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging + ${CMAKE_SOURCE_DIR}/src/server/shared/Packets + ${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 + ${CMAKE_CURRENT_SOURCE_DIR}/Packets + ${MYSQL_INCLUDE_DIR} + ${OPENSSL_INCLUDE_DIR} + ${VALGRIND_INCLUDE_DIR} +) + +add_executable(bnetserver + ${bnetserver_SRCS} + ${bnetserver_PCH_SRC} +) + +add_dependencies(bnetserver revision.h) + +if( NOT WIN32 ) + set_target_properties(bnetserver PROPERTIES + COMPILE_DEFINITIONS _TRINITY_BNET_CONFIG="${CONF_DIR}/bnetserver.conf" + ) +endif() + +target_link_libraries(bnetserver + shared + ${MYSQL_LIBRARY} + ${OPENSSL_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${Boost_LIBRARIES} +) + +if( WIN32 ) + if ( MSVC ) + add_custom_command(TARGET bnetserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bnetserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ + ) + elseif ( MINGW ) + add_custom_command(TARGET bnetserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/bnetserver.conf.dist ${CMAKE_BINARY_DIR}/bin/ + ) + endif() +endif() + +if( UNIX ) + install(TARGETS bnetserver DESTINATION bin) + install(FILES bnetserver.conf.dist DESTINATION ${CONF_DIR}) +elseif( WIN32 ) + install(TARGETS bnetserver DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(FILES bnetserver.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}") +endif() + +# Generate precompiled header +if (USE_COREPCH) + add_cxx_pch(bnetserver ${bnetserver_PCH_HDR} ${bnetserver_PCH_SRC}) +endif() diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp new file mode 100644 index 00000000000..cb9bab97841 --- /dev/null +++ b/src/server/bnetserver/Main.cpp @@ -0,0 +1,238 @@ +/* + * 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 main.cpp +* @brief Authentication Server main program +* +* This file contains the main program for the +* authentication server +*/ + +#include "ComponentManager.h" +#include "ModuleManager.h" +#include "SessionManager.h" +#include "Common.h" +#include "Config.h" +#include "DatabaseEnv.h" +#include "Log.h" +#include "ProcessPriority.h" +#include "RealmList.h" +#include "SystemConfig.h" +#include "Util.h" +#include +#include +#include +#include +#include +#include + +using boost::asio::ip::tcp; +using namespace boost::program_options; + +#ifndef _TRINITY_BNET_CONFIG +# define _TRINITY_BNET_CONFIG "authserver.conf" +#endif + +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); + +boost::asio::io_service _ioService; +boost::asio::deadline_timer _dbPingTimer(_ioService); +uint32 _dbPingInterval; +LoginDatabaseWorkerPool LoginDatabase; + +int main(int argc, char** argv) +{ + std::string configFile = _TRINITY_BNET_CONFIG; + auto vm = GetConsoleArguments(argc, argv, configFile); + // exit if help is enabled + if (vm.count("help")) + return 0; + + std::string configError; + if (!sConfigMgr->LoadInitial(configFile, configError)) + { + printf("Error in config file: %s\n", configError.c_str()); + return 1; + } + + TC_LOG_INFO("server.bnetserver", "%s (bnetserver)", _FULLVERSION); + TC_LOG_INFO("server.bnetserver", " to stop.\n"); + TC_LOG_INFO("server.bnetserver", "Using configuration file %s.", configFile.c_str()); + TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); + TC_LOG_INFO("server.bnetserver", "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", ""); + if (!pidFile.empty()) + { + if (uint32 pid = CreatePIDFile(pidFile)) + TC_LOG_INFO("server.bnetserver", "Daemon PID: %u\n", pid); + else + { + TC_LOG_ERROR("server.bnetserver", "Cannot create PID file %s.\n", pidFile.c_str()); + return 1; + } + } + + // Initialize the database connection + if (!StartDB()) + return 1; + + // Get the list of realms for the server + sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); + + if (sRealmList->size() == 0) + { + TC_LOG_ERROR("server.bnetserver", "No valid realms specified."); + StopDB(); + return 1; + } + + // Start the listening port (acceptor) for auth connections + int32 bnport = sConfigMgr->GetIntDefault("BattlenetPort", 1119); + if (bnport < 0 || bnport > 0xFFFF) + { + TC_LOG_ERROR("server.bnetserver", "Specified battle.net port (%d) out of allowed range (1-65535)", bnport); + StopDB(); + return 1; + } + + std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); + + sSessionMgr.StartNetwork(_ioService, bindIp, bnport); + + // Set signal handlers + boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); +#if PLATFORM == PLATFORM_WINDOWS + signals.add(SIGBREAK); +#endif + signals.async_wait(SignalHandler); + + // Set process priority according to configuration settings + SetProcessPriority("server.bnetserver"); + + // 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); + + sComponentMgr->Load(); + sModuleMgr->Load(); + + // Start the io service worker loop + _ioService.run(); + + // Close the Database Pool and library + StopDB(); + + TC_LOG_INFO("server.bnetserver", "Halting process..."); + return 0; +} + + +/// Initialize connection to the database +bool StartDB() +{ + MySQL::Library_Init(); + + std::string dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); + if (dbstring.empty()) + { + TC_LOG_ERROR("server.authserver", "Database not specified"); + return false; + } + + int32 worker_threads = sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1); + if (worker_threads < 1 || worker_threads > 32) + { + TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1."); + worker_threads = 1; + } + + int32 synch_threads = sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1); + if (synch_threads < 1 || synch_threads > 32) + { + TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1."); + synch_threads = 1; + } + + // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever. + if (!LoginDatabase.Open(dbstring, uint8(worker_threads), uint8(synch_threads))) + { + TC_LOG_ERROR("server.authserver", "Cannot connect to database"); + return false; + } + + TC_LOG_INFO("server.authserver", "Started auth database connection pool."); + sLog->SetRealmId(0); // Enables DB appenders when realm is set. + return true; +} + +/// Close the connection to the database +void StopDB() +{ + LoginDatabase.Close(); + MySQL::Library_End(); +} + +void SignalHandler(const boost::system::error_code& error, int /*signalNumber*/) +{ + if (!error) + _ioService.stop(); +} + +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(&configFile)->default_value(_TRINITY_BNET_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/bnetserver/Packets/AchievementPackets.h b/src/server/bnetserver/Packets/AchievementPackets.h new file mode 100644 index 00000000000..99a0f19d0a2 --- /dev/null +++ b/src/server/bnetserver/Packets/AchievementPackets.h @@ -0,0 +1,42 @@ +/* + * 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 AchievementPackets_h__ +#define AchievementPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Achievement + { + enum Opcode + { + CMSG_LISTEN_REQUEST = 0x0, // Not implemented + CMSG_CRITERIA_FLUSH_REQUEST = 0x3, // Not implemented + CMSG_CHANGE_TROPHY_CASE_REQUEST = 0x5, // Not implemented + + SMSG_DATA = 0x2, // Not implemented + SMSG_CRITERIA_FLUSH_RESPONSE = 0x3, // Not implemented + SMSG_ACHIEVEMENT_HANDLE_UPDATE = 0x4, // Not implemented + SMSG_CHANGE_TROPHY_CASE_RESULT = 0x6 // Not implemented + }; + } +} + +#endif // AchievementPackets_h__ + diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.cpp b/src/server/bnetserver/Packets/AuthenticationPackets.cpp new file mode 100644 index 00000000000..ae2db016972 --- /dev/null +++ b/src/server/bnetserver/Packets/AuthenticationPackets.cpp @@ -0,0 +1,319 @@ +/* + * 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 "AuthenticationPackets.h" +#include "Util.h" + +void Battlenet::Authentication::LogonRequest::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read(32); + } + + if (_stream.Read(1)) + Login = _stream.ReadString(9, 3); +} + +std::string Battlenet::Authentication::LogonRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::LogonRequest Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (Component const& component : Components) + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + + if (!Login.empty()) + stream << std::endl << "Battlenet::Authentication::LogonRequest Login: " << Login; + + return stream.str(); +} + +void Battlenet::Authentication::LogonRequest::CallHandler(Session* session) const +{ + session->HandleLogonRequest(*this); +} + +void Battlenet::Authentication::ResumeRequest::Read() +{ + Program = _stream.ReadFourCC(); + Platform = _stream.ReadFourCC(); + Locale = _stream.ReadFourCC(); + + Components.resize(_stream.Read(6)); + for (size_t i = 0; i < Components.size(); ++i) + { + Component& component = Components[i]; + component.Program = _stream.ReadFourCC(); + component.Platform = _stream.ReadFourCC(); + component.Build = _stream.Read(32); + } + + Login = _stream.ReadString(9, 3); + Region = _stream.Read(8); + GameAccountName = _stream.ReadString(5, 1); +} + +std::string Battlenet::Authentication::ResumeRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::ResumeRequest Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale; + for (Component const& component : Components) + stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build; + + stream << std::endl << "Login: " << Login; + stream << std::endl << "Region: " << uint32(Region); + stream << std::endl << "GameAccountName: " << GameAccountName; + + return stream.str(); +} + +void Battlenet::Authentication::ResumeRequest::CallHandler(Session* session) const +{ + session->HandleResumeRequest(*this); +} + +Battlenet::Authentication::ProofRequest::~ProofRequest() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + +void Battlenet::Authentication::ProofRequest::Write() +{ + _stream.Write(Modules.size(), 3); + for (ModuleInfo const* info : Modules) + { + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } +} + +std::string Battlenet::Authentication::ProofRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::ProofRequest modules " << Modules.size(); + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +Battlenet::Authentication::ProofResponse::~ProofResponse() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + +void Battlenet::Authentication::ProofResponse::Read() +{ + Modules.resize(_stream.Read(3)); + for (size_t i = 0; i < Modules.size(); ++i) + { + BitStream*& dataStream = Modules[i]; + dataStream = new BitStream(_stream.Read(10)); + memcpy(dataStream->GetBuffer(), _stream.ReadBytes(dataStream->GetSize()).get(), dataStream->GetSize()); + } +} + +std::string Battlenet::Authentication::ProofResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::ProofResponse Modules " << Modules.size(); + for (BitStream* module : Modules) + { + std::string hexStr = ByteArrayToHexStr(module->GetBuffer(), module->GetSize()); + stream << std::endl << "Battlenet::Authentication::ProofResponse::ModuleData Size: " << module->GetSize() << ", Data: " << hexStr; + } + + return stream.str(); +} + +void Battlenet::Authentication::ProofResponse::CallHandler(Session* session) const +{ + session->HandleProofResponse(*this); +} + +Battlenet::Authentication::LogonResponse::~LogonResponse() +{ + for (ModuleInfo* m : Modules) + delete m; +} + +void Battlenet::Authentication::LogonResponse::Write() +{ + _stream.Write(Result.ResultValue != ResponseFailure::UPDATE, 1); + if (Result.ResultValue == ResponseFailure::UPDATE) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } + + _stream.Write(PingTimeout + std::numeric_limits::min(), 32); + _stream.Write(1, 1); // RegulatorRules != NULL (not a pointer for us, always write) + // if written == 1 + { + _stream.Write(RegulatorRules.Type == Regulator::LEAKY_BUCKET, 1); + if (RegulatorRules.Type == Regulator::LEAKY_BUCKET) + { + _stream.Write(RegulatorRules.Threshold, 32); + _stream.Write(RegulatorRules.Rate, 32); + } + } + + _stream.WriteString(FirstName, 8); // First name + _stream.WriteString(LastName, 8); // Last name - not set for WoW + + _stream.Write(AccountId, 32); + _stream.Write(Region, 8); + _stream.Write(Flags, 64); + + _stream.Write(GameAccountRegion, 8); + _stream.WriteString(GameAccountName, 5, -1); + _stream.Write(GameAccountFlags, 64); + + _stream.Write(FailedLogins, 32); + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + } + + _stream.Write(Result.ResultValue, 2); + if (Result.ResultValue == ResponseFailure::FAILURE) + { + _stream.Write(Result.Error, 16); + _stream.Write(Result.Wait + std::numeric_limits::min(), 32); + } + } +} + +std::string Battlenet::Authentication::LogonResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::LogonResponse AuthResult " << Result.Error << " PingTimeout " << PingTimeout + << " RegulatorRules.Threshold " << RegulatorRules.Threshold << " RegulatorRules.Rate " << RegulatorRules.Rate + << " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName + << " GameAccountFlags " << GameAccountFlags << " FailedLogins " << FailedLogins << " Modules " << Modules.size(); + + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +void Battlenet::Authentication::LogonResponse::SetAuthResult(AuthResult result) +{ + Result.ResultValue = result != AUTH_OK ? ResponseFailure::FAILURE : ResponseFailure::UPDATE; + Result.Error = result; +} + +Battlenet::Authentication::ResumeResponse::~ResumeResponse() +{ + for (ModuleInfo* m : Modules) + delete m; +} + +void Battlenet::Authentication::ResumeResponse::Write() +{ + _stream.Write(Result.ResultValue != ResponseFailure::UPDATE, 1); + if (Result.ResultValue == ResponseFailure::UPDATE) + { + _stream.Write(Modules.size(), 3); + for (size_t i = 0; i < Modules.size(); ++i) + { + ModuleInfo* info = Modules[i]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.Write(info->DataSize, 10); + _stream.WriteBytes(info->Data, info->DataSize); + } + + _stream.Write(PingTimeout + std::numeric_limits::min(), 32); + _stream.Write(1, 1); // RegulatorRules != NULL (not a pointer for us, always write) + // if written == 1 + { + _stream.Write(RegulatorRules.Type == Regulator::LEAKY_BUCKET, 1); + if (RegulatorRules.Type == Regulator::LEAKY_BUCKET) + { + _stream.Write(RegulatorRules.Threshold, 32); + _stream.Write(RegulatorRules.Rate, 32); + } + } + } + else + { + _stream.Write(!Modules.empty(), 1); + if (!Modules.empty()) + { + ModuleInfo* info = Modules[0]; + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + } + + _stream.Write(Result.ResultValue, 2); + if (Result.ResultValue == ResponseFailure::FAILURE) + { + _stream.Write(Result.Error, 16); + _stream.Write(Result.Wait + std::numeric_limits::min(), 32); + } + } +} + +std::string Battlenet::Authentication::ResumeResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Authentication::ResumeResponse AuthResult " << Result.Error << " PingTimeout " << PingTimeout + << " RegulatorRules.Threshold " << RegulatorRules.Threshold << " RegulatorRules.Rate " << RegulatorRules.Rate + << " Modules " << Modules.size(); + + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} + +void Battlenet::Authentication::ResumeResponse::SetAuthResult(AuthResult result) +{ + Result.ResultValue = result != AUTH_OK ? ResponseFailure::FAILURE : ResponseFailure::UPDATE; + Result.Error = result; +} diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.h b/src/server/bnetserver/Packets/AuthenticationPackets.h new file mode 100644 index 00000000000..8003e13db24 --- /dev/null +++ b/src/server/bnetserver/Packets/AuthenticationPackets.h @@ -0,0 +1,196 @@ +/* + * 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 AuthenticationPackets_h__ +#define AuthenticationPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Authentication + { + enum Opcode + { + CMSG_LOGON_REQUEST = 0x0, + CMSG_RESUME_REQUEST = 0x1, + CMSG_PROOF_RESPONSE = 0x2, + + SMSG_LOGON_RESPONSE = 0x0, + SMSG_RESUME_RESPONSE = 0x1, + SMSG_PROOF_REQUEST = 0x2, + SMSG_PATCH = 0x3, // Not implemented + SMSG_AUTHORIZED_LICENSES = 0x4 // Not implemented + }; + + class LogonRequest final : public ClientPacket + { + public: + LogonRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_LOGON_REQUEST, AUTHENTICATION) && "Invalid packet header for LogonRequest"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector Components; + std::string Login; + }; + + class ResumeRequest final : public ClientPacket + { + public: + ResumeRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_RESUME_REQUEST, AUTHENTICATION) && "Invalid packet header for ResumeRequest"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + std::string Program; + std::string Platform; + std::string Locale; + std::vector Components; + std::string Login; + uint8 Region; + std::string GameAccountName; + }; + + class ProofResponse final : public ClientPacket + { + public: + ProofResponse(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_PROOF_RESPONSE, AUTHENTICATION) && "Invalid packet header for ProofResponse"); + } + + ~ProofResponse(); + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + std::vector Modules; + }; + + class ProofRequest final : public ServerPacket + { + public: + ProofRequest() : ServerPacket(PacketHeader(SMSG_PROOF_REQUEST, AUTHENTICATION)) { } + ~ProofRequest(); + + void Write() override; + std::string ToString() const override; + + std::vector Modules; + }; + + class ResponseFailure + { + public: + enum Result + { + UPDATE = 0, + FAILURE = 1, + VERSION_CHECK_DISCONNECT = 2 + }; + + ResponseFailure() : ResultValue(UPDATE), Error(AUTH_OK), Wait(0) { } + + Result ResultValue; + AuthResult Error; + int32 Wait; + }; + + class Regulator + { + public: + enum Info + { + NONE = 0, + LEAKY_BUCKET = 1 + }; + + Regulator() : Type(LEAKY_BUCKET), Threshold(25000000), Rate(1000) { } + + Info Type; + uint32 Threshold; + uint32 Rate; + }; + + class LogonResponse final : public ServerPacket + { + public: + LogonResponse() : ServerPacket(PacketHeader(SMSG_LOGON_RESPONSE, AUTHENTICATION)), + PingTimeout(120000), FirstName(""), LastName(""), AccountId(0), Region(2), Flags(0), + GameAccountRegion(2), GameAccountName(""), FailedLogins(0) + { + } + + ~LogonResponse(); + + void Write() override; + std::string ToString() const override; + + std::vector Modules; + void SetAuthResult(AuthResult result); + ResponseFailure Result; + + int32 PingTimeout; + Regulator RegulatorRules; + std::string FirstName; + std::string LastName; + uint32 AccountId; + uint8 Region; + uint64 Flags; + uint8 GameAccountRegion; + std::string GameAccountName; + uint64 GameAccountFlags; + + uint32 FailedLogins; + }; + + class ResumeResponse final : public ServerPacket + { + public: + ResumeResponse() : ServerPacket(PacketHeader(SMSG_RESUME_RESPONSE, AUTHENTICATION)), PingTimeout(120000) + { + } + + ~ResumeResponse(); + + void Write() override; + std::string ToString() const override; + + std::vector Modules; + void SetAuthResult(AuthResult result); + ResponseFailure Result; + + int32 PingTimeout; + Regulator RegulatorRules; + }; + } +} + +#endif // AuthenticationPackets_h__ diff --git a/src/server/bnetserver/Packets/BitStream.cpp b/src/server/bnetserver/Packets/BitStream.cpp new file mode 100644 index 00000000000..5f002f6b1d9 --- /dev/null +++ b/src/server/bnetserver/Packets/BitStream.cpp @@ -0,0 +1,30 @@ +/* + * 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 "BitStream.h" + +template<> +bool Battlenet::BitStream::Read(uint32 /*bitCount*/) +{ + return Read(1) != 0; +} + +template<> +void Battlenet::BitStream::Write(bool value, uint32 /*bitCount*/) +{ + Write(value ? 1 : 0, 1); +} diff --git a/src/server/bnetserver/Packets/BitStream.h b/src/server/bnetserver/Packets/BitStream.h new file mode 100644 index 00000000000..952ec5a39e2 --- /dev/null +++ b/src/server/bnetserver/Packets/BitStream.h @@ -0,0 +1,243 @@ +/* + * 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 BitStream_h__ +#define BitStream_h__ + +#include "Common.h" +#include "ByteConverter.h" +#include "MessageBuffer.h" +#include +#include +#include +#include + +namespace Battlenet +{ + class BitStreamPositionException : public std::exception + { + static uint32 const MessageSize = 128; + + public: + BitStreamPositionException(bool read, uint32 operationSize, uint32 position, uint32 streamSize) + { + memset(_message, 0, MessageSize); + snprintf(_message, MessageSize, "Attempted to %s more bits (%u) %s stream than %s (%u)\n", + (read ? "read" : "write"), + operationSize + position, + (read ? "from" : "to"), + (read ? "exist" : "allowed"), + streamSize); + } + + char const* what() const throw() + { + return _message; + } + + private: + char _message[MessageSize]; + }; + + class BitStream + { + public: + static uint32 const MaxSize = 0x4000; + + // length : The maximum number of bytes to read + BitStream(uint32 length) : _writePos(length * 8), _readPos(0) + { + _buffer.resize(length, 0); + } + + BitStream(MessageBuffer&& buffer) : _writePos(buffer.GetActiveSize() * 8), _readPos(0), _buffer(buffer.Move()) + { + } + + BitStream() : _writePos(0), _readPos(0) + { + _buffer.reserve(0x1000); + } + + void AlignToNextByte() + { + _readPos = (_readPos + 7) & ~7; + _writePos = (_writePos + 7) & ~7; + } + + std::string ReadString(uint32 bitCount, int32 baseLength = 0) + { + uint32 len = Read(bitCount) + baseLength; + AlignToNextByte(); + std::string str(reinterpret_cast(&_buffer[_readPos >> 3]), len); + _readPos += len * 8; + return str; + } + + std::unique_ptr ReadBytes(uint32 count) + { + AlignToNextByte(); + if (_readPos + count * 8 > _writePos) + throw BitStreamPositionException(true, count * 8, _readPos, _writePos); + + std::unique_ptr buf(new uint8[count]); + memcpy(buf.get(), &_buffer[_readPos >> 3], count); + _readPos += count * 8; + return buf; + } + + float ReadFloat() + { + uint32 val = Read(32); + return *reinterpret_cast(&val); + } + + std::string ReadFourCC() + { + uint32 fcc = Read(32); + EndianConvertReverse(fcc); + size_t len = 4; + while (!(fcc & 0xFF)) + { + fcc >>= 8; + --len; + } + + return std::string(reinterpret_cast(&fcc), len); + } + + template + T Read(uint32 bitCount) + { + static_assert(std::is_integral::value || std::is_enum::value, "T must be an integer type"); + + if (_readPos + bitCount > _writePos) + throw BitStreamPositionException(true, bitCount, _readPos, _writePos); + + uint64 ret = 0; + while (bitCount != 0) + { + uint32 bitPos = (_readPos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + ret |= (uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount; + _readPos += bitsLeftInByte; + } + + return static_cast(ret); + } + + void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0) + { + Write(str.length() + baseLength, bitCount); + WriteBytes(str.c_str(), str.length()); + } + + template + void WriteBytes(T* data, uint32 count) + { + AlignToNextByte(); + if (!count || !data) + return; + + if ((_writePos >> 3) + count > MaxSize) + throw BitStreamPositionException(false, count * 8, _writePos, MaxSize * 8); + + _buffer.resize(_buffer.size() + count); + memcpy(&_buffer[_writePos >> 3], data, count); + _writePos += count * 8; + } + + void WriteFloat(float value) + { + uint32 intVal = *reinterpret_cast(&value); + Write(intVal, 32); + } + + void WriteFourCC(std::string const& fcc) + { + uint32 intVal = *(uint32*)fcc.c_str(); + size_t len = fcc.length(); + EndianConvertReverse(intVal); + // Add padding + while (len++ < 4) + intVal >>= 8; + + Write(intVal, 32); + } + + template + void Write(T value, uint32 bitCount) + { + static_assert(std::is_integral::value || std::is_enum::value, "T must be an integer type"); + + if (_writePos + bitCount > 8 * MaxSize) + throw BitStreamPositionException(false, bitCount, _writePos, MaxSize * 8); + + while (bitCount != 0) + { + uint32 bitPos = (_writePos & 7); + uint32 bitsLeftInByte = 8 - bitPos; + if (bitsLeftInByte >= bitCount) + bitsLeftInByte = bitCount; + + bitCount -= bitsLeftInByte; + + uint8 firstHalf = (uint8)(~(((uint8)(1 << bitsLeftInByte) - 1) << bitPos)); + uint8 secondHalf = (uint8)((((uint8)(1 << bitsLeftInByte) - 1) & (uint8)(value >> bitCount)) << bitPos); + + if (_buffer.size() > (_writePos >> 3)) + _buffer[_writePos >> 3] = (uint8)((_buffer[_writePos >> 3] & firstHalf) | secondHalf); + else + _buffer.push_back(secondHalf); + + _writePos += bitsLeftInByte; + } + } + + void SetReadPos(uint32 bits) + { + if (bits > _writePos) + throw BitStreamPositionException(true, bits, 0, _writePos); + + _readPos = bits; + } + + bool IsRead() const { return _readPos >= _writePos; } + + uint8* GetBuffer() { return _buffer.data(); } + uint8 const* GetBuffer() const { return _buffer.data(); } + + size_t GetSize() const { return ((_writePos + 7) & ~7) / 8; } + + private: + uint32 _writePos; + uint32 _readPos; + std::vector _buffer; + }; + + template<> + bool BitStream::Read(uint32 bitCount); + + template<> + void BitStream::Write(bool value, uint32 bitCount); +} + +#endif // BitStream_h__ diff --git a/src/server/bnetserver/Packets/CachePackets.h b/src/server/bnetserver/Packets/CachePackets.h new file mode 100644 index 00000000000..2e473df4e72 --- /dev/null +++ b/src/server/bnetserver/Packets/CachePackets.h @@ -0,0 +1,43 @@ +/* + * 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 CachePackets_h__ +#define CachePackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Cache + { + enum Opcode + { + CMSG_GATEWAY_LOOKUP_REQUEST = 0x2, // Not implemented + CMSG_CONNECT_REQUEST = 0x4, // Not implemented + CMSG_DATA_CHUNK = 0x7, // Not implemented + SMSG_GET_STREAM_ITEMS_REQUEST = 0x9, // Not implemented + + SMSG_GATEWAY_LOOKUP_RESPONSE = 0x3, // Not implemented + SMSG_CONNECT_RESPONSE = 0x4, // Not implemented + SMSG_PUBLISH_LIST_RESPONSE = 0x7, // Not implemented + SMSG_RESULT = 0x8, // Not implemented + SMSG_GET_STREAM_ITEMS_RESPONSE = 0x9 // Not implemented + }; + } +} + +#endif // CachePackets_h__ diff --git a/src/server/bnetserver/Packets/ChatPackets.h b/src/server/bnetserver/Packets/ChatPackets.h new file mode 100644 index 00000000000..fc4b638754c --- /dev/null +++ b/src/server/bnetserver/Packets/ChatPackets.h @@ -0,0 +1,63 @@ +/* + * 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 ChatPackets_h__ +#define ChatPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Chat + { + enum Opcode + { + CMSG_JOIN_REQUEST_2 = 0x00, // Not implemented + CMSG_LEAVE_REQUEST = 0x02, // Not implemented + CMSG_INVITE_REQUEST = 0x03, // Not implemented + CMSG_CREATE_AND_INVITE_REQUEST = 0x0A, // Not implemented + CMSG_MESSAGE_SEND = 0x0B, // Not implemented + CMSG_DATAGRAM_CONNECTION_UPDATE = 0x0D, // Not implemented + CMSG_REPORT_SPAM_REQUEST = 0x0E, // Not implemented + CMSG_WHISPER_SEND = 0x13, // Not implemented + CMSG_ENUM_CATEGORY_DESCRIPTIONS = 0x15, // Not implemented + CMSG_ENUM_CONFERENCE_DESCRIPTIONS = 0x17, // Not implemented + CMSG_ENUM_CONFERENCE_MEMBER_COUNTS = 0x19, // Not implemented + CMSG_MODIFY_CHANNEL_LIST_REQUEST = 0x1B, // Not implemented + + SMSG_MEMBERSHIP_CHANGE_NOTIFY = 0x01, // Not implemented + SMSG_INVITE_NOTIFY = 0x04, // Not implemented + SMSG_INVITE_CANCELED = 0x07, // Not implemented + SMSG_MESSAGE_RECV = 0x0B, // Not implemented + SMSG_MESSAGE_UNDELIVERABLE = 0x0C, // Not implemented + SMSG_DATAGRAM_CONNECTION_UPDATE = 0x0D, // Not implemented + SMSG_INVITE_FAILURE = 0x0F, // Not implemented + SMSG_SYSTEM_MESSAGE = 0x10, // Not implemented + SMSG_MESSAGE_BLOCKED = 0x12, // Not implemented + SMSG_WHISPER_RECV = 0x13, // Not implemented + SMSG_WHISPER_UNDELIVERABLE = 0x14, // Not implemented + SMSG_CATEGORY_DESCRIPTIONS = 0x16, // Not implemented + SMSG_CONFERENCE_DESCRIPTIONS = 0x18, // Not implemented + SMSG_CONFERENCE_MEMBER_COUNTS = 0x1A, // Not implemented + SMSG_JOIN_NOTIFY_2 = 0x1B, // Not implemented + SMSG_MODIFY_CHANNEL_LIST_RESPONSE = 0x1C, // Not implemented + SMSG_CONFIG_CHANGED = 0x1D // Not implemented + }; + } +} + +#endif // ChatPackets_h__ diff --git a/src/server/bnetserver/Packets/ConnectionPackets.cpp b/src/server/bnetserver/Packets/ConnectionPackets.cpp new file mode 100644 index 00000000000..0449ecbb756 --- /dev/null +++ b/src/server/bnetserver/Packets/ConnectionPackets.cpp @@ -0,0 +1,54 @@ +/* + * 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 "Session.h" +#include "ConnectionPackets.h" + +std::string Battlenet::Connection::Ping::ToString() const +{ + return "Battlenet::Connection::Ping"; +} + +void Battlenet::Connection::Ping::CallHandler(Session* session) const +{ + session->HandlePing(*this); +} + +std::string Battlenet::Connection::EnableEncryption::ToString() const +{ + return "Battlenet::Connection::EnableEncryption"; +} + +void Battlenet::Connection::EnableEncryption::CallHandler(Session* session) const +{ + session->HandleEnableEncryption(*this); +} + +std::string Battlenet::Connection::LogoutRequest::ToString() const +{ + return "Battlenet::Connection::LogoutRequest"; +} + +void Battlenet::Connection::LogoutRequest::CallHandler(Session* session) const +{ + session->HandleLogoutRequest(*this); +} + +std::string Battlenet::Connection::Pong::ToString() const +{ + return "Battlenet::Connection::Pong"; +} diff --git a/src/server/bnetserver/Packets/ConnectionPackets.h b/src/server/bnetserver/Packets/ConnectionPackets.h new file mode 100644 index 00000000000..f3fa4852d07 --- /dev/null +++ b/src/server/bnetserver/Packets/ConnectionPackets.h @@ -0,0 +1,94 @@ +/* + * 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 ConnectionPackets_h__ +#define ConnectionPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Connection + { + enum Opcode + { + CMSG_PING = 0x0, + CMSG_ENABLE_ENCRYPTION = 0x5, + CMSG_LOGOUT_REQUEST = 0x6, + CMSG_DISCONNECT_REQUEST = 0x7, // Not implemented + CMSG_CONNECTION_CLOSING = 0x9, // Not implemented + + SMSG_PONG = 0x0, + SMSG_BOOM = 0x1, // Not implemented + SMSG_REGULATOR_UPDATE = 0x2, // Not implemented + SMSG_SERVER_VERSION = 0x3, // Not implemented + SMSG_STUN_SERVERS = 0x4 // Not implemented + }; + + class Ping final : public ClientPacket + { + public: + Ping(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_PING, CONNECTION) && "Invalid packet header for Ping"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class EnableEncryption final : public ClientPacket + { + public: + EnableEncryption(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_ENABLE_ENCRYPTION, CONNECTION) && "Invalid packet header for EnableEncryption"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class LogoutRequest final : public ClientPacket + { + public: + LogoutRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_LOGOUT_REQUEST, CONNECTION) && "Invalid packet header for LogoutRequest"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class Pong final : public ServerPacket + { + public: + Pong() : ServerPacket(PacketHeader(SMSG_PONG, CONNECTION)) + { + } + + void Write() override { } + std::string ToString() const override; + }; + } +} + +#endif // ConnectionPackets_h__ diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp new file mode 100644 index 00000000000..784d6980777 --- /dev/null +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -0,0 +1,179 @@ +/* + * 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 "Session.h" +#include "FriendsPackets.h" + +void Battlenet::Friends::SocialnetworkCheckConnected::Read() +{ + SocialNetworkId = _stream.Read(32); +} + +std::string Battlenet::Friends::SocialnetworkCheckConnected::ToString() const +{ + return "Battlenet::Friends::SocialnetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); +} + +void Battlenet::Friends::SocialnetworkCheckConnected::CallHandler(Session* session) const +{ + SocialNetworkCheckConnectedResult* result = new SocialNetworkCheckConnectedResult(SocialNetworkId); + session->AsyncWrite(result); +} + +void Battlenet::Friends::SocialnetworkConnect::Read() +{ + int32 unk1 = _stream.Read(32); + uint32 size1 = _stream.Read(9); + auto data1 = _stream.ReadBytes(size1); + uint32 size2 = _stream.Read(7); + auto data2 = _stream.ReadBytes(size2); +} + +std::string Battlenet::Friends::SocialnetworkConnect::ToString() const +{ + return "Battlenet::Friends::SocialnetworkConnect"; +} + +void Battlenet::Friends::SocialnetworkConnect::CallHandler(Session* session) const +{ + session->LogUnhandledPacket(*this); +} + +std::string Battlenet::Friends::SocialNetworkConnectResult::ToString() const +{ + return "Battlenet::Friends::SocialNetworkConnectResult"; +} + +void Battlenet::Friends::SocialNetworkConnectResult::Write() +{ +} + +std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() const +{ + return "Battlenet::Friends::SocialNetworkCheckConnectedResult"; +} + +void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() +{ + _stream.Write(0, 23); // Ignored + volatile uint16 res = 0; + _stream.Write(res, 16); // Unknown + _stream.Write(SocialNetworkId, 32); +} + +void Battlenet::Friends::GetFriendsOfFriend::Read() +{ + uint8 unk = _stream.Read(2); + uint32 unk1 = _stream.Read(32); +} + +std::string Battlenet::Friends::GetFriendsOfFriend::ToString() const +{ + return "Battlenet::Friends::GetFriendsOfFriend"; +} + +void Battlenet::Friends::GetFriendsOfFriend::CallHandler(Session* session) const +{ + session->LogUnhandledPacket(*this); +} + +void Battlenet::Friends::RealIdFriendInvite::Read() +{ + _stream.Read(32); + uint8 type = _stream.Read(3); + + switch (type) + { + case 0: + { + _stream.Read(32); // Presence Id? + break; + } + case 1: // GameAccount? + { + _stream.Read(8); + _stream.Read(32); + _stream.Read(32); + uint8 size = _stream.Read(7); // Only if *(a1 + 16) <= 0x64 + _stream.ReadBytes(size); + break; + } + case 2: + Email = _stream.ReadString(9, 3); + break; + case 3: + { + _stream.Read(32); + break; + } + case 4: + { + _stream.Read(64); + _stream.Read(32); + break; + } + } + + _stream.Read(1); + + if (_stream.Read(1)) + Message = _stream.ReadString(9); + + _stream.Read(32); +} + +std::string Battlenet::Friends::RealIdFriendInvite::ToString() const +{ + return "Battlenet::Friends::RealIdFriendInvite Mail: " + Email + " Message: " + Message; +} + +void Battlenet::Friends::RealIdFriendInvite::CallHandler(Session* session) const +{ + FriendInviteResult* result = new FriendInviteResult(); + session->AsyncWrite(result); +} + +std::string Battlenet::Friends::FriendInviteResult::ToString() const +{ + return "Battlenet::Friends::RealIdFriendInviteResult"; +} + +void Battlenet::Friends::FriendInviteResult::Write() +{ + bool hasNames = false; + _stream.Write(hasNames, 1); + if (hasNames) + { + _stream.WriteString("Testing1", 8); + _stream.WriteString("Testing2", 8); + } + _stream.Write(5, 32); + + _stream.Write(0, 0xC); // Ignored + + _stream.Write(1, 16); + + bool moreInfo = true; + _stream.Write(moreInfo, 1); + if (moreInfo) + { + _stream.Write(0, 8); + _stream.Write(4, 32); + _stream.Write(3, 32); + _stream.WriteString("Testing3", 7, 2); + } +} diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h new file mode 100644 index 00000000000..a0ef6f4a63f --- /dev/null +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -0,0 +1,162 @@ +/* + * 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 FriendsPackets_h__ +#define FriendsPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Friends + { + enum Opcode + { + CMSG_FRIEND_INVITE = 0x01, // Not implemented + CMSG_FRIEND_INVITE_RESPONSE = 0x02, // Not implemented + CMSG_FRIEND_REMOVE = 0x04, // Not implemented + CMSG_FRIEND_NOTE = 0x05, // Not implemented + CMSG_TOONS_OF_FRIEND_REQUEST = 0x06, // Not implemented + CMSG_BLOCK_ADD = 0x08, // Not implemented + CMSG_BLOCK_REMOVE = 0x0A, // Not implemented + CMSG_GET_FRIENDS_OF_FRIEND = 0x0B, // Not implemented + CMSG_GET_SOCIAL_NETWORK_FRIENDS = 0x0D, // Not implemented + CMSG_SOCIAL_NETWORK_CONNECT = 0x0F, // Not implemented + CMSG_SOCIAL_NETWORK_DISCONNECT = 0x11, // Not implemented + CMSG_SOCIAL_NETWORK_CHECK_CONNECTED = 0x13, + CMSG_REALID_FRIEND_INVITE = 0x16, // Not implemented + + SMSG_FRIEND_INVITE_NOTIFY = 0x01, // Not implemented + SMSG_FRIEND_INVITE_RESULT = 0x03, // Not implemented + SMSG_TOONS_OF_FRIEND_NOTIFY = 0x06, // Not implemented + SMSG_BLOCK_INVITE_NOTIFY = 0x07, // Not implemented + SMSG_BLOCK_ADD_FAILURE = 0x09, // Not implemented + SMSG_FRIENDS_OF_FRIEND = 0x0C, // Not implemented + SMSG_SOCIAL_NETWORK_FRIENDS = 0x0E, // Not implemented + SMSG_SOCIAL_NETWORK_CONNECT_RESULT = 0x10, // Not implemented + SMSG_SOCIAL_NETWORK_DISCONNECT_RESULT = 0x12, // Not implemented + SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT = 0x14, + SMSG_MAX_FRIENDS_NOTIFY = 0x15, // Not implemented + SMSG_FRIENDS_LIST_NOTIFY_3 = 0x18 // Not implemented + }; + + class SocialnetworkConnect final : public ClientPacket + { + public: + SocialnetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialnetworkConnect"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class SocialNetworkConnectResult final : public ServerPacket + { + public: + SocialNetworkConnectResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CONNECT_RESULT, FRIENDS)) + { + } + + void Write() override; + std::string ToString() const override; + }; + + class SocialnetworkCheckConnected final : public ClientPacket + { + public: + SocialnetworkCheckConnected(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS) && "Invalid packet header for SocialNetworkCheckConnected"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + uint32 SocialNetworkId; + }; + + class SocialNetworkCheckConnectedResult final : public ServerPacket + { + public: + SocialNetworkCheckConnectedResult(uint32 socialNetworkId) : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), SocialNetworkId(socialNetworkId) + { + } + + void Write() override; + std::string ToString() const override; + + uint32 SocialNetworkId; + }; + + class GetFriendsOfFriend final : public ClientPacket + { + public: + GetFriendsOfFriend(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS) && "Invalid packet header for GetFriendsOfFriend"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class FriendsOfFriend final : public ServerPacket + { + public: + FriendsOfFriend() : ServerPacket(PacketHeader(SMSG_FRIENDS_OF_FRIEND, FRIENDS)) + { + } + + void Write() override; + std::string ToString() const override; + }; + + class RealIdFriendInvite final : public ClientPacket + { + public: + RealIdFriendInvite(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_REALID_FRIEND_INVITE, FRIENDS) && "Invalid packet header for RealIdFriendInvite"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + std::string Email; + std::string Message; + }; + + class FriendInviteResult final : public ServerPacket + { + public: + FriendInviteResult() : ServerPacket(PacketHeader(SMSG_FRIEND_INVITE_RESULT, FRIENDS)) + { + } + + void Write() override; + std::string ToString() const override; + }; + } +} + +#endif // FriendsPackets_h__ diff --git a/src/server/bnetserver/Packets/PacketFactory.h b/src/server/bnetserver/Packets/PacketFactory.h new file mode 100644 index 00000000000..4ae6338cfd7 --- /dev/null +++ b/src/server/bnetserver/Packets/PacketFactory.h @@ -0,0 +1,83 @@ +/* + * 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 PacketFactory_h__ +#define PacketFactory_h__ + +#include "Packets.h" +#include + +namespace Battlenet +{ + class PacketFactory + { + typedef ClientPacket*(*PacketCreateFn)(PacketHeader const& header, BitStream& stream); + + public: + ClientPacket* Create(PacketHeader const& header, BitStream& stream) + { + auto creator = _creators.find(header); + if (creator == _creators.end()) + return nullptr; + + ClientPacket* packet = creator->second(header, stream); + packet->Read(); + return packet; + } + + static PacketFactory& Instance() + { + static PacketFactory instance; + return instance; + } + + private: + PacketFactory() + { + _creators[PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION)] = &New; + _creators[PacketHeader(Authentication::CMSG_RESUME_REQUEST, AUTHENTICATION)] = &New; + _creators[PacketHeader(Authentication::CMSG_PROOF_RESPONSE, AUTHENTICATION)] = &New; + + _creators[PacketHeader(Connection::CMSG_PING, CONNECTION)] = &New; + _creators[PacketHeader(Connection::CMSG_ENABLE_ENCRYPTION, CONNECTION)] = &New; + _creators[PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION)] = &New; + + _creators[PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM)] = &New; + _creators[PacketHeader(WoWRealm::CMSG_JOIN_REQUEST_V2, WOWREALM)] = &New; + + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New; + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New; + _creators[PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS)] = &New; + _creators[PacketHeader(Friends::CMSG_REALID_FRIEND_INVITE, FRIENDS)] = &New; + + _creators[PacketHeader(Presence::CMSG_UPDATE_REQUEST, PRESENCE)] = &New; + _creators[PacketHeader(Presence::CMSG_STATISTIC_SUBSCRIBE, PRESENCE)] = &New; + } + + template + static ClientPacket* New(PacketHeader const& header, BitStream& stream) + { + return new PacketType(header, stream); + } + + std::map _creators; + }; +} + +#define sPacketFactory Battlenet::PacketFactory::Instance() + +#endif // PacketFactory_h__ diff --git a/src/server/bnetserver/Packets/Packets.h b/src/server/bnetserver/Packets/Packets.h new file mode 100644 index 00000000000..f62ba6f65cd --- /dev/null +++ b/src/server/bnetserver/Packets/Packets.h @@ -0,0 +1,32 @@ +/* + * 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 Packets_h__ +#define Packets_h__ + +#include "AuthenticationPackets.h" +#include "ConnectionPackets.h" +#include "WoWRealmPackets.h" +#include "FriendsPackets.h" +#include "PresencePackets.h" +#include "ChatPackets.h" +#include "SupportPackets.h" +#include "AchievementPackets.h" +#include "CachePackets.h" +#include "ProfilePackets.h" + +#endif // Packets_h__ diff --git a/src/server/bnetserver/Packets/PacketsBase.cpp b/src/server/bnetserver/Packets/PacketsBase.cpp new file mode 100644 index 00000000000..6471337060c --- /dev/null +++ b/src/server/bnetserver/Packets/PacketsBase.cpp @@ -0,0 +1,38 @@ +/* + * 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 "Packets.h" +#include + +std::string Battlenet::PacketHeader::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::PacketHeader opcode: " << Opcode << ", channel: " << Channel; + return stream.str(); +} + +Battlenet::ServerPacket::ServerPacket(PacketHeader const& header) : Packet(header, *new BitStream()) +{ + _stream.Write(header.Opcode, 6); + _stream.Write(1, 1); + _stream.Write(header.Channel, 4); +} + +Battlenet::ServerPacket::~ServerPacket() +{ + delete &_stream; +} diff --git a/src/server/bnetserver/Packets/PacketsBase.h b/src/server/bnetserver/Packets/PacketsBase.h new file mode 100644 index 00000000000..839a10548e9 --- /dev/null +++ b/src/server/bnetserver/Packets/PacketsBase.h @@ -0,0 +1,120 @@ +/* + * 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 PacketsBase_h__ +#define PacketsBase_h__ + +#include "AuthCodes.h" +#include "BitStream.h" +#include "Define.h" +#include "Errors.h" +#include +#include + +using boost::asio::ip::tcp; + +namespace Battlenet +{ + class BitStream; + class Session; + + enum Channel + { + AUTHENTICATION = 0, + CONNECTION = 1, + WOWREALM = 2, + FRIENDS = 3, + PRESENCE = 4, + CHAT = 5, + SUPPORT = 7, + ACHIEVEMENT = 8, + CACHE = 11, + PROFILE = 14 + }; + + struct PacketHeader + { + PacketHeader(uint32 opcode, uint32 channel) : Opcode(opcode), Channel(channel) { } + PacketHeader() : Opcode(0), Channel(AUTHENTICATION) { } + + uint32 Opcode; + int32 Channel; + + bool operator<(PacketHeader const& right) const + { + if (Opcode < right.Opcode) + return true; + if (Opcode > right.Opcode) + return false; + + return Channel < right.Channel; + } + + bool operator==(PacketHeader const& right) const + { + return Opcode == right.Opcode && Channel == right.Channel; + } + + std::string ToString() const; + }; + + class Packet + { + public: + Packet(PacketHeader const& header, BitStream& stream) : _header(header), _stream(stream) { } + virtual ~Packet() { } + + PacketHeader const& GetHeader() const { return _header; } + + virtual void Write() = 0; + virtual void Read() = 0; + + virtual std::string ToString() const = 0; + + protected: + PacketHeader _header; + BitStream& _stream; + + private: + Packet(Packet const& right); + Packet& operator=(Packet const& right); + }; + + class ClientPacket : public Packet + { + public: + ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } + + void Write() override final { ASSERT(!"Write not implemented for this packet."); } + virtual void CallHandler(Session* session) const = 0; + }; + + class ServerPacket : public Packet + { + public: + ServerPacket(PacketHeader const& header); + ~ServerPacket(); + + void Read() override final { ASSERT(!"Read not implemented for server packets."); } + + uint8* GetData() { return _stream.GetBuffer(); } + uint8 const* GetData() const { return _stream.GetBuffer(); } + size_t GetSize() const { return _stream.GetSize(); } + }; +} + +#endif // PacketsBase_h__ diff --git a/src/server/bnetserver/Packets/PresencePackets.cpp b/src/server/bnetserver/Packets/PresencePackets.cpp new file mode 100644 index 00000000000..da49f41af76 --- /dev/null +++ b/src/server/bnetserver/Packets/PresencePackets.cpp @@ -0,0 +1,48 @@ +/* + * 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 "Session.h" +#include "PresencePackets.h" + +void Battlenet::Presence::UpdateRequest::Read() +{ + +} + +std::string Battlenet::Presence::UpdateRequest::ToString() const +{ + return "Battlenet::Presence::UpdateRequest"; +} + +void Battlenet::Presence::UpdateRequest::CallHandler(Session* session) const +{ + session->LogUnhandledPacket(*this); +} + +void Battlenet::Presence::StatisticSubscribe::Read() +{ +} + +std::string Battlenet::Presence::StatisticSubscribe::ToString() const +{ + return "Battlenet::Presence::StatisticSubscribe"; +} + +void Battlenet::Presence::StatisticSubscribe::CallHandler(Session* session) const +{ + session->LogUnhandledPacket(*this); +} diff --git a/src/server/bnetserver/Packets/PresencePackets.h b/src/server/bnetserver/Packets/PresencePackets.h new file mode 100644 index 00000000000..c934228a3cb --- /dev/null +++ b/src/server/bnetserver/Packets/PresencePackets.h @@ -0,0 +1,65 @@ +/* + * 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 PresencePackets_h__ +#define PresencePackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Presence + { + enum Opcode + { + CMSG_UPDATE_REQUEST = 0x0, // Not implemented + CMSG_STATISTIC_SUBSCRIBE = 0x2, // Not implemented + + SMSG_UPDATE_NOTIFY = 0x0, // Not implemented + SMSG_FIELD_SPEC_ANNOUNCE = 0x1, // Not implemented + SMSG_STATISTICS_UPDATE = 0x3 // Not implemented + }; + + class UpdateRequest final : public ClientPacket + { + public: + UpdateRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_UPDATE_REQUEST, PRESENCE) && "Invalid packet header for UpdateRequest"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class StatisticSubscribe final : public ClientPacket + { + public: + StatisticSubscribe(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_STATISTIC_SUBSCRIBE, PRESENCE) && "Invalid packet header for StatisticSubscribe"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + } +} + +#endif // PresencePackets_h__ diff --git a/src/server/bnetserver/Packets/ProfilePackets.h b/src/server/bnetserver/Packets/ProfilePackets.h new file mode 100644 index 00000000000..bf413471f62 --- /dev/null +++ b/src/server/bnetserver/Packets/ProfilePackets.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 ProfilePackets_h__ +#define ProfilePackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Profile + { + enum Opcode + { + CMSG_READ_REQUEST = 0x0, // Not implemented + CMSG_ADDRESS_QUERY_REQUEST = 0x1, // Not implemented + CMSG_RESOLVE_TOON_HANDLE_TO_NAME_REQUEST = 0x2, // Not implemented + CMSG_RESOLVE_TOON_NAME_TO_HANDLE_REQUEST = 0x3, // Not implemented + CMSG_CHANGE_SETTINGS = 0x5, // Not implemented + + SMSG_READ_RESPONSE = 0x0, // Not implemented + SMSG_ADDRESS_QUERY_RESPONSE = 0x1, // Not implemented + SMSG_RESOLVE_TOON_HANDLE_TO_NAME_RESPONSE = 0x2, // Not implemented + SMSG_RESOLVE_TOON_NAME_TO_HANDLE_RESPONSE = 0x3, // Not implemented + SMSG_SETTINGS_AVAILABLE = 0x4 // Not implemented + }; + } +} + +#endif // ProfilePackets_h__ diff --git a/src/server/bnetserver/Packets/SupportPackets.h b/src/server/bnetserver/Packets/SupportPackets.h new file mode 100644 index 00000000000..43f51bd564e --- /dev/null +++ b/src/server/bnetserver/Packets/SupportPackets.h @@ -0,0 +1,34 @@ +/* + * 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 SupportPackets_h__ +#define SupportPackets_h__ + +#include "PacketsBase.h" + +namespace Battlenet +{ + namespace Support + { + enum Opcode + { + CMSG_COMPLAINT_REQUEST = 0x0 // Not implemented + }; + } +} + +#endif // SupportPackets_h__ diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp new file mode 100644 index 00000000000..6845fc914b1 --- /dev/null +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -0,0 +1,202 @@ +/* + * 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 "WoWRealmPackets.h" +#include "Session.h" +#include +#include + +std::string Battlenet::WoWRealm::ListSubscribeRequest::ToString() const +{ + return "Battlenet::WoWRealm::ListSubscribeRequest"; +} + +void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session) const +{ + session->HandleListSubscribeRequest(*this); +} + +Battlenet::WoWRealm::ListSubscribeResponse::~ListSubscribeResponse() +{ + for (ServerPacket* realmData : RealmData) + delete realmData; +} + +void Battlenet::WoWRealm::ListSubscribeResponse::Write() +{ + _stream.Write(Response, 1); + if (Response == SUCCESS) + { + _stream.Write(CharacterCounts.size(), 7); + for (CharacterCountEntry const& entry : CharacterCounts) + { + _stream.Write(entry.Realm.Battlegroup, 8); + _stream.Write(entry.Realm.Index, 32); + _stream.Write(entry.Realm.Region, 8); + _stream.Write(entry.CharacterCount, 16); + } + + for (ServerPacket* realmData : RealmData) + { + realmData->Write(); + _stream.WriteBytes(realmData->GetData(), realmData->GetSize()); + } + } + else + _stream.Write(ResponseCode, 8); +} + +std::string Battlenet::WoWRealm::ListSubscribeResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::WoWRealm::ListSubscribeResponse"; + + if (Response == SUCCESS) + { + stream << " Realms " << CharacterCounts.size(); + + for (CharacterCountEntry const& entry : CharacterCounts) + stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount; + + for (ServerPacket* realmData : RealmData) + stream << std::endl << realmData->ToString(); + } + else + stream << " Failure"; + + return stream.str().c_str(); +} + +void Battlenet::WoWRealm::ListUpdate::Write() +{ + _stream.Write(UpdateState, 1); + if (UpdateState == UPDATE) + { + _stream.Write(Type + -std::numeric_limits::min(), 32); + _stream.WriteFloat(Population); + _stream.Write(Flags, 8); + _stream.Write(Lock, 8); + _stream.Write(Timezone, 32); + _stream.Write(!Version.empty(), 1); + if (!Version.empty()) + { + _stream.WriteString(Version, 5); + _stream.Write(Build, 32); + + boost::asio::ip::address_v4::bytes_type ip = Address.address().to_v4().to_bytes(); + uint16 port = Address.port(); + + EndianConvertReverse(ip); + EndianConvertReverse(port); + + _stream.WriteBytes(ip.data(), 4); + _stream.WriteBytes(&port, 2); + } + + _stream.WriteString(Name, 10); + } + + _stream.Write(Battlegroup, 8); + _stream.Write(Index, 32); + _stream.Write(Region, 8); +} + +std::string Battlenet::WoWRealm::ListUpdate::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::WoWRealm::ListUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name + << " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index; + + if (!Version.empty()) + stream << " Version " << Version; + + return stream.str().c_str(); +} + +void Battlenet::WoWRealm::JoinRequestV2::Read() +{ + Realm.Battlegroup = _stream.Read(8); + Realm.Index = _stream.Read(32); + Realm.Region = _stream.Read(8); + ClientSeed = _stream.Read(32); +} + +std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::WoWRealm::JoinRequestV2 ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index; + return stream.str().c_str(); +} + +void Battlenet::WoWRealm::JoinRequestV2::CallHandler(Session* session) const +{ + session->HandleJoinRequestV2(*this); +} + +void Battlenet::WoWRealm::JoinResponseV2::Write() +{ + _stream.Write(0, 27); + _stream.Write(Response, 1); + if (Response == SUCCESS) + { + _stream.Write(ServerSeed, 32); + _stream.Write(IPv6.size(), 5); + for (tcp::endpoint const& addr : IPv6) + { + boost::asio::ip::address_v6::bytes_type ip = addr.address().to_v6().to_bytes(); + uint16 port = addr.port(); + + EndianConvertReverse(port); + + _stream.WriteBytes(ip.data(), 16); + _stream.WriteBytes(&port, 2); + } + + _stream.Write(IPv4.size(), 5); + for (tcp::endpoint const& addr : IPv4) + { + boost::asio::ip::address_v4::bytes_type ip = addr.address().to_v4().to_bytes(); + uint16 port = addr.port(); + + EndianConvertReverse(port); + + _stream.WriteBytes(ip.data(), 4); + _stream.WriteBytes(&port, 2); + } + } + else + _stream.Write(ResponseCode, 8); +} + +std::string Battlenet::WoWRealm::JoinResponseV2::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::WoWRealm::JoinResponseV2"; + if (Response == SUCCESS) + { + stream << " ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size() << " IPv6 Addresses " << IPv6.size(); + for (tcp::endpoint const& addr : IPv4) + stream << std::endl << "Battlenet::WoWRealm::JoinResponseV2::Address " << boost::lexical_cast(addr); + + for (tcp::endpoint const& addr : IPv6) + stream << std::endl << "Battlenet::WoWRealm::JoinResponseV2::Address " << boost::lexical_cast(addr); + } + else + stream << " Failure"; + + return stream.str().c_str(); +} diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h new file mode 100644 index 00000000000..4ce5ea68835 --- /dev/null +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -0,0 +1,173 @@ +/* + * 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 WoWRealmPackets_h__ +#define WoWRealmPackets_h__ + +#include "PacketsBase.h" +#include "RealmList.h" + +namespace Battlenet +{ + namespace WoWRealm + { + enum Opcode + { + CMSG_LIST_SUBSCRIBE_REQUEST = 0x0, + CMSG_LIST_UNSUBSCRIBE = 0x1, // Not implemented + CMSG_JOIN_REQUEST_V2 = 0x8, + CMSG_MULTI_LOGON_REQUEST_V2 = 0x9, // Not implemented + + SMSG_LIST_SUBSCRIBE_RESPONSE = 0x0, + SMSG_LIST_UPDATE = 0x2, + SMSG_LIST_COMPLETE = 0x3, + SMSG_TOON_READY = 0x6, // Not implemented + SMSG_TOON_LOGGED_OUT = 0x7, // Not implemented + SMSG_JOIN_RESPONSE_V2 = 0x8 + }; + + class ListSubscribeRequest final : public ClientPacket + { + public: + ListSubscribeRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM) && "Invalid packet header for ListSubscribeRequest"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + + class JoinRequestV2 final : public ClientPacket + { + public: + JoinRequestV2(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_JOIN_REQUEST_V2, WOWREALM) && "Invalid packet header for RealmJoinRequest"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) const override; + + uint32 ClientSeed; + RealmId Realm; + }; + + class ListSubscribeResponse final : public ServerPacket + { + public: + enum Result + { + SUCCESS = 0, + FAILURE = 1 + }; + + ListSubscribeResponse() : ServerPacket(PacketHeader(SMSG_LIST_SUBSCRIBE_RESPONSE, WOWREALM)), + Response(SUCCESS), ResponseCode(26) + { + } + + ~ListSubscribeResponse(); + + struct CharacterCountEntry + { + RealmId Realm; + uint32 CharacterCount; + }; + + void Write() override; + std::string ToString() const override; + + Result Response; + uint8 ResponseCode; + std::vector CharacterCounts; + std::vector RealmData; + }; + + class ListUpdate final : public ServerPacket + { + public: + enum State + { + DELETED = 0, + UPDATE = 1 + }; + + ListUpdate() : ServerPacket(PacketHeader(SMSG_LIST_UPDATE, WOWREALM)), UpdateState(UPDATE), + Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), + Flags(0), Region(0), Battlegroup(0), Index(0), Build(0) + { + } + + void Write() override; + std::string ToString() const override; + + int UpdateState; + uint32 Timezone; + float Population; + uint8 Lock; + uint32 Type; + std::string Name; + std::string Version; + tcp::endpoint Address; + uint8 Flags; + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; + + class ListComplete final : public ServerPacket + { + public: + ListComplete() : ServerPacket(PacketHeader(SMSG_LIST_COMPLETE, WOWREALM)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::WoWRealm::ListComplete"; } + }; + + class JoinResponseV2 final : public ServerPacket + { + public: + enum Result + { + SUCCESS = 0, + FAILURE = 1 + }; + + JoinResponseV2() : ServerPacket(PacketHeader(SMSG_JOIN_RESPONSE_V2, WOWREALM)), + ServerSeed(0), Response(SUCCESS), ResponseCode(26) + { + } + + void Write() override; + std::string ToString() const override; + + Result Response; + uint8 ResponseCode; + uint32 ServerSeed; + std::vector IPv4; + std::vector IPv6; + }; + } +} + +#endif // WoWRealmPackets_h__ diff --git a/src/server/bnetserver/PrecompiledHeaders/bnetPCH.cpp b/src/server/bnetserver/PrecompiledHeaders/bnetPCH.cpp new file mode 100644 index 00000000000..60b1d41a1a8 --- /dev/null +++ b/src/server/bnetserver/PrecompiledHeaders/bnetPCH.cpp @@ -0,0 +1 @@ +#include "bnetPCH.h" diff --git a/src/server/bnetserver/PrecompiledHeaders/bnetPCH.h b/src/server/bnetserver/PrecompiledHeaders/bnetPCH.h new file mode 100644 index 00000000000..82cd5393489 --- /dev/null +++ b/src/server/bnetserver/PrecompiledHeaders/bnetPCH.h @@ -0,0 +1,10 @@ +#include "Common.h" +#include "Configuration/Config.h" +#include "Database/DatabaseEnv.h" +#include "Log.h" +#include "ComponentManager.h" +#include "ModuleManager.h" +#include "RealmList.h" +#include "ByteBuffer.h" +#include "Packets.h" +#include "Session.h" diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp new file mode 100644 index 00000000000..60d40f98edf --- /dev/null +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -0,0 +1,207 @@ +/* + * 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 "Common.h" +#include "RealmList.h" +#include "Database/DatabaseEnv.h" +#include "Util.h" + +ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const +{ + ip::address realmIp; + + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (LocalAddress.is_loopback() || 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 = LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) == + (LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = LocalAddress; + } + else + realmIp = ExternalAddress; + } + + ip::tcp::endpoint endpoint(realmIp, port); + + // Return external IP + return endpoint; +} + +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(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, 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]; + + realm.m_ID = id; + realm.name = name; + realm.icon = icon; + realm.flag = flag; + realm.timezone = timezone; + realm.allowedSecurityLevel = allowedSecurityLevel; + 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; +} + +void RealmList::UpdateIfNeed() +{ + // maybe disabled or updated recently + if (!m_UpdateInterval || m_NextUpdateTime > time(NULL)) + return; + + m_NextUpdateTime = time(NULL) + m_UpdateInterval; + + // Clears Realm list + m_realms.clear(); + + // Get the content of the realmlist table in the database + UpdateRealms(); +} + +void RealmList::UpdateRealms(bool init) +{ + TC_LOG_INFO("server.authserver", "Updating Realm List..."); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); + PreparedQueryResult result = LoginDatabase.Query(stmt); + + // Circle through results and add them to the realm map + if (result) + { + do + { + 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(ip::tcp::v4(), fields[2].GetString(), ""); + + boost::system::error_code ec; + boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery, ec); + if (endPoint == end || ec) + { + 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(ip::tcp::v4(), fields[3].GetString(), ""); + endPoint = _resolver->resolve(localAddressQuery, ec); + if (endPoint == end || ec) + { + 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(ip::tcp::v4(), fields[4].GetString(), ""); + endPoint = _resolver->resolve(localSubmaskQuery, ec); + if (endPoint == end || ec) + { + 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()); + } +} + +Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const +{ + auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair) + { + return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index; + }); + + if (itr != m_realms.end()) + return &itr->second; + + return NULL; +} diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h new file mode 100644 index 00000000000..502fef80ee7 --- /dev/null +++ b/src/server/bnetserver/Realms/RealmList.h @@ -0,0 +1,113 @@ +/* + * 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 _REALMLIST_H +#define _REALMLIST_H + +#include +#include +#include +#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 +}; + +// Storage object for a realm +struct Realm +{ + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 port; + std::string name; + uint8 icon; + RealmFlags flag; + uint8 timezone; + uint32 m_ID; + AccountTypes allowedSecurityLevel; + float populationLevel; + uint32 gamebuild; + uint8 Region; + uint8 Battlegroup; + + ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; +}; + +namespace Battlenet +{ + struct RealmId + { + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + }; +} + +/// Storage object for the list of realms on the server +class RealmList +{ +public: + typedef std::map RealmMap; + + static RealmList* instance() + { + static RealmList instance; + return &instance; + } + + ~RealmList(); + + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); + + void UpdateIfNeed(); + + void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; } + + RealmMap::const_iterator begin() const { return m_realms.begin(); } + RealmMap::const_iterator end() const { return m_realms.end(); } + uint32 size() const { return m_realms.size(); } + Realm const* GetRealm(Battlenet::RealmId const& id) const; + +private: + 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 RealmList::instance() +#endif diff --git a/src/server/bnetserver/Server/ComponentManager.cpp b/src/server/bnetserver/Server/ComponentManager.cpp new file mode 100644 index 00000000000..be1f22022f4 --- /dev/null +++ b/src/server/bnetserver/Server/ComponentManager.cpp @@ -0,0 +1,55 @@ +/* + * 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 "ComponentManager.h" +#include "DatabaseEnv.h" + +Battlenet::ComponentMgr::~ComponentMgr() +{ + for (Component* component : _components) + delete component; +} + +void Battlenet::ComponentMgr::Load() +{ + QueryResult result = LoginDatabase.Query("SELECT Program, Platform, Build FROM battlenet_components"); + if (result) + { + do + { + Field* fields = result->Fetch(); + Component* component = new Component(); + component->Program = fields[0].GetString(); + component->Platform = fields[1].GetString(); + component->Build = fields[2].GetUInt32(); + + _components.insert(component); + _programs.insert(component->Program); + _platforms.insert(component->Platform); + + } while (result->NextRow()); + } +} + +bool Battlenet::ComponentMgr::HasComponent(Battlenet::Component const* component) const +{ + for (Component const* c : _components) + if (component->Program == c->Program && component->Platform == c->Platform && component->Build == c->Build) + return true; + + return false; +} diff --git a/src/server/bnetserver/Server/ComponentManager.h b/src/server/bnetserver/Server/ComponentManager.h new file mode 100644 index 00000000000..865cfca7f62 --- /dev/null +++ b/src/server/bnetserver/Server/ComponentManager.h @@ -0,0 +1,61 @@ +/* + * 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 ComponentManager_h__ +#define ComponentManager_h__ + +#include "Define.h" +#include +#include +#include + +namespace Battlenet +{ + struct Component + { + std::string Program; + std::string Platform; + uint32 Build; + }; + + class ComponentMgr + { + ComponentMgr() { } + ~ComponentMgr(); + + public: + void Load(); + bool HasComponent(Component const* component) const; + bool HasProgram(std::string const& program) const { return _programs.count(program) != 0; } + bool HasPlatform(std::string const& platform) const { return _platforms.count(platform) != 0; } + + static ComponentMgr* instance() + { + static ComponentMgr instance; + return &instance; + } + + private: + std::set _components; + std::set _programs; + std::set _platforms; + }; +} + +#define sComponentMgr Battlenet::ComponentMgr::instance() + +#endif // ComponentManager_h__ diff --git a/src/server/bnetserver/Server/ModuleManager.cpp b/src/server/bnetserver/Server/ModuleManager.cpp new file mode 100644 index 00000000000..8dc43136739 --- /dev/null +++ b/src/server/bnetserver/Server/ModuleManager.cpp @@ -0,0 +1,57 @@ +/* + * 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 "ModuleManager.h" +#include "DatabaseEnv.h" + +Battlenet::ModuleManager::~ModuleManager() +{ + for (auto const& m : _modules) + delete m.second; +} + +void Battlenet::ModuleManager::Load() +{ + QueryResult result = LoginDatabase.Query("SELECT `Hash`, `Name`, `Type`, `System`, `Data` FROM battlenet_modules"); + if (result) + { + do + { + Field* fields = result->Fetch(); + ModuleInfo* module = new ModuleInfo(); + module->Type = fields[2].GetString(); + HexStrToByteArray(fields[0].GetString(), module->ModuleId); + std::string data = fields[4].GetString(); + module->DataSize = data.length() / 2; + if (module->DataSize) + { + module->Data = new uint8[data.length() / 2]; + HexStrToByteArray(data, module->Data); + } + + _modules[{ fields[3].GetString(), fields[1].GetString() }] = module; + } while (result->NextRow()); + } +} + +Battlenet::ModuleInfo* Battlenet::ModuleManager::CreateModule(std::string const& os, std::string const& name) const +{ + ModuleKey key { os, name }; + ASSERT(_modules.count(key)); + + return new ModuleInfo(*_modules.at(key)); +} diff --git a/src/server/bnetserver/Server/ModuleManager.h b/src/server/bnetserver/Server/ModuleManager.h new file mode 100644 index 00000000000..36ffb2fec3f --- /dev/null +++ b/src/server/bnetserver/Server/ModuleManager.h @@ -0,0 +1,94 @@ +/* + * 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 ModuleManager_h__ +#define ModuleManager_h__ + +#include "Define.h" +#include +#include +#include + +namespace Battlenet +{ + struct ModuleKey + { + std::string Platform; + std::string Name; + + bool operator<(ModuleKey const& right) const + { + int32 res = Platform.compare(right.Platform); + if (res < 0) + return true; + else if (res > 0) + return false; + + return Name < right.Name; + } + }; + + struct ModuleInfo + { + ModuleInfo() : Region("EU"), DataSize(0), Data(nullptr) { } + ModuleInfo(ModuleInfo const& right) : Type(right.Type), Region(right.Region), DataSize(right.DataSize), Data(nullptr) + { + memcpy(ModuleId, right.ModuleId, 32); + if (DataSize) + { + Data = new uint8[DataSize]; + memcpy(Data, right.Data, DataSize); + } + } + ~ModuleInfo() + { + delete Data; + } + + std::string Type; + std::string Region; + uint8 ModuleId[32]; + uint32 DataSize; + uint8* Data; + }; + + class ModuleManager + { + ModuleManager() { } + ~ModuleManager(); + + public: + void Load(); + ModuleInfo* CreateModule(std::string const& os, std::string const& name) const; + + static ModuleManager* instance() + { + static ModuleManager instance; + return &instance; + } + + private: + void LoadComponents(); + void LoadModules(); + + std::map _modules; + }; +} + +#define sModuleMgr Battlenet::ModuleManager::instance() + +#endif // ModuleManager_h__ diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp new file mode 100644 index 00000000000..8935d520c40 --- /dev/null +++ b/src/server/bnetserver/Server/Session.cpp @@ -0,0 +1,1000 @@ +/* + * 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 "AuthCodes.h" +#include "BitStream.h" +#include "PacketFactory.h" +#include "SessionManager.h" +#include "Database/DatabaseEnv.h" +#include "HmacHash.h" +#include "Log.h" +#include "RealmList.h" +#include "SHA256.h" +#include + +Battlenet::Session::ModuleHandler const Battlenet::Session::ModuleHandlers[MODULE_COUNT] = +{ + &Battlenet::Session::HandlePasswordModule, + &Battlenet::Session::UnhandledModule, + &Battlenet::Session::UnhandledModule, + &Battlenet::Session::HandleSelectGameAccountModule, + &Battlenet::Session::HandleRiskFingerprintModule, + &Battlenet::Session::HandleResumeModule, +}; + +Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountId(0), _accountName(), _locale(), + _os(), _build(0), _gameAccountId(0), _gameAccountName(), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), + _reconnectProof(), _crypt(), _authed(false) +{ + static uint8 const N_Bytes[] = + { + 0xAB, 0x24, 0x43, 0x63, 0xA9, 0xC2, 0xA6, 0xC3, 0x3B, 0x37, 0xE4, 0x61, 0x84, 0x25, 0x9F, 0x8B, + 0x3F, 0xCB, 0x8A, 0x85, 0x27, 0xFC, 0x3D, 0x87, 0xBE, 0xA0, 0x54, 0xD2, 0x38, 0x5D, 0x12, 0xB7, + 0x61, 0x44, 0x2E, 0x83, 0xFA, 0xC2, 0x21, 0xD9, 0x10, 0x9F, 0xC1, 0x9F, 0xEA, 0x50, 0xE3, 0x09, + 0xA6, 0xE5, 0x5E, 0x23, 0xA7, 0x77, 0xEB, 0x00, 0xC7, 0xBA, 0xBF, 0xF8, 0x55, 0x8A, 0x0E, 0x80, + 0x2B, 0x14, 0x1A, 0xA2, 0xD4, 0x43, 0xA9, 0xD4, 0xAF, 0xAD, 0xB5, 0xE1, 0xF5, 0xAC, 0xA6, 0x13, + 0x1C, 0x69, 0x78, 0x64, 0x0B, 0x7B, 0xAF, 0x9C, 0xC5, 0x50, 0x31, 0x8A, 0x23, 0x08, 0x01, 0xA1, + 0xF5, 0xFE, 0x31, 0x32, 0x7F, 0xE2, 0x05, 0x82, 0xD6, 0x0B, 0xED, 0x4D, 0x55, 0x32, 0x41, 0x94, + 0x29, 0x6F, 0x55, 0x7D, 0xE3, 0x0F, 0x77, 0x19, 0xE5, 0x6C, 0x30, 0xEB, 0xDE, 0xF6, 0xA7, 0x86 + }; + + N.SetBinary(N_Bytes, sizeof(N_Bytes)); + g.SetDword(2); + + SHA256Hash sha; + sha.UpdateBigNumbers(&N, &g, NULL); + sha.Finalize(); + k.SetBinary(sha.GetDigest(), sha.GetLength()); +} + +Battlenet::Session::~Session() +{ + sSessionMgr.RemoveSession(this); + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::OnClose"); +} + +void Battlenet::Session::_SetVSFields(std::string const& pstr) +{ + s.SetRand(uint32(BufferSizes::SRP_6_S) * 8); + + BigNumber p; + p.SetHexStr(pstr.c_str()); + + SHA256Hash sha; + sha.UpdateBigNumbers(&s, &p, NULL); + sha.Finalize(); + BigNumber x; + x.SetBinary(sha.GetDigest(), sha.GetLength()); + v = g.ModExp(x, N); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_VS_FIELDS); + stmt->setString(0, v.AsHexStr()); + stmt->setString(1, s.AsHexStr()); + stmt->setString(2, _accountName); + + LoginDatabase.Execute(stmt); +} + +void Battlenet::Session::LogUnhandledPacket(ClientPacket const& packet) +{ + TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::LogUnhandledPacket %s", packet.ToString().c_str()); +} + +void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& info) +{ + // Verify that this IP is not in the ip_banned table + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + + std::string ip_address = GetRemoteIpAddress().to_string(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); + stmt->setString(0, ip_address); + if (PreparedQueryResult result = LoginDatabase.Query(stmt)) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(LOGIN_BANNED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); + return; + } + + if (info.Program != "WoW") + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_INVALID_PROGRAM); + AsyncWrite(complete); + return; + } + + if (!sComponentMgr->HasPlatform(info.Platform)) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_INVALID_OS); + AsyncWrite(complete); + return; + } + + if (!sComponentMgr->HasPlatform(info.Locale)) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); + AsyncWrite(complete); + return; + } + + for (Component const& component : info.Components) + { + if (!sComponentMgr->HasComponent(&component)) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + if (!sComponentMgr->HasProgram(component.Program)) + complete->SetAuthResult(AUTH_INVALID_PROGRAM); + else if (!sComponentMgr->HasPlatform(component.Platform)) + complete->SetAuthResult(AUTH_INVALID_OS); + else + { + if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) + complete->SetAuthResult(AUTH_REGION_BAD_VERSION); + else + complete->SetAuthResult(AUTH_USE_GRUNT_LOGON); + } + + AsyncWrite(complete); + return; + } + + if (component.Platform == "base") + _build = component.Build; + } + + _accountName = info.Login; + _locale = info.Locale; + _os = info.Platform; + + Utf8ToUpperOnlyLatin(_accountName); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); + stmt->setString(0, _accountName); + + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(complete); + return; + } + + Field* fields = result->Fetch(); + + _accountId = fields[1].GetUInt32(); + + // If the IP is 'locked', check that the player comes indeed from the correct IP address + if (fields[2].GetUInt8() == 1) // if ip is locked + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + + if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(complete); + return; + } + } + else + { + TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); + std::string accountCountry = fields[3].GetString(); + if (accountCountry.empty() || accountCountry == "00") + TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.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.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); + if (loginCountry != accountCountry) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(complete); + return; + } + } + } + } + + //set expired bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); + + // If the account is banned, reject the logon attempt + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); + stmt->setUInt32(0, _accountId); + PreparedQueryResult banresult = LoginDatabase.Query(stmt); + if (banresult) + { + Field* fields = banresult->Fetch(); + if (fields[0].GetUInt32() == fields[1].GetUInt32()) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(LOGIN_BANNED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + return; + } + else + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(LOGIN_SUSPENDED); + AsyncWrite(complete); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + return; + } + } + + SHA256Hash sha; + sha.UpdateData(_accountName); + sha.Finalize(); + + I.SetBinary(sha.GetDigest(), sha.GetLength()); + + ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); + ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); + + std::string pStr = fields[0].GetString(); + + std::string databaseV = fields[5].GetString(); + std::string databaseS = fields[6].GetString(); + + if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) + _SetVSFields(pStr); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(128 * 8); + B = ((v * k) + g.ModExp(b, N)) % N; + BigNumber unk; + unk.SetRand(128 * 8); + + BitStream passwordData; + uint8 state = 0; + passwordData.WriteBytes(&state, 1); + passwordData.WriteBytes(I.AsByteArray(32).get(), 32); + passwordData.WriteBytes(s.AsByteArray(32).get(), 32); + passwordData.WriteBytes(B.AsByteArray(128).get(), 128); + passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); + + password->DataSize = passwordData.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); + + _modulesWaitingForData.push(MODULE_PASSWORD); + + Authentication::ProofRequest* request = new Authentication::ProofRequest(); + request->Modules.push_back(password); + // if has authenticator, send Token module + request->Modules.push_back(thumbprint); + AsyncWrite(request); +} + +void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& reconnect) +{ + _accountName = reconnect.Login; + _locale = reconnect.Locale; + _os = reconnect.Platform; + auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); + if (baseComponent != reconnect.Components.end()) + _build = baseComponent->Build; + + Utf8ToUpperOnlyLatin(_accountName); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); + stmt->setString(0, _accountName); + stmt->setString(1, reconnect.GameAccountName); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + Authentication::ResumeResponse* resume = new Authentication::ResumeResponse(); + resume->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(resume); + return; + } + + Field* fields = result->Fetch(); + + _accountId = fields[0].GetUInt32(); + K.SetHexStr(fields[1].GetString().c_str()); + _gameAccountId = fields[2].GetUInt32(); + _gameAccountName = reconnect.GameAccountName; + + ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); + ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); + BitStream resumeData; + uint8 state = 0; + _reconnectProof.SetRand(16 * 8); + + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(_reconnectProof.AsByteArray().get(), 16); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + _modulesWaitingForData.push(MODULE_RESUME); + + Authentication::ProofRequest* request = new Authentication::ProofRequest(); + request->Modules.push_back(thumbprint); + request->Modules.push_back(resume); + AsyncWrite(request); +} + +void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proof) +{ + if (_modulesWaitingForData.size() < proof.Modules.size()) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + AsyncWrite(complete); + return; + } + + ServerPacket* response = nullptr; + for (size_t i = 0; i < proof.Modules.size(); ++i) + { + if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) + break; + + _modulesWaitingForData.pop(); + } + + if (!response) + { + response = new Authentication::LogonResponse(); + static_cast(response)->SetAuthResult(AUTH_INTERNAL_ERROR); + } + + AsyncWrite(response); + return; +} + +void Battlenet::Session::HandlePing(Connection::Ping const& /*ping*/) +{ + AsyncWrite(new Connection::Pong()); +} + +void Battlenet::Session::HandleEnableEncryption(Connection::EnableEncryption const& /*enableEncryption*/) +{ + _crypt.Init(&K); +} + +void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /*logoutRequest*/) +{ + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, ""); + stmt->setBool(1, false); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); +} + +void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/) +{ + sRealmList->UpdateIfNeed(); + + WoWRealm::ListSubscribeResponse* counts = new WoWRealm::ListSubscribeResponse(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); + stmt->setUInt32(0, _gameAccountId); + + if (PreparedQueryResult countResult = LoginDatabase.Query(stmt)) + { + do + { + Field* fields = countResult->Fetch(); + uint32 build = fields[4].GetUInt32(); + counts->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + } while (countResult->NextRow()); + } + + for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) + { + Realm const& realm = i->second; + + uint32 flag = realm.flag & ~REALM_FLAG_SPECIFYBUILD; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); + if (realm.gamebuild != _build) + { + flag |= REALM_FLAG_INVALID; + if (buildInfo) + flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + WoWRealm::ListUpdate* update = new WoWRealm::ListUpdate(); + update->Timezone = realm.timezone; + update->Population = realm.populationLevel; + update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + update->Type = realm.icon; + update->Name = realm.name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; + + update->Version = version.str(); + update->Address = realm.GetAddressForClient(GetRemoteIpAddress()); + update->Build = buildInfo->Build; + } + + update->Flags = flag; + update->Region = realm.Region; + update->Battlegroup = realm.Battlegroup; + update->Index = realm.m_ID; + + counts->RealmData.push_back(update); + } + + counts->RealmData.push_back(new WoWRealm::ListComplete()); + + AsyncWrite(counts); +} + +void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join) +{ + WoWRealm::JoinResponseV2* result = new WoWRealm::JoinResponseV2(); + Realm const* realm = sRealmList->GetRealm(join.Realm); + if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) + { + result->Response = WoWRealm::JoinResponseV2::FAILURE; + AsyncWrite(result); + return; + } + + result->ServerSeed = uint32(rand32()); + + uint8 sessionKey[40]; + HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); + hmac.UpdateData((uint8*)"WoW\0", 4); + hmac.UpdateData((uint8*)&join.ClientSeed, 4); + hmac.UpdateData((uint8*)&result->ServerSeed, 4); + hmac.Finalize(); + + memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); + + HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); + hmac2.UpdateData((uint8*)"WoW\0", 4); + hmac2.UpdateData((uint8*)&result->ServerSeed, 4); + hmac2.UpdateData((uint8*)&join.ClientSeed, 4); + hmac2.Finalize(); + + memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); + + LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", + ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); + + result->IPv4.emplace_back(realm->ExternalAddress, realm->port); + if (realm->ExternalAddress != realm->LocalAddress) + result->IPv4.emplace_back(realm->LocalAddress, realm->port); + + AsyncWrite(result); +} + +void Battlenet::Session::ReadHandler() +{ + BitStream stream(std::move(GetReadBuffer())); + _crypt.DecryptRecv(stream.GetBuffer(), stream.GetSize()); + + while (!stream.IsRead()) + { + try + { + PacketHeader header; + header.Opcode = stream.Read(6); + if (stream.Read(1)) + header.Channel = stream.Read(4); + + if (header.Channel != AUTHENTICATION && !_authed) + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::ReadDataHandler Received not allowed packet %s", header.ToString().c_str()); + CloseSocket(); + return; + } + + if (ClientPacket* packet = sPacketFactory.Create(header, stream)) + { + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::ReadDataHandler %s", packet->ToString().c_str()); + packet->CallHandler(this); + delete packet; + } + else + { + TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::ReadDataHandler Unhandled opcode %s", header.ToString().c_str()); + break; + } + + stream.AlignToNextByte(); + } + catch (BitStreamPositionException const& e) + { + TC_LOG_ERROR("server.battlenet", "Battlenet::Session::ReadDataHandler Exception: %s", e.what()); + CloseSocket(); + return; + } + } + + GetReadBuffer().Resize(size_t(BufferSizes::Read)); + AsyncRead(); +} + +void Battlenet::Session::Start() +{ + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::Start"); + AsyncRead(); +} + +void Battlenet::Session::AsyncWrite(ServerPacket* packet) +{ + if (!IsOpen()) + { + delete packet; + return; + } + + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::AsyncWrite %s", packet->ToString().c_str()); + + packet->Write(); + + MessageBuffer buffer; + buffer.Write(packet->GetData(), packet->GetSize()); + delete packet; + + std::unique_lock guard(_writeLock); + + _crypt.EncryptSend(buffer.GetReadPointer(), buffer.GetActiveSize()); + + QueuePacket(std::move(buffer), guard); +} + +inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse) +{ + if (*oldResponse) + delete *oldResponse; + + *oldResponse = newResponse; +} + +bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->GetSize() != 1 + 128 + 32 + 128) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + if (dataStream->Read(8) != 2) // State + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + + BigNumber A, clientM1, clientChallenge; + A.SetBinary(dataStream->ReadBytes(128).get(), 128); + clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); + clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); + + if (A.isZero()) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + SHA256Hash sha; + sha.UpdateBigNumbers(&A, &B, NULL); + sha.Finalize(); + + BigNumber u; + u.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); + + uint8 S_bytes[128]; + memcpy(S_bytes, S.AsByteArray(128).get(), 128); + + uint8 part1[64]; + uint8 part2[64]; + + for (int i = 0; i < 64; ++i) + { + part1[i] = S_bytes[i * 2]; + part2[i] = S_bytes[i * 2 + 1]; + } + + SHA256Hash part1sha, part2sha; + part1sha.UpdateData(part1, 64); + part1sha.Finalize(); + part2sha.UpdateData(part2, 64); + part2sha.Finalize(); + + uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; + for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) + { + sessionKey[i * 2] = part1sha.GetDigest()[i]; + sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; + } + + K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); + + BigNumber M1; + + uint8 hash[SHA256_DIGEST_LENGTH]; + sha.Initialize(); + sha.UpdateBigNumbers(&N, NULL); + sha.Finalize(); + memcpy(hash, sha.GetDigest(), sha.GetLength()); + + sha.Initialize(); + sha.UpdateBigNumbers(&g, NULL); + sha.Finalize(); + + for (int i = 0; i < sha.GetLength(); ++i) + hash[i] ^= sha.GetDigest()[i]; + + SHA256Hash shaI; + shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); + shaI.Finalize(); + + // Concat all variables for M1 hash + sha.Initialize(); + sha.UpdateData(hash, SHA256_DIGEST_LENGTH); + sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); + sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); + sha.Finalize(); + + M1.SetBinary(sha.GetDigest(), sha.GetLength()); + + if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); + stmt->setString(0, _accountName); + LoginDatabase.Execute(stmt); + + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + uint64 numAccounts = 0; + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNTS); + stmt->setUInt32(0, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + numAccounts = result->GetRowCount(); + + if (!numAccounts) + { + Authentication::LogonResponse* noAccounts = new Authentication::LogonResponse(); + noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, noAccounts); + return false; + } + + Field* fields = result->Fetch(); + + //set expired game account bans to inactive + LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + BigNumber M; + sha.Initialize(); + sha.UpdateBigNumbers(&A, &M1, &K, NULL); + sha.Finalize(); + M.SetBinary(sha.GetDigest(), sha.GetLength()); + + BigNumber serverProof; + serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client + + BitStream stream; + ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); + uint8 state = 3; + + stream.WriteBytes(&state, 1); + stream.WriteBytes(M.AsByteArray(32).get(), 32); + stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); + + password->DataSize = stream.GetSize(); + password->Data = new uint8[password->DataSize]; + memcpy(password->Data, stream.GetBuffer(), password->DataSize); + + Authentication::ProofRequest* request = new Authentication::ProofRequest(); + request->Modules.push_back(password); + if (numAccounts > 1) + { + BitStream accounts; + state = 0; + accounts.WriteBytes(&state, 1); + accounts.Write(numAccounts, 8); + do + { + fields = result->Fetch(); + std::ostringstream name; + std::string originalName = fields[1].GetString(); + if (originalName.find('#') != std::string::npos) + name << "WoW" << uint32(fields[0].GetUInt8()); + else + name << originalName; + + accounts.Write(2, 8); + accounts.WriteString(name.str(), 8); + } while (result->NextRow()); + + ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount"); + selectGameAccount->DataSize = accounts.GetSize(); + selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; + memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); + request->Modules.push_back(selectGameAccount); + _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); + } + else + { + if (fields[4].GetBool()) + { + delete request; + + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + if (fields[2].GetUInt32() == fields[3].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[0].GetUInt32(); + _gameAccountName = fields[1].GetString(); + + request->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + } + + ReplaceResponse(response, request); + return true; +} + +bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + dataStream->Read(8); + std::string account = dataStream->ReadString(8); + if (account.empty()) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + PreparedStatement* stmt; + if (account.substr(0, 3) != "WoW") + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT); + stmt->setString(0, account); + } + else + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_UNNAMED); + stmt->setUInt8(0, atol(account.substr(3).c_str())); + } + + stmt->setUInt32(1, _accountId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (!result) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, complete); + return false; + } + + Field* fields = result->Fetch(); + if (fields[4].GetBool()) + { + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + if (fields[2].GetUInt32() == fields[3].GetUInt32()) + { + complete->SetAuthResult(LOGIN_BANNED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + } + else + { + complete->SetAuthResult(LOGIN_SUSPENDED); + TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + } + + ReplaceResponse(response, complete); + return false; + } + + _gameAccountId = fields[0].GetUInt32(); + _gameAccountName = fields[1].GetString(); + + Authentication::ProofRequest* request = new Authentication::ProofRequest(); + request->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); + ReplaceResponse(response, request); + + _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); + return true; +} + +bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) +{ + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + if (dataStream->Read(8) == 1) + { + complete->AccountId = _accountId; + complete->GameAccountName = _gameAccountName; + complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_FAILED_LOGINS); + stmt->setUInt32(0, _accountId); + if (PreparedQueryResult failedLoginsResult = LoginDatabase.Query(stmt)) + complete->FailedLogins = (*failedLoginsResult)[0].GetUInt32(); + + SQLTransaction trans = LoginDatabase.BeginTransaction(); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO); + stmt->setString(0, GetRemoteIpAddress().to_string()); + stmt->setUInt8(1, GetLocaleByName(_locale)); + stmt->setString(2, _os); + stmt->setUInt32(3, _accountId); + trans->Append(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + trans->Append(stmt); + + LoginDatabase.CommitTransaction(trans); + + _authed = true; + sSessionMgr.AddSession(this); + } + else + complete->SetAuthResult(AUTH_BAD_VERSION_HASH); + + ReplaceResponse(response, complete); + return true; +} + +bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response) +{ + if (dataStream->Read(8) != 1) + { + Authentication::ResumeResponse* complete = new Authentication::ResumeResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; + } + + static uint8 const ResumeClient = 0; + static uint8 const ResumeServer = 1; + + std::unique_ptr clientChallenge = dataStream->ReadBytes(16); + std::unique_ptr clientProof = dataStream->ReadBytes(32); + std::unique_ptr serverChallenge = _reconnectProof.AsByteArray(16); + std::unique_ptr sessionKey = K.AsByteArray(64); + + HmacSha256 clientPart(64, sessionKey.get()); + clientPart.UpdateData(&ResumeClient, 1); + clientPart.UpdateData(clientChallenge.get(), 16); + clientPart.UpdateData(serverChallenge.get(), 16); + clientPart.Finalize(); + + HmacSha256 serverPart(64, sessionKey.get()); + serverPart.UpdateData(&ResumeServer, 1); + serverPart.UpdateData(serverChallenge.get(), 16); + serverPart.UpdateData(clientChallenge.get(), 16); + serverPart.Finalize(); + + uint8 newSessionKey[64]; + memcpy(&newSessionKey[0], clientPart.GetDigest(), clientPart.GetLength()); + memcpy(&newSessionKey[32], serverPart.GetDigest(), serverPart.GetLength()); + + K.SetBinary(newSessionKey, 64); + + HmacSha256 proof(64, newSessionKey); + proof.UpdateData(&ResumeClient, 1); + proof.UpdateData(clientChallenge.get(), 16); + proof.UpdateData(serverChallenge.get(), 16); + proof.Finalize(); + + if (memcmp(proof.GetDigest(), clientProof.get(), serverPart.GetLength())) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); + stmt->setString(0, _accountName); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); + Authentication::ResumeResponse* result = new Authentication::ResumeResponse(); + result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, result); + return false; + } + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_SESSION_KEY); + stmt->setString(0, K.AsHexStr()); + stmt->setBool(1, true); + stmt->setUInt32(2, _accountId); + LoginDatabase.Execute(stmt); + + HmacSha256 serverProof(64, newSessionKey); + serverProof.UpdateData(&ResumeServer, 1); + serverProof.UpdateData(serverChallenge.get(), 16); + serverProof.UpdateData(clientChallenge.get(), 16); + serverProof.Finalize(); + + ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); + + BitStream resumeData; + uint8 state = 2; + resumeData.WriteBytes(&state, 1); + resumeData.WriteBytes(serverProof.GetDigest(), serverProof.GetLength()); + + resume->DataSize = resumeData.GetSize(); + resume->Data = new uint8[resume->DataSize]; + memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); + + Authentication::ResumeResponse* result = new Authentication::ResumeResponse(); + result->Modules.push_back(resume); + ReplaceResponse(response, result); + _authed = true; + sSessionMgr.AddSession(this); + return true; +} + +bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) +{ + Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + complete->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, complete); + return false; +} diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h new file mode 100644 index 00000000000..41caadbab3f --- /dev/null +++ b/src/server/bnetserver/Server/Session.h @@ -0,0 +1,128 @@ +/* + * 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 Session_h__ +#define Session_h__ + +#include "Packets.h" +#include "BattlenetPacketCrypt.h" +#include "Socket.h" +#include "BigNumber.h" +#include +#include + +using boost::asio::ip::tcp; + +namespace Battlenet +{ + struct PacketHeader; + class BitStream; + + enum ModuleType + { + MODULE_PASSWORD, + MODULE_TOKEN, + MODULE_THUMBPRINT, + MODULE_SELECT_GAME_ACCOUNT, + MODULE_RISK_FINGERPRINT, + MODULE_RESUME, + + MODULE_COUNT + }; + + enum class BufferSizes : uint32 + { + SRP_6_V = 0x80, + SRP_6_S = 0x20, + Read = 0x4000 + }; + + class Session : public Socket + { + typedef Socket BattlenetSocket; + + public: + explicit Session(tcp::socket&& socket); + ~Session(); + + void LogUnhandledPacket(ClientPacket const& packet); + + // Authentication + void HandleLogonRequest(Authentication::LogonRequest const& logonRequest); + void HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest); + void HandleProofResponse(Authentication::ProofResponse const& proofResponse); + + // Connection + void HandlePing(Connection::Ping const& ping); + void HandleEnableEncryption(Connection::EnableEncryption const& enableEncryption); + void HandleLogoutRequest(Connection::LogoutRequest const& logoutRequest); + + // WoWRealm + void HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& listSubscribeRequest); + void HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest); + + void Start() override; + + void AsyncWrite(ServerPacket* packet); + + protected: + void ReadHandler() override; + + private: + void _SetVSFields(std::string const& rI); + + typedef bool(Session::*ModuleHandler)(BitStream* dataStream, ServerPacket** response); + static ModuleHandler const ModuleHandlers[MODULE_COUNT]; + + bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response); + bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response); + bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response); + bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); + bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + + uint32 _accountId; + std::string _accountName; + std::string _locale; + std::string _os; + uint32 _build; + uint32 _gameAccountId; + std::string _gameAccountName; + AccountTypes _accountSecurityLevel; + + BigNumber N; + BigNumber g; + BigNumber k; + + BigNumber I; + BigNumber s; + BigNumber v; + + BigNumber b; + BigNumber B; + BigNumber K; // session key + + BigNumber _reconnectProof; + + std::queue _modulesWaitingForData; + + PacketCrypt _crypt; + bool _authed; + }; + +} + +#endif // Session_h__ diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp new file mode 100644 index 00000000000..d8b6bfca8d1 --- /dev/null +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -0,0 +1,37 @@ +/* + * 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 "SessionManager.h" + +bool Battlenet::SessionManager::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) +{ + if (!BaseSocketMgr::StartNetwork(service, bindIp, port)) + return false; + + _acceptor->AsyncAcceptManaged(&OnSocketAccept); + return true; +} + +NetworkThread* Battlenet::SessionManager::CreateThreads() const +{ + return new NetworkThread[GetNetworkThreadCount()]; +} + +void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock) +{ + sSessionMgr.OnSocketOpen(std::forward(sock)); +} diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h new file mode 100644 index 00000000000..10e7196e4d8 --- /dev/null +++ b/src/server/bnetserver/Server/SessionManager.h @@ -0,0 +1,71 @@ +/* + * 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 SessionManager_h__ +#define SessionManager_h__ + +#include "Session.h" +#include "SocketMgr.h" + +namespace Battlenet +{ +#pragma pack(push, 1) + + struct SessionInfo + { + uint32 AccountId; + uint32 GameAccountIndex; + + bool operator<(SessionInfo const& right) const + { + return memcmp(this, &right, sizeof(SessionInfo)) < 0; + } + }; + +#pragma pack(pop) + + class SessionManager : SocketMgr + { + typedef SocketMgr BaseSocketMgr; + + public: + static SessionManager& Instance() + { + static SessionManager instance; + return instance; + } + + bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override; + + // noop for now, will be needed later to broadcast realmlist updates for example + void AddSession(Session* /*session*/) { } + + void RemoveSession(Session* /*session*/) { } + + protected: + NetworkThread* CreateThreads() const override; + + private: + static void OnSocketAccept(tcp::socket&& sock); + + std::map _sessions; + }; +} + +#define sSessionMgr Battlenet::SessionManager::Instance() + +#endif // SessionManager_h__ diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist new file mode 100644 index 00000000000..e0ef6982353 --- /dev/null +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -0,0 +1,257 @@ +############################################### +# Trinity Core Auth Server configuration file # +############################################### +[authserver] + +################################################################################################### +# SECTION INDEX +# +# EXAMPLE CONFIG +# AUTH SERVER SETTINGS +# MYSQL SETTINGS +# LOGGING SYSTEM SETTINGS +# +################################################################################################### + +################################################################################################### +# EXAMPLE CONFIG +# +# Variable +# Description: Brief description what the variable is doing. +# Important: Annotation for important things about this variable. +# Example: "Example, i.e. if the value is a string" +# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options) +# 0 - (Disabled|Comment|Variable name in case of grouped config options) +# +# Note to developers: +# - Copy this example to keep the formatting. +# - Line breaks should be at column 100. +################################################################################################### + +################################################################################################### +# AUTH SERVER SETTINGS +# +# LogsDir +# Description: Logs directory setting. +# Important: LogsDir needs to be quoted, as the string might contain space characters. +# Logs directory must exists, or log file creation will be disabled. +# Default: "" - (Log files will be stored in the current path) + +LogsDir = "" + +# +# MaxPingTime +# Description: Time (in minutes) between database pings. +# Default: 30 + +MaxPingTime = 30 + +# +# RealmServerPort +# Description: TCP port to reach the auth server. +# Default: 3724 + +RealmServerPort = 3724 + +# +# BattlenetPort +# Description: TCP port to reach the auth server for battle.net connections. +# Default: 1119 + +BattlenetPort = 1119 + +# +# +# BindIP +# Description: Bind auth server to IP/hostname +# Default: "0.0.0.0" - (Bind to all IPs on the system) + +BindIP = "0.0.0.0" + +# +# PidFile +# Description: Auth server PID file. +# Example: "./authserver.pid" - (Enabled) +# Default: "" - (Disabled) + +PidFile = "" + +# +# UseProcessors +# Description: Processors mask for Windows and Linux based multi-processor systems. +# Example: A computer with 2 CPUs: +# 1 - 1st CPU only, 2 - 2nd CPU only, 3 - 1st and 2nd CPU, because 1 | 2 is 3 +# Default: 0 - (Selected by OS) +# 1+ - (Bit mask value of selected processors) + +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. +# Default: 0 - (Normal) +# 1 - (High) + +ProcessPriority = 0 + +# +# RealmsStateUpdateDelay +# Description: Time (in seconds) between realm list updates. +# Default: 20 - (Enabled) +# 0 - (Disabled) + +RealmsStateUpdateDelay = 20 + +# +# WrongPass.MaxCount +# Description: Number of login attemps with wrong password before the account or IP will be +# banned. +# Default: 0 - (Disabled) +# 1+ - (Enabled) + +WrongPass.MaxCount = 0 + +# +# WrongPass.BanTime +# Description: Time (in seconds) for banning account or IP for invalid login attempts. +# Default: 600 - (10 minutes) +# 0 - (Permanent ban) + +WrongPass.BanTime = 600 + +# +# WrongPass.BanType +# Description: Ban type for invalid login attempts. +# Default: 0 - (Ban IP) +# 1 - (Ban Account) + +WrongPass.BanType = 0 + +# +################################################################################################### + +################################################################################################### +# MYSQL SETTINGS +# +# LoginDatabaseInfo +# Description: Database connection settings for the realm server. +# Example: "hostname;port;username;password;database" +# ".;somenumber;username;password;database" - (Use named pipes on Windows +# "enable-named-pipe" to [mysqld] +# section my.ini) +# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on +# Unix/Linux) +# Default: "127.0.0.1;3306;trinity;trinity;auth" + +LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth" + +# +# LoginDatabase.WorkerThreads +# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL +# statements. Each worker thread is mirrored with its own connection to the +# Default: 1 + +LoginDatabase.WorkerThreads = 1 + +# +# Wrong.Password.Login.Logging +# Description: Additionally log attempted wrong password logging +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Wrong.Password.Login.Logging = 0 +# +################################################################################################### + +################################################################################################### +# +# LOGGING SYSTEM SETTINGS +# +# Appender config values: Given a appender "name" +# Appender.name +# Description: Defines 'where to log' +# Format: Type,LogLevel,Flags,optional1,optional2,optional3 +# +# Type +# 0 - (None) +# 1 - (Console) +# 2 - (File) +# 3 - (DB) +# +# LogLevel +# 0 - (Disabled) +# 1 - (Trace) +# 2 - (Debug) +# 3 - (Info) +# 4 - (Warn) +# 5 - (Error) +# 6 - (Fatal) +# +# Flags: +# 0 - None +# 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) +# +# Colors (read as optional1 if Type = Console) +# Format: "fatal error warn info debug trace" +# 0 - BLACK +# 1 - RED +# 2 - GREEN +# 3 - BROWN +# 4 - BLUE +# 5 - MAGENTA +# 6 - CYAN +# 7 - GREY +# 8 - YELLOW +# 9 - LRED +# 10 - LGREEN +# 11 - LBLUE +# 12 - LMAGENTA +# 13 - LCYAN +# 14 - WHITE +# Example: "13 11 9 5 3 1" +# +# File: Name of the file (read as optional1 if Type = File) +# Allows to use one "%s" to create dynamic files +# +# Mode: Mode to open the file (read as optional2 if Type = File) +# a - (Append) +# w - (Overwrite) +# +# MaxFileSize: Maximum file size of the log file before creating a new log file +# (read as optional3 if Type = File) +# Size is measured in bytes expressed in a 64-bit unsigned integer. +# Maximum value is 4294967295 (4 gb). Leave blank for no limit. +# NOTE: Does not work with dynamic filenames. +# Example: 536870912 (512 mb) +# + +Appender.Console=1,2,0 +Appender.Auth=2,2,0,Auth.log,w + +# Logger config values: Given a logger "name" +# Logger.name +# Description: Defines 'What to log' +# Format: LogLevel,AppenderList +# +# LogLevel +# 0 - (Disabled) +# 1 - (Trace) +# 2 - (Debug) +# 3 - (Info) +# 4 - (Warn) +# 5 - (Error) +# 6 - (Fatal) +# +# AppenderList: List of appenders linked to logger +# (Using spaces as separator). +# + +Logger.root=3,Console Auth + +# +################################################################################################### diff --git a/src/server/bnetserver/bnetserver.ico b/src/server/bnetserver/bnetserver.ico new file mode 100644 index 00000000000..da318f48a8c Binary files /dev/null and b/src/server/bnetserver/bnetserver.ico differ diff --git a/src/server/bnetserver/bnetserver.rc b/src/server/bnetserver/bnetserver.rc new file mode 100644 index 00000000000..f030203fdcd --- /dev/null +++ b/src/server/bnetserver/bnetserver.rc @@ -0,0 +1,94 @@ +/* + * 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 "resource.h" +#include "revision.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" //"afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APPICON ICON "bnetserver.ico" + +///////////////////////////////////////////////////////////////////////////// +// Neutre (Par défaut système) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_PRODUCTVERSION + +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + +#ifndef _DEBUG + FILEFLAGS 0 +#else + #define VER_PRERELEASE VS_FF_PRERELEASE + #define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD + #define VER_DEBUG 0 + FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG) +#endif + +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080004b0" + BEGIN + VALUE "CompanyName", VER_COMPANYNAME_STR + VALUE "FileDescription", "TrinityCore Battle.net Server Daemon" + VALUE "FileVersion", VER_FILEVERSION_STR + VALUE "InternalName", "bnetserver" + VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR + VALUE "OriginalFilename", "bnetserver.exe" + VALUE "ProductName", "TrinityCore Battle.net Server" + VALUE "ProductVersion", VER_PRODUCTVERSION_STR + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x800, 1200 + END +END +#endif diff --git a/src/server/bnetserver/resource.h b/src/server/bnetserver/resource.h new file mode 100644 index 00000000000..7dc5cb9ef7b --- /dev/null +++ b/src/server/bnetserver/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by TrinityCore.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif -- cgit v1.2.3 From f52e921521b7a29b5ec971875d4be1a44f2f839c Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 10 Oct 2014 23:22:11 +0200 Subject: Core/Config: Removed bnet port from authserver and authserver port from bnet config giles --- src/server/authserver/authserver.conf.dist | 7 ------- src/server/bnetserver/bnetserver.conf.dist | 11 ++--------- 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index e0ef6982353..b7dee9ac08b 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -53,13 +53,6 @@ MaxPingTime = 30 RealmServerPort = 3724 -# -# BattlenetPort -# Description: TCP port to reach the auth server for battle.net connections. -# Default: 1119 - -BattlenetPort = 1119 - # # # BindIP diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index e0ef6982353..2ca57cea20c 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -46,13 +46,6 @@ LogsDir = "" MaxPingTime = 30 -# -# RealmServerPort -# Description: TCP port to reach the auth server. -# Default: 3724 - -RealmServerPort = 3724 - # # BattlenetPort # Description: TCP port to reach the auth server for battle.net connections. @@ -231,7 +224,7 @@ Wrong.Password.Login.Logging = 0 # Appender.Console=1,2,0 -Appender.Auth=2,2,0,Auth.log,w +Appender.Bnet=2,2,0,Bnet.log,w # Logger config values: Given a logger "name" # Logger.name @@ -251,7 +244,7 @@ Appender.Auth=2,2,0,Auth.log,w # (Using spaces as separator). # -Logger.root=3,Console Auth +Logger.root=3,Console Bnet # ################################################################################################### -- cgit v1.2.3 From 00603772df8dfbbbcc0050813cde1b50619685d6 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 10 Oct 2014 23:48:01 +0200 Subject: Core/Battle.net: Added missing includes and changed default config file name --- src/server/bnetserver/Main.cpp | 2 +- .../bnetserver/Packets/AuthenticationPackets.h | 2 + src/server/bnetserver/Server/Session.cpp | 304 ++++++++++----------- 3 files changed, 155 insertions(+), 153 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index cb9bab97841..e208f3cd1d9 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -46,7 +46,7 @@ using boost::asio::ip::tcp; using namespace boost::program_options; #ifndef _TRINITY_BNET_CONFIG -# define _TRINITY_BNET_CONFIG "authserver.conf" +# define _TRINITY_BNET_CONFIG "bnetserver.conf" #endif bool StartDB(); diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.h b/src/server/bnetserver/Packets/AuthenticationPackets.h index 8003e13db24..72e598b858e 100644 --- a/src/server/bnetserver/Packets/AuthenticationPackets.h +++ b/src/server/bnetserver/Packets/AuthenticationPackets.h @@ -19,6 +19,8 @@ #define AuthenticationPackets_h__ #include "PacketsBase.h" +#include "ComponentManager.h" +#include "ModuleManager.h" namespace Battlenet { diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 8935d520c40..1d8e0136af3 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -94,7 +94,7 @@ void Battlenet::Session::LogUnhandledPacket(ClientPacket const& packet) TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::LogUnhandledPacket %s", packet.ToString().c_str()); } -void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& info) +void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& logonRequest) { // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); @@ -104,55 +104,55 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& stmt->setString(0, ip_address); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(LOGIN_BANNED); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(LOGIN_BANNED); + AsyncWrite(logonResponse); TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); return; } - if (info.Program != "WoW") + if (logonRequest.Program != "WoW") { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_INVALID_PROGRAM); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); + AsyncWrite(logonResponse); return; } - if (!sComponentMgr->HasPlatform(info.Platform)) + if (!sComponentMgr->HasPlatform(logonRequest.Platform)) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_INVALID_OS); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_INVALID_OS); + AsyncWrite(logonResponse); return; } - if (!sComponentMgr->HasPlatform(info.Locale)) + if (!sComponentMgr->HasPlatform(logonRequest.Locale)) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); + AsyncWrite(logonResponse); return; } - for (Component const& component : info.Components) + for (Component const& component : logonRequest.Components) { if (!sComponentMgr->HasComponent(&component)) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (!sComponentMgr->HasProgram(component.Program)) - complete->SetAuthResult(AUTH_INVALID_PROGRAM); + logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); else if (!sComponentMgr->HasPlatform(component.Platform)) - complete->SetAuthResult(AUTH_INVALID_OS); + logonResponse->SetAuthResult(AUTH_INVALID_OS); else { if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) - complete->SetAuthResult(AUTH_REGION_BAD_VERSION); + logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION); else - complete->SetAuthResult(AUTH_USE_GRUNT_LOGON); + logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON); } - AsyncWrite(complete); + AsyncWrite(logonResponse); return; } @@ -160,9 +160,9 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& _build = component.Build; } - _accountName = info.Login; - _locale = info.Locale; - _os = info.Platform; + _accountName = logonRequest.Login; + _locale = logonRequest.Locale; + _os = logonRequest.Platform; Utf8ToUpperOnlyLatin(_accountName); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); @@ -171,9 +171,9 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(logonResponse); return; } @@ -188,9 +188,9 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(logonResponse); return; } } @@ -213,9 +213,9 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); if (loginCountry != accountCountry) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_ACCOUNT_LOCKED); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); + AsyncWrite(logonResponse); return; } } @@ -234,17 +234,17 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& Field* fields = banresult->Fetch(); if (fields[0].GetUInt32() == fields[1].GetUInt32()) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(LOGIN_BANNED); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(LOGIN_BANNED); + AsyncWrite(logonResponse); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } else { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(LOGIN_SUSPENDED); - AsyncWrite(complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(LOGIN_SUSPENDED); + AsyncWrite(logonResponse); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } @@ -291,32 +291,32 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& _modulesWaitingForData.push(MODULE_PASSWORD); - Authentication::ProofRequest* request = new Authentication::ProofRequest(); - request->Modules.push_back(password); + Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); + proofRequest->Modules.push_back(password); // if has authenticator, send Token module - request->Modules.push_back(thumbprint); - AsyncWrite(request); + proofRequest->Modules.push_back(thumbprint); + AsyncWrite(proofRequest); } -void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& reconnect) +void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest) { - _accountName = reconnect.Login; - _locale = reconnect.Locale; - _os = reconnect.Platform; - auto baseComponent = std::find_if(reconnect.Components.begin(), reconnect.Components.end(), [](Component const& c) { return c.Program == "base"; }); - if (baseComponent != reconnect.Components.end()) + _accountName = resumeRequest.Login; + _locale = resumeRequest.Locale; + _os = resumeRequest.Platform; + auto baseComponent = std::find_if(resumeRequest.Components.begin(), resumeRequest.Components.end(), [](Component const& c) { return c.Program == "base"; }); + if (baseComponent != resumeRequest.Components.end()) _build = baseComponent->Build; Utf8ToUpperOnlyLatin(_accountName); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_RECONNECT_INFO); stmt->setString(0, _accountName); - stmt->setString(1, reconnect.GameAccountName); + stmt->setString(1, resumeRequest.GameAccountName); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - Authentication::ResumeResponse* resume = new Authentication::ResumeResponse(); - resume->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - AsyncWrite(resume); + Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); + resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + AsyncWrite(resumeResponse); return; } @@ -325,7 +325,7 @@ void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const _accountId = fields[0].GetUInt32(); K.SetHexStr(fields[1].GetString().c_str()); _gameAccountId = fields[2].GetUInt32(); - _gameAccountName = reconnect.GameAccountName; + _gameAccountName = resumeRequest.GameAccountName; ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); ModuleInfo* resume = sModuleMgr->CreateModule(_os, "Resume"); @@ -342,15 +342,15 @@ void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const _modulesWaitingForData.push(MODULE_RESUME); - Authentication::ProofRequest* request = new Authentication::ProofRequest(); - request->Modules.push_back(thumbprint); - request->Modules.push_back(resume); - AsyncWrite(request); + Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); + proofRequest->Modules.push_back(thumbprint); + proofRequest->Modules.push_back(resume); + AsyncWrite(proofRequest); } -void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proof) +void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proofResponse) { - if (_modulesWaitingForData.size() < proof.Modules.size()) + if (_modulesWaitingForData.size() < proofResponse.Modules.size()) { Authentication::LogonResponse* complete = new Authentication::LogonResponse(); complete->SetAuthResult(AUTH_CORRUPTED_MODULE); @@ -359,9 +359,9 @@ void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const } ServerPacket* response = nullptr; - for (size_t i = 0; i < proof.Modules.size(); ++i) + for (size_t i = 0; i < proofResponse.Modules.size(); ++i) { - if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proof.Modules[i], &response)) + if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proofResponse.Modules[i], &response)) break; _modulesWaitingForData.pop(); @@ -400,7 +400,7 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque { sRealmList->UpdateIfNeed(); - WoWRealm::ListSubscribeResponse* counts = new WoWRealm::ListSubscribeResponse(); + WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); stmt->setUInt32(0, _gameAccountId); @@ -411,7 +411,7 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque { Field* fields = countResult->Fetch(); uint32 build = fields[4].GetUInt32(); - counts->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + listSubscribeResponse->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); } while (countResult->NextRow()); } @@ -428,62 +428,62 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for } - WoWRealm::ListUpdate* update = new WoWRealm::ListUpdate(); - update->Timezone = realm.timezone; - update->Population = realm.populationLevel; - update->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - update->Type = realm.icon; - update->Name = realm.name; + WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); + listUpdate->Timezone = realm.timezone; + listUpdate->Population = realm.populationLevel; + listUpdate->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + listUpdate->Type = realm.icon; + listUpdate->Name = realm.name; if (flag & REALM_FLAG_SPECIFYBUILD) { std::ostringstream version; version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; - update->Version = version.str(); - update->Address = realm.GetAddressForClient(GetRemoteIpAddress()); - update->Build = buildInfo->Build; + listUpdate->Version = version.str(); + listUpdate->Address = realm.GetAddressForClient(GetRemoteIpAddress()); + listUpdate->Build = buildInfo->Build; } - update->Flags = flag; - update->Region = realm.Region; - update->Battlegroup = realm.Battlegroup; - update->Index = realm.m_ID; + listUpdate->Flags = flag; + listUpdate->Region = realm.Region; + listUpdate->Battlegroup = realm.Battlegroup; + listUpdate->Index = realm.m_ID; - counts->RealmData.push_back(update); + listSubscribeResponse->RealmData.push_back(listUpdate); } - counts->RealmData.push_back(new WoWRealm::ListComplete()); + listSubscribeResponse->RealmData.push_back(new WoWRealm::ListComplete()); - AsyncWrite(counts); + AsyncWrite(listSubscribeResponse); } -void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join) +void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest) { - WoWRealm::JoinResponseV2* result = new WoWRealm::JoinResponseV2(); - Realm const* realm = sRealmList->GetRealm(join.Realm); + WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); + Realm const* realm = sRealmList->GetRealm(joinRequest.Realm); if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) { - result->Response = WoWRealm::JoinResponseV2::FAILURE; - AsyncWrite(result); + joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; + AsyncWrite(joinResponse); return; } - result->ServerSeed = uint32(rand32()); + joinResponse->ServerSeed = uint32(rand32()); uint8 sessionKey[40]; HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get()); hmac.UpdateData((uint8*)"WoW\0", 4); - hmac.UpdateData((uint8*)&join.ClientSeed, 4); - hmac.UpdateData((uint8*)&result->ServerSeed, 4); + hmac.UpdateData((uint8*)&joinRequest.ClientSeed, 4); + hmac.UpdateData((uint8*)&joinResponse->ServerSeed, 4); hmac.Finalize(); memcpy(sessionKey, hmac.GetDigest(), hmac.GetLength()); HmacSha1 hmac2(K.GetNumBytes(), K.AsByteArray().get()); hmac2.UpdateData((uint8*)"WoW\0", 4); - hmac2.UpdateData((uint8*)&result->ServerSeed, 4); - hmac2.UpdateData((uint8*)&join.ClientSeed, 4); + hmac2.UpdateData((uint8*)&joinResponse->ServerSeed, 4); + hmac2.UpdateData((uint8*)&joinRequest.ClientSeed, 4); hmac2.Finalize(); memcpy(sessionKey + hmac.GetLength(), hmac2.GetDigest(), hmac2.GetLength()); @@ -491,11 +491,11 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); - result->IPv4.emplace_back(realm->ExternalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->port); if (realm->ExternalAddress != realm->LocalAddress) - result->IPv4.emplace_back(realm->LocalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->port); - AsyncWrite(result); + AsyncWrite(joinResponse); } void Battlenet::Session::ReadHandler() @@ -586,17 +586,17 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke { if (dataStream->GetSize() != 1 + 128 + 32 + 128) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, logonResponse); return false; } if (dataStream->Read(8) != 2) // State { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, logonResponse); return false; } @@ -608,9 +608,9 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke if (A.isZero()) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, logonResponse); return false; } @@ -684,9 +684,9 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke stmt->setString(0, _accountName); LoginDatabase.Execute(stmt); - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, logonResponse); return false; } @@ -699,9 +699,9 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke if (!numAccounts) { - Authentication::LogonResponse* noAccounts = new Authentication::LogonResponse(); - noAccounts->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); - ReplaceResponse(response, noAccounts); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, logonResponse); return false; } @@ -731,8 +731,8 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke password->Data = new uint8[password->DataSize]; memcpy(password->Data, stream.GetBuffer(), password->DataSize); - Authentication::ProofRequest* request = new Authentication::ProofRequest(); - request->Modules.push_back(password); + Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); + proofRequest->Modules.push_back(password); if (numAccounts > 1) { BitStream accounts; @@ -757,39 +757,39 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke selectGameAccount->DataSize = accounts.GetSize(); selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); - request->Modules.push_back(selectGameAccount); + proofRequest->Modules.push_back(selectGameAccount); _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); } else { if (fields[4].GetBool()) { - delete request; + delete proofRequest; - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (fields[2].GetUInt32() == fields[3].GetUInt32()) { - complete->SetAuthResult(LOGIN_BANNED); + logonResponse->SetAuthResult(LOGIN_BANNED); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } else { - complete->SetAuthResult(LOGIN_SUSPENDED); + logonResponse->SetAuthResult(LOGIN_SUSPENDED); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } - ReplaceResponse(response, complete); + ReplaceResponse(response, logonResponse); return false; } _gameAccountId = fields[0].GetUInt32(); _gameAccountName = fields[1].GetString(); - request->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); + proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); } - ReplaceResponse(response, request); + ReplaceResponse(response, proofRequest); return true; } @@ -797,9 +797,9 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se { if (dataStream->Read(8) != 1) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, logonResponse); return false; } @@ -807,9 +807,9 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se std::string account = dataStream->ReadString(8); if (account.empty()) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); + ReplaceResponse(response, logonResponse); return false; } @@ -838,28 +838,28 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se Field* fields = result->Fetch(); if (fields[4].GetBool()) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (fields[2].GetUInt32() == fields[3].GetUInt32()) { - complete->SetAuthResult(LOGIN_BANNED); + logonResponse->SetAuthResult(LOGIN_BANNED); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } else { - complete->SetAuthResult(LOGIN_SUSPENDED); + logonResponse->SetAuthResult(LOGIN_SUSPENDED); TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } - ReplaceResponse(response, complete); + ReplaceResponse(response, logonResponse); return false; } _gameAccountId = fields[0].GetUInt32(); _gameAccountName = fields[1].GetString(); - Authentication::ProofRequest* request = new Authentication::ProofRequest(); - request->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); - ReplaceResponse(response, request); + Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); + proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); + ReplaceResponse(response, proofRequest); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); return true; @@ -867,16 +867,16 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (dataStream->Read(8) == 1) { - complete->AccountId = _accountId; - complete->GameAccountName = _gameAccountName; - complete->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; + logonResponse->AccountId = _accountId; + logonResponse->GameAccountName = _gameAccountName; + logonResponse->GameAccountFlags = GAMEACCOUNT_FLAG_PROPASS_LOCK; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_FAILED_LOGINS); stmt->setUInt32(0, _accountId); if (PreparedQueryResult failedLoginsResult = LoginDatabase.Query(stmt)) - complete->FailedLogins = (*failedLoginsResult)[0].GetUInt32(); + logonResponse->FailedLogins = (*failedLoginsResult)[0].GetUInt32(); SQLTransaction trans = LoginDatabase.BeginTransaction(); @@ -899,9 +899,9 @@ bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, Serv sSessionMgr.AddSession(this); } else - complete->SetAuthResult(AUTH_BAD_VERSION_HASH); + logonResponse->SetAuthResult(AUTH_BAD_VERSION_HASH); - ReplaceResponse(response, complete); + ReplaceResponse(response, logonResponse); return true; } @@ -909,9 +909,9 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* { if (dataStream->Read(8) != 1) { - Authentication::ResumeResponse* complete = new Authentication::ResumeResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); + resumeResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, resumeResponse); return false; } @@ -954,9 +954,9 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* LoginDatabase.Execute(stmt); TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); - Authentication::ResumeResponse* result = new Authentication::ResumeResponse(); - result->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); - ReplaceResponse(response, result); + Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); + resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); + ReplaceResponse(response, resumeResponse); return false; } @@ -983,9 +983,9 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* resume->Data = new uint8[resume->DataSize]; memcpy(resume->Data, resumeData.GetBuffer(), resume->DataSize); - Authentication::ResumeResponse* result = new Authentication::ResumeResponse(); - result->Modules.push_back(resume); - ReplaceResponse(response, result); + Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); + resumeResponse->Modules.push_back(resume); + ReplaceResponse(response, resumeResponse); _authed = true; sSessionMgr.AddSession(this); return true; @@ -993,8 +993,8 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) { - Authentication::LogonResponse* complete = new Authentication::LogonResponse(); - complete->SetAuthResult(AUTH_CORRUPTED_MODULE); - ReplaceResponse(response, complete); + Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); + logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); + ReplaceResponse(response, logonResponse); return false; } -- cgit v1.2.3 From 56cf7ff2a8f1e0a710544ec6300a21cfa44c0f73 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 11 Oct 2014 15:13:30 +0200 Subject: Core/Battle.net: Implemented updating realm list after initial login --- src/server/authserver/Realms/RealmList.cpp | 10 +- src/server/authserver/Realms/RealmList.h | 4 +- src/server/bnetserver/Main.cpp | 9 +- src/server/bnetserver/Packets/FriendsPackets.cpp | 22 ++-- src/server/bnetserver/Packets/FriendsPackets.h | 11 +- src/server/bnetserver/Packets/PacketFactory.h | 5 +- src/server/bnetserver/Packets/WoWRealmPackets.cpp | 20 +++- src/server/bnetserver/Packets/WoWRealmPackets.h | 21 +++- src/server/bnetserver/Realms/RealmList.cpp | 133 +++++++++++++--------- src/server/bnetserver/Realms/RealmList.h | 74 ++++++------ src/server/bnetserver/Server/Session.cpp | 110 +++++++++++------- src/server/bnetserver/Server/Session.h | 15 +++ src/server/bnetserver/Server/SessionManager.cpp | 12 ++ src/server/bnetserver/Server/SessionManager.h | 20 +++- src/server/bnetserver/bnetserver.conf.dist | 4 +- 15 files changed, 283 insertions(+), 187 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 662a015dc65..15302c74ac6 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -77,7 +77,7 @@ void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInte } 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) + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -90,15 +90,11 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address cons realm.allowedSecurityLevel = allowedSecurityLevel; 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; } void RealmList::UpdateIfNeed() @@ -174,11 +170,9 @@ void RealmList::UpdateRealms(bool init) 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); + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); if (init) TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index f7a98cda686..9d5771144a9 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -54,8 +54,6 @@ struct Realm AccountTypes allowedSecurityLevel; float populationLevel; uint32 gamebuild; - uint8 Region; - uint8 Battlegroup; ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; }; @@ -89,7 +87,7 @@ private: 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); + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index e208f3cd1d9..5e0d728d724 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -99,14 +99,7 @@ int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - - if (sRealmList->size() == 0) - { - TC_LOG_ERROR("server.bnetserver", "No valid realms specified."); - StopDB(); - return 1; - } + sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10)); // Start the listening port (acceptor) for auth connections int32 bnport = sConfigMgr->GetIntDefault("BattlenetPort", 1119); diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index 784d6980777..cd920e91c9c 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -18,23 +18,22 @@ #include "Session.h" #include "FriendsPackets.h" -void Battlenet::Friends::SocialnetworkCheckConnected::Read() +void Battlenet::Friends::SocialNetworkCheckConnected::Read() { SocialNetworkId = _stream.Read(32); } -std::string Battlenet::Friends::SocialnetworkCheckConnected::ToString() const +std::string Battlenet::Friends::SocialNetworkCheckConnected::ToString() const { - return "Battlenet::Friends::SocialnetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); + return "Battlenet::Friends::SocialNetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); } -void Battlenet::Friends::SocialnetworkCheckConnected::CallHandler(Session* session) const +void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) const { - SocialNetworkCheckConnectedResult* result = new SocialNetworkCheckConnectedResult(SocialNetworkId); - session->AsyncWrite(result); + session->HandleSocialNetworkCheckConnected(*this); } -void Battlenet::Friends::SocialnetworkConnect::Read() +void Battlenet::Friends::SocialNetworkConnect::Read() { int32 unk1 = _stream.Read(32); uint32 size1 = _stream.Read(9); @@ -43,12 +42,12 @@ void Battlenet::Friends::SocialnetworkConnect::Read() auto data2 = _stream.ReadBytes(size2); } -std::string Battlenet::Friends::SocialnetworkConnect::ToString() const +std::string Battlenet::Friends::SocialNetworkConnect::ToString() const { - return "Battlenet::Friends::SocialnetworkConnect"; + return "Battlenet::Friends::SocialNetworkConnect"; } -void Battlenet::Friends::SocialnetworkConnect::CallHandler(Session* session) const +void Battlenet::Friends::SocialNetworkConnect::CallHandler(Session* session) const { session->LogUnhandledPacket(*this); } @@ -70,8 +69,7 @@ std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() co void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() { _stream.Write(0, 23); // Ignored - volatile uint16 res = 0; - _stream.Write(res, 16); // Unknown + _stream.Write(0, 16); // Unknown _stream.Write(SocialNetworkId, 32); } diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h index a0ef6f4a63f..ec20f202098 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.h +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -54,10 +54,10 @@ namespace Battlenet SMSG_FRIENDS_LIST_NOTIFY_3 = 0x18 // Not implemented }; - class SocialnetworkConnect final : public ClientPacket + class SocialNetworkConnect final : public ClientPacket { public: - SocialnetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + SocialNetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialnetworkConnect"); } @@ -78,10 +78,10 @@ namespace Battlenet std::string ToString() const override; }; - class SocialnetworkCheckConnected final : public ClientPacket + class SocialNetworkCheckConnected final : public ClientPacket { public: - SocialnetworkCheckConnected(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + SocialNetworkCheckConnected(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS) && "Invalid packet header for SocialNetworkCheckConnected"); } @@ -96,7 +96,8 @@ namespace Battlenet class SocialNetworkCheckConnectedResult final : public ServerPacket { public: - SocialNetworkCheckConnectedResult(uint32 socialNetworkId) : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), SocialNetworkId(socialNetworkId) + SocialNetworkCheckConnectedResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), + SocialNetworkId(0) { } diff --git a/src/server/bnetserver/Packets/PacketFactory.h b/src/server/bnetserver/Packets/PacketFactory.h index 4ae6338cfd7..418e56abea4 100644 --- a/src/server/bnetserver/Packets/PacketFactory.h +++ b/src/server/bnetserver/Packets/PacketFactory.h @@ -57,10 +57,11 @@ namespace Battlenet _creators[PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION)] = &New; _creators[PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM)] = &New; + _creators[PacketHeader(WoWRealm::CMSG_LIST_UNSUBSCRIBE, WOWREALM)] = &New; _creators[PacketHeader(WoWRealm::CMSG_JOIN_REQUEST_V2, WOWREALM)] = &New; - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New; - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New; + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New; + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New; _creators[PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS)] = &New; _creators[PacketHeader(Friends::CMSG_REALID_FRIEND_INVITE, FRIENDS)] = &New; diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index 6845fc914b1..95176963c18 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -30,6 +30,16 @@ void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session) co session->HandleListSubscribeRequest(*this); } +std::string Battlenet::WoWRealm::ListUnsubscribe::ToString() const +{ + return "Battlenet::WoWRealm::ListUnsubscribe"; +} + +void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) const +{ + session->HandleListUnsubscribe(*this); +} + Battlenet::WoWRealm::ListSubscribeResponse::~ListSubscribeResponse() { for (ServerPacket* realmData : RealmData) @@ -95,7 +105,7 @@ void Battlenet::WoWRealm::ListUpdate::Write() if (!Version.empty()) { _stream.WriteString(Version, 5); - _stream.Write(Build, 32); + _stream.Write(Id.Build, 32); boost::asio::ip::address_v4::bytes_type ip = Address.address().to_v4().to_bytes(); uint16 port = Address.port(); @@ -110,16 +120,16 @@ void Battlenet::WoWRealm::ListUpdate::Write() _stream.WriteString(Name, 10); } - _stream.Write(Battlegroup, 8); - _stream.Write(Index, 32); - _stream.Write(Region, 8); + _stream.Write(Id.Battlegroup, 8); + _stream.Write(Id.Index, 32); + _stream.Write(Id.Region, 8); } std::string Battlenet::WoWRealm::ListUpdate::ToString() const { std::ostringstream stream; stream << "Battlenet::WoWRealm::ListUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name - << " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index; + << " Flags " << uint32(Flags) << " Region " << uint32(Id.Region) << " Battlegroup " << uint32(Id.Battlegroup) << " Index " << Id.Index; if (!Version.empty()) stream << " Version " << Version; diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index 4ce5ea68835..a27601f7478 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -53,6 +53,19 @@ namespace Battlenet void CallHandler(Session* session) const override; }; + class ListUnsubscribe final : public ClientPacket + { + public: + ListUnsubscribe(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_LIST_UNSUBSCRIBE, WOWREALM) && "Invalid packet header for ListUnsubscribe"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + class JoinRequestV2 final : public ClientPacket { public: @@ -110,8 +123,7 @@ namespace Battlenet }; ListUpdate() : ServerPacket(PacketHeader(SMSG_LIST_UPDATE, WOWREALM)), UpdateState(UPDATE), - Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), - Flags(0), Region(0), Battlegroup(0), Index(0), Build(0) + Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), Flags(0) { } @@ -127,10 +139,7 @@ namespace Battlenet std::string Version; tcp::endpoint Address; uint8 Flags; - uint8 Region; - uint8 Battlegroup; - uint32 Index; - uint32 Build; + RealmId Id; }; class ListComplete final : public ServerPacket diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index 60d40f98edf..6e2c1e99e56 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -18,9 +18,10 @@ #include #include "Common.h" -#include "RealmList.h" #include "Database/DatabaseEnv.h" +#include "SessionManager.h" #include "Util.h" +#include "RealmList.h" ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const { @@ -51,73 +52,71 @@ ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) cons realmIp = ExternalAddress; } - ip::tcp::endpoint endpoint(realmIp, port); + ip::tcp::endpoint endpoint(realmIp, Port); // Return external IP return endpoint; } -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) +RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) { } RealmList::~RealmList() { + delete _updateTimer; delete _resolver; } // Load the realm list from the database void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _updateInterval = updateInterval; + _updateTimer = new boost::asio::deadline_timer(ioService); _resolver = new boost::asio::ip::tcp::resolver(ioService); - m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database - UpdateRealms(true); + UpdateRealms(boost::system::error_code()); } -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) +template +inline void UpdateField(FieldType& out, FieldType const& in, bool& changed) { - // Create new if not exist or update existed - Realm& realm = m_realms[name]; - - realm.m_ID = id; - realm.name = name; - realm.icon = icon; - realm.flag = flag; - realm.timezone = timezone; - realm.allowedSecurityLevel = allowedSecurityLevel; - 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; + if (out != in) + { + out = in; + changed = true; + } } -void RealmList::UpdateIfNeed() +void RealmList::UpdateRealm(Battlenet::RealmId const& 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) { - // maybe disabled or updated recently - if (!m_UpdateInterval || m_NextUpdateTime > time(NULL)) - return; - - m_NextUpdateTime = time(NULL) + m_UpdateInterval; - - // Clears Realm list - m_realms.clear(); - - // Get the content of the realmlist table in the database - UpdateRealms(); + // Create new if not exist or update existed + Realm& realm = _realms[id]; + + realm.Keep = true; + realm.Updated = false; + + realm.Id = id; + UpdateField(realm.Name, name, realm.Updated); + UpdateField(realm.Type, icon, realm.Updated); + UpdateField(realm.Flags, flag, realm.Updated); + UpdateField(realm.Timezone, timezone, realm.Updated); + UpdateField(realm.AllowedSecurityLevel, allowedSecurityLevel, realm.Updated); + UpdateField(realm.PopulationLevel, population, realm.Updated); + UpdateField(realm.ExternalAddress, address, realm.Updated); + UpdateField(realm.LocalAddress, localAddr, realm.Updated); + UpdateField(realm.LocalSubnetMask, localSubmask, realm.Updated); + UpdateField(realm.Port, port, realm.Updated); } -void RealmList::UpdateRealms(bool init) +void RealmList::UpdateRealms(boost::system::error_code const& error) { + if (error) + return; + TC_LOG_INFO("server.authserver", "Updating Realm List..."); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); @@ -133,7 +132,6 @@ void RealmList::UpdateRealms(bool init) 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(ip::tcp::v4(), fields[2].GetString(), ""); @@ -142,7 +140,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); - return; + continue; } ip::address externalAddress = (*endPoint).endpoint().address(); @@ -152,7 +150,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); - return; + continue; } ip::address localAddress = (*endPoint).endpoint().address(); @@ -162,7 +160,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); - return; + continue; } ip::address localSubmask = (*endPoint).endpoint().address(); @@ -173,15 +171,17 @@ void RealmList::UpdateRealms(bool init) uint8 timezone = fields[8].GetUInt8(); uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); + uint32 realmId = fields[0].GetUInt32(); 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); + Battlenet::RealmId id{ region, battlegroup, realmId, build }; - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); + + //TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[id].ExternalAddress.to_string().c_str(), port); } catch (std::exception& ex) { @@ -191,16 +191,41 @@ void RealmList::UpdateRealms(bool init) } while (result->NextRow()); } + + std::vector updatedRealms; + std::vector deletedRealms; + + for (RealmMap::value_type const& pair : _realms) + { + if (pair.second.Updated) + updatedRealms.push_back(&pair.second); + if (!pair.second.Keep) + deletedRealms.push_back(pair.first); + } + + for (Battlenet::RealmId const& deleted : deletedRealms) + _realms.erase(deleted); + + if (!updatedRealms.empty() || !deletedRealms.empty()) + { + sSessionMgr.LockedForEach([&updatedRealms, &deletedRealms](Battlenet::Session* session) + { + if (session->IsSubscribedToRealmListUpdates()) + session->UpdateRealms(updatedRealms, deletedRealms); + }); + } + + if (_updateInterval) + { + _updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); + _updateTimer->async_wait(std::bind(&RealmList::UpdateRealms, this, std::placeholders::_1)); + } } Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const { - auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair) - { - return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index; - }); - - if (itr != m_realms.end()) + auto itr = _realms.find(id); + if (itr != _realms.end()) return &itr->second; return NULL; diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index 502fef80ee7..c7108101056 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -39,43 +39,55 @@ enum RealmFlags REALM_FLAG_FULL = 0x80 }; -// Storage object for a realm -struct Realm -{ - ip::address ExternalAddress; - ip::address LocalAddress; - ip::address LocalSubnetMask; - uint16 port; - std::string name; - uint8 icon; - RealmFlags flag; - uint8 timezone; - uint32 m_ID; - AccountTypes allowedSecurityLevel; - float populationLevel; - uint32 gamebuild; - uint8 Region; - uint8 Battlegroup; - - ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; -}; +#pragma pack(push, 1) namespace Battlenet { struct RealmId { + RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { } + RealmId(uint8 region, uint8 battlegroup, uint32 index, uint32 build) + : Region(region), Battlegroup(battlegroup), Index(index), Build(build) { } + uint8 Region; uint8 Battlegroup; uint32 Index; uint32 Build; + + bool operator<(RealmId const& r) const + { + return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0; + } }; } +#pragma pack(pop) + +// Storage object for a realm +struct Realm +{ + Battlenet::RealmId Id; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 Port; + std::string Name; + uint8 Type; + RealmFlags Flags; + uint8 Timezone; + AccountTypes AllowedSecurityLevel; + float PopulationLevel; + bool Updated; + bool Keep; + + ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; +}; + /// Storage object for the list of realms on the server class RealmList { public: - typedef std::map RealmMap; + typedef std::map RealmMap; static RealmList* instance() { @@ -87,25 +99,19 @@ public: void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); - void UpdateIfNeed(); - - void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; } - - RealmMap::const_iterator begin() const { return m_realms.begin(); } - RealmMap::const_iterator end() const { return m_realms.end(); } - uint32 size() const { return m_realms.size(); } + RealmMap const& GetRealms() const { return _realms; } Realm const* GetRealm(Battlenet::RealmId const& id) const; private: 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); + void UpdateRealms(boost::system::error_code const& error); + void UpdateRealm(Battlenet::RealmId const& 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); - RealmMap m_realms; - uint32 m_UpdateInterval; - time_t m_NextUpdateTime; + RealmMap _realms; + uint32 _updateInterval; + boost::asio::deadline_timer* _updateTimer; boost::asio::ip::tcp::resolver* _resolver; }; diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 1d8e0136af3..301a6b9bae1 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -38,7 +38,7 @@ Battlenet::Session::ModuleHandler const Battlenet::Session::ModuleHandlers[MODUL Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountId(0), _accountName(), _locale(), _os(), _build(0), _gameAccountId(0), _gameAccountName(), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), - _reconnectProof(), _crypt(), _authed(false) + _reconnectProof(), _crypt(), _authed(false), _subscribedToRealmListUpdates(false) { static uint8 const N_Bytes[] = { @@ -398,8 +398,6 @@ void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /* void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/) { - sRealmList->UpdateIfNeed(); - WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); @@ -411,58 +409,29 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque { Field* fields = countResult->Fetch(); uint32 build = fields[4].GetUInt32(); - listSubscribeResponse->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + listSubscribeResponse->CharacterCounts.push_back({ RealmId(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0)), fields[0].GetUInt8() }); } while (countResult->NextRow()); } - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) - { - Realm const& realm = i->second; - - uint32 flag = realm.flag & ~REALM_FLAG_SPECIFYBUILD; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (realm.gamebuild != _build) - { - flag |= REALM_FLAG_INVALID; - if (buildInfo) - flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for - } - - WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); - listUpdate->Timezone = realm.timezone; - listUpdate->Population = realm.populationLevel; - listUpdate->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - listUpdate->Type = realm.icon; - listUpdate->Name = realm.name; - - if (flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream version; - version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; - - listUpdate->Version = version.str(); - listUpdate->Address = realm.GetAddressForClient(GetRemoteIpAddress()); - listUpdate->Build = buildInfo->Build; - } - - listUpdate->Flags = flag; - listUpdate->Region = realm.Region; - listUpdate->Battlegroup = realm.Battlegroup; - listUpdate->Index = realm.m_ID; - - listSubscribeResponse->RealmData.push_back(listUpdate); - } + for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms()) + listSubscribeResponse->RealmData.push_back(BuildListUpdate(&i.second)); listSubscribeResponse->RealmData.push_back(new WoWRealm::ListComplete()); AsyncWrite(listSubscribeResponse); + _subscribedToRealmListUpdates = true; +} + +void Battlenet::Session::HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& /*listUnsubscribe*/) +{ + _subscribedToRealmListUpdates = false; } void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest) { WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); Realm const* realm = sRealmList->GetRealm(joinRequest.Realm); - if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) + if (!realm || realm->Flags & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) { joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; AsyncWrite(joinResponse); @@ -491,13 +460,20 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); - joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port); if (realm->ExternalAddress != realm->LocalAddress) - joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->Port); AsyncWrite(joinResponse); } +void Battlenet::Session::HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected) +{ + Friends::SocialNetworkCheckConnectedResult* socialNetworkCheckConnectedResult = new Friends::SocialNetworkCheckConnectedResult(); + socialNetworkCheckConnectedResult->SocialNetworkId = socialNetworkCheckConnected.SocialNetworkId; + AsyncWrite(socialNetworkCheckConnectedResult); +} + void Battlenet::Session::ReadHandler() { BitStream stream(std::move(GetReadBuffer())); @@ -998,3 +974,49 @@ bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket ReplaceResponse(response, logonResponse); return false; } + +void Battlenet::Session::UpdateRealms(std::vector& realms, std::vector& deletedRealms) +{ + for (Realm const* realm : realms) + AsyncWrite(BuildListUpdate(realm)); + + for (RealmId& deleted : deletedRealms) + { + WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); + listUpdate->UpdateState = WoWRealm::ListUpdate::DELETED; + listUpdate->Id = deleted; + AsyncWrite(listUpdate); + } +} + +Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const* realm) const +{ + uint32 flag = realm->Flags & ~REALM_FLAG_SPECIFYBUILD; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm->Id.Build); + if (realm->Id.Build != _build) + { + flag |= REALM_FLAG_INVALID; + if (buildInfo) + flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); + listUpdate->Timezone = realm->Timezone; + listUpdate->Population = realm->PopulationLevel; + listUpdate->Lock = (realm->AllowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + listUpdate->Type = realm->Type; + listUpdate->Name = realm->Name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; + + listUpdate->Version = version.str(); + listUpdate->Address = realm->GetAddressForClient(GetRemoteIpAddress()); + } + + listUpdate->Flags = flag; + listUpdate->Id = realm->Id; + return listUpdate; +} diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 41caadbab3f..7def3c70460 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -25,6 +25,7 @@ #include #include +struct Realm; using boost::asio::ip::tcp; namespace Battlenet @@ -73,12 +74,23 @@ namespace Battlenet // WoWRealm void HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& listSubscribeRequest); + void HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& listUnsubscribe); void HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest); + // Friends + void HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected); + void Start() override; + void UpdateRealms(std::vector& realms, std::vector& deletedRealms); + void AsyncWrite(ServerPacket* packet); + uint32 GetAccountId() const { return _accountId; } + uint32 GetGameAccountId() const { return _gameAccountId; } + + bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; } + protected: void ReadHandler() override; @@ -94,6 +106,8 @@ namespace Battlenet bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const; + uint32 _accountId; std::string _accountName; std::string _locale; @@ -121,6 +135,7 @@ namespace Battlenet PacketCrypt _crypt; bool _authed; + bool _subscribedToRealmListUpdates; }; } diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index d8b6bfca8d1..caa17364038 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -35,3 +35,15 @@ void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock) { sSessionMgr.OnSocketOpen(std::forward(sock)); } + +void Battlenet::SessionManager::AddSession(Session* session) +{ + std::unique_lock lock(_sessionMutex); + _sessions[{ session->GetAccountId(), session->GetGameAccountId() }] = session; +} + +void Battlenet::SessionManager::RemoveSession(Session* session) +{ + std::unique_lock lock(_sessionMutex); + _sessions.erase({ session->GetAccountId(), session->GetGameAccountId() }); +} diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index 10e7196e4d8..4f8e0d9fa97 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -20,6 +20,8 @@ #include "Session.h" #include "SocketMgr.h" +#include +#include namespace Battlenet { @@ -28,7 +30,7 @@ namespace Battlenet struct SessionInfo { uint32 AccountId; - uint32 GameAccountIndex; + uint32 GameAccountId; bool operator<(SessionInfo const& right) const { @@ -41,6 +43,7 @@ namespace Battlenet class SessionManager : SocketMgr { typedef SocketMgr BaseSocketMgr; + typedef std::map SessionMap; public: static SessionManager& Instance() @@ -52,9 +55,17 @@ namespace Battlenet bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override; // noop for now, will be needed later to broadcast realmlist updates for example - void AddSession(Session* /*session*/) { } + void AddSession(Session* /*session*/); - void RemoveSession(Session* /*session*/) { } + void RemoveSession(Session* /*session*/); + + template + void LockedForEach(Iterator iterator) + { + boost::shared_lock lock(_sessionMutex); + for (SessionMap::value_type const& pair : _sessions) + iterator(pair.second); + } protected: NetworkThread* CreateThreads() const override; @@ -62,7 +73,8 @@ namespace Battlenet private: static void OnSocketAccept(tcp::socket&& sock); - std::map _sessions; + SessionMap _sessions; + boost::shared_mutex _sessionMutex; }; } diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 2ca57cea20c..ac02a06c918 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -91,10 +91,10 @@ ProcessPriority = 0 # # RealmsStateUpdateDelay # Description: Time (in seconds) between realm list updates. -# Default: 20 - (Enabled) +# Default: 10 # 0 - (Disabled) -RealmsStateUpdateDelay = 20 +RealmsStateUpdateDelay = 10 # # WrongPass.MaxCount -- cgit v1.2.3 From 26e4b67e851d92475e603e7073b2558427c6d23f Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 11 Oct 2014 15:16:06 +0200 Subject: Core/Battle.net: Removed remaining authserver references --- src/server/bnetserver/CMakeLists.txt | 2 +- src/server/bnetserver/Main.cpp | 15 +++++++-------- src/server/bnetserver/Realms/RealmList.cpp | 14 +++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index 3fa4abf034a..9d99ac7f0c5 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -8,7 +8,7 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -########### authserver ############### +########### bnetserver ############### file(GLOB_RECURSE sources_authentication Authentication/*.cpp Authentication/*.h) file(GLOB_RECURSE sources_realms Realms/*.cpp Realms/*.h) diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index 5e0d728d724..ff891304bd3 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -81,7 +81,7 @@ int main(int argc, char** argv) TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); TC_LOG_INFO("server.bnetserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); - // authserver PID file creation + // bnetserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); if (!pidFile.empty()) { @@ -151,32 +151,31 @@ bool StartDB() std::string dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) { - TC_LOG_ERROR("server.authserver", "Database not specified"); + TC_LOG_ERROR("server.bnetserver", "Database not specified"); return false; } int32 worker_threads = sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1); if (worker_threads < 1 || worker_threads > 32) { - TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1."); + TC_LOG_ERROR("server.bnetserver", "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1."); worker_threads = 1; } int32 synch_threads = sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1); if (synch_threads < 1 || synch_threads > 32) { - TC_LOG_ERROR("server.authserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1."); + TC_LOG_ERROR("server.bnetserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1."); synch_threads = 1; } - // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever. if (!LoginDatabase.Open(dbstring, uint8(worker_threads), uint8(synch_threads))) { - TC_LOG_ERROR("server.authserver", "Cannot connect to database"); + TC_LOG_ERROR("server.bnetserver", "Cannot connect to database"); return false; } - TC_LOG_INFO("server.authserver", "Started auth database connection pool."); + TC_LOG_INFO("server.bnetserver", "Started auth database connection pool."); sLog->SetRealmId(0); // Enables DB appenders when realm is set. return true; } @@ -198,7 +197,7 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) { if (!error) { - TC_LOG_INFO("server.authserver", "Ping MySQL to keep connection alive"); + TC_LOG_INFO("server.bnetserver", "Ping MySQL to keep connection alive"); LoginDatabase.KeepAlive(); _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval)); diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index 6e2c1e99e56..8d6edb12b5c 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -35,7 +35,7 @@ ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) cons realmIp = clientAddr; else { - // Assume that user connecting from the machine that authserver is located on + // Assume that user connecting from the machine that bnetserver is located on // has all realms available in his local network realmIp = LocalAddress; } @@ -117,7 +117,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) if (error) return; - TC_LOG_INFO("server.authserver", "Updating Realm List..."); + TC_LOG_INFO("server.bnetserver", "Updating Realm List..."); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -139,7 +139,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); + TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[2].GetString().c_str()); continue; } @@ -149,7 +149,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) endPoint = _resolver->resolve(localAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); + TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[3].GetString().c_str()); continue; } @@ -159,7 +159,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) endPoint = _resolver->resolve(localSubmaskQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); + TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[4].GetString().c_str()); continue; } @@ -181,11 +181,11 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); - //TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[id].ExternalAddress.to_string().c_str(), port); + //TC_LOG_INFO("server.bnetserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[id].ExternalAddress.to_string().c_str(), port); } catch (std::exception& ex) { - TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + TC_LOG_ERROR("server.bnetserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); ASSERT(false); } } -- cgit v1.2.3 From cbabfe99200be41be0f6362756d044b653065171 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 11 Oct 2014 22:45:01 +0200 Subject: Core/Battle.net: Handle ConnectionClosing --- .../bnetserver/Packets/AuthenticationPackets.cpp | 6 +- .../bnetserver/Packets/AuthenticationPackets.h | 30 +++++----- .../bnetserver/Packets/ConnectionPackets.cpp | 60 ++++++++++++++++++- src/server/bnetserver/Packets/ConnectionPackets.h | 69 ++++++++++++++++++++-- src/server/bnetserver/Packets/FriendsPackets.cpp | 14 +---- src/server/bnetserver/Packets/FriendsPackets.h | 8 +-- src/server/bnetserver/Packets/PacketFactory.h | 2 + src/server/bnetserver/Packets/PacketsBase.cpp | 6 ++ src/server/bnetserver/Packets/PacketsBase.h | 8 ++- src/server/bnetserver/Packets/PresencePackets.cpp | 10 ---- src/server/bnetserver/Packets/PresencePackets.h | 2 - src/server/bnetserver/Packets/WoWRealmPackets.cpp | 6 +- src/server/bnetserver/Packets/WoWRealmPackets.h | 6 +- src/server/bnetserver/Server/Session.cpp | 8 ++- src/server/bnetserver/Server/Session.h | 1 + 15 files changed, 172 insertions(+), 64 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.cpp b/src/server/bnetserver/Packets/AuthenticationPackets.cpp index ae2db016972..c1362cd5f03 100644 --- a/src/server/bnetserver/Packets/AuthenticationPackets.cpp +++ b/src/server/bnetserver/Packets/AuthenticationPackets.cpp @@ -50,7 +50,7 @@ std::string Battlenet::Authentication::LogonRequest::ToString() const return stream.str(); } -void Battlenet::Authentication::LogonRequest::CallHandler(Session* session) const +void Battlenet::Authentication::LogonRequest::CallHandler(Session* session) { session->HandleLogonRequest(*this); } @@ -89,7 +89,7 @@ std::string Battlenet::Authentication::ResumeRequest::ToString() const return stream.str(); } -void Battlenet::Authentication::ResumeRequest::CallHandler(Session* session) const +void Battlenet::Authentication::ResumeRequest::CallHandler(Session* session) { session->HandleResumeRequest(*this); } @@ -153,7 +153,7 @@ std::string Battlenet::Authentication::ProofResponse::ToString() const return stream.str(); } -void Battlenet::Authentication::ProofResponse::CallHandler(Session* session) const +void Battlenet::Authentication::ProofResponse::CallHandler(Session* session) { session->HandleProofResponse(*this); } diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.h b/src/server/bnetserver/Packets/AuthenticationPackets.h index 72e598b858e..c698d3125cf 100644 --- a/src/server/bnetserver/Packets/AuthenticationPackets.h +++ b/src/server/bnetserver/Packets/AuthenticationPackets.h @@ -49,7 +49,7 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; std::string Program; std::string Platform; @@ -68,7 +68,7 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; std::string Program; std::string Platform; @@ -91,23 +91,11 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; std::vector Modules; }; - class ProofRequest final : public ServerPacket - { - public: - ProofRequest() : ServerPacket(PacketHeader(SMSG_PROOF_REQUEST, AUTHENTICATION)) { } - ~ProofRequest(); - - void Write() override; - std::string ToString() const override; - - std::vector Modules; - }; - class ResponseFailure { public: @@ -192,6 +180,18 @@ namespace Battlenet int32 PingTimeout; Regulator RegulatorRules; }; + + class ProofRequest final : public ServerPacket + { + public: + ProofRequest() : ServerPacket(PacketHeader(SMSG_PROOF_REQUEST, AUTHENTICATION)) { } + ~ProofRequest(); + + void Write() override; + std::string ToString() const override; + + std::vector Modules; + }; } } diff --git a/src/server/bnetserver/Packets/ConnectionPackets.cpp b/src/server/bnetserver/Packets/ConnectionPackets.cpp index 0449ecbb756..aa934cb631a 100644 --- a/src/server/bnetserver/Packets/ConnectionPackets.cpp +++ b/src/server/bnetserver/Packets/ConnectionPackets.cpp @@ -23,7 +23,7 @@ std::string Battlenet::Connection::Ping::ToString() const return "Battlenet::Connection::Ping"; } -void Battlenet::Connection::Ping::CallHandler(Session* session) const +void Battlenet::Connection::Ping::CallHandler(Session* session) { session->HandlePing(*this); } @@ -33,7 +33,7 @@ std::string Battlenet::Connection::EnableEncryption::ToString() const return "Battlenet::Connection::EnableEncryption"; } -void Battlenet::Connection::EnableEncryption::CallHandler(Session* session) const +void Battlenet::Connection::EnableEncryption::CallHandler(Session* session) { session->HandleEnableEncryption(*this); } @@ -43,11 +43,65 @@ std::string Battlenet::Connection::LogoutRequest::ToString() const return "Battlenet::Connection::LogoutRequest"; } -void Battlenet::Connection::LogoutRequest::CallHandler(Session* session) const +void Battlenet::Connection::LogoutRequest::CallHandler(Session* session) { session->HandleLogoutRequest(*this); } +void Battlenet::Connection::DisconnectRequest::Read() +{ + Timeout = _stream.Read(16); + Tick = _stream.Read(32); +} + +std::string Battlenet::Connection::DisconnectRequest::ToString() const +{ + std::ostringstream str; + str << "Battlenet::Connection::DisconnectRequest Timeout: " << Timeout << ", Tick: " << Tick; + return str.str(); +} + +void Battlenet::Connection::ConnectionClosing::Read() +{ + Reason = _stream.Read(4); + if (_stream.Read(1)) // HasHeader + { + Header.Opcode = _stream.Read(6); + if (_stream.Read(1)) + Header.Channel = _stream.Read(4); + } + + Now = _stream.Read(32); + _stream.Read(25); + auto bytes = _stream.ReadBytes(_stream.Read(8)); // BadData + Packets.resize(_stream.Read(6)); + for (size_t i = 0; i < Packets.size(); ++i) + { + PacketInfo& info = Packets[i]; + info.CommandName = _stream.ReadFourCC(); + info.LayerId = _stream.Read(16); + info.Channel = _stream.ReadFourCC(); + info.Timestamp = _stream.Read(32); + info.Size = _stream.Read(16); + } +} + +std::string Battlenet::Connection::ConnectionClosing::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Connection::ConnectionClosing Reason: " << Reason << ", Now: " << Now << ", Packet history size: " << Packets.size(); + for (PacketInfo const& packet : Packets) + stream << std::endl << "Battlenet::Connection::ConnectionClosing::PacketInfo LayerId: " << packet.LayerId + << ", Channel: " << packet.Channel << ", CommandName: " << packet.CommandName << ", Size: " << packet.Size << ", Timestamp: " << packet.Timestamp; + + return stream.str(); +} + +void Battlenet::Connection::ConnectionClosing::CallHandler(Session* session) +{ + session->HandleConnectionClosing(*this); +} + std::string Battlenet::Connection::Pong::ToString() const { return "Battlenet::Connection::Pong"; diff --git a/src/server/bnetserver/Packets/ConnectionPackets.h b/src/server/bnetserver/Packets/ConnectionPackets.h index f3fa4852d07..8572cd5d854 100644 --- a/src/server/bnetserver/Packets/ConnectionPackets.h +++ b/src/server/bnetserver/Packets/ConnectionPackets.h @@ -29,8 +29,8 @@ namespace Battlenet CMSG_PING = 0x0, CMSG_ENABLE_ENCRYPTION = 0x5, CMSG_LOGOUT_REQUEST = 0x6, - CMSG_DISCONNECT_REQUEST = 0x7, // Not implemented - CMSG_CONNECTION_CLOSING = 0x9, // Not implemented + CMSG_DISCONNECT_REQUEST = 0x7, // Not handled + CMSG_CONNECTION_CLOSING = 0x9, SMSG_PONG = 0x0, SMSG_BOOM = 0x1, // Not implemented @@ -49,7 +49,7 @@ namespace Battlenet void Read() override { } std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; }; class EnableEncryption final : public ClientPacket @@ -62,7 +62,7 @@ namespace Battlenet void Read() override { } std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; }; class LogoutRequest final : public ClientPacket @@ -75,7 +75,66 @@ namespace Battlenet void Read() override { } std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; + }; + + class DisconnectRequest final : public ClientPacket + { + public: + DisconnectRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_DISCONNECT_REQUEST, CONNECTION) && "Invalid packet header for DisconnectRequest"); + } + + void Read() override; + std::string ToString() const override; + + uint16 Timeout; + uint32 Tick; + }; + + class ConnectionClosing final : public ClientPacket + { + public: + enum ClosingReason + { + PACKET_TOO_LARGE, + PACKET_CORRUPT, + PACKET_INVALID, + PACKET_INCORRECT, + HEADER_CORRUPT, + HEADER_IGNORED, + HEADER_INCORRECT, + PACKET_REJECTED, + CHANNEL_UNHANDLED, + COMMAND_UNHANDLED, + COMMAND_BAD_PERMISSIONS, + DIRECT_CALL, + TIMEOUT, + }; + + struct PacketInfo + { + uint16 LayerId; + std::string Channel; + uint32 Timestamp; + std::string CommandName; + uint16 Size; + }; + + ConnectionClosing(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_CONNECTION_CLOSING, CONNECTION) && "Invalid packet header for ConnectionClosing"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session) override; + + PacketHeader Header; + ClosingReason Reason; + std::vector Packets; + time_t Now; }; class Pong final : public ServerPacket diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index cd920e91c9c..7a4bd7dd64f 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -28,7 +28,7 @@ std::string Battlenet::Friends::SocialNetworkCheckConnected::ToString() const return "Battlenet::Friends::SocialNetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); } -void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) const +void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) { session->HandleSocialNetworkCheckConnected(*this); } @@ -47,11 +47,6 @@ std::string Battlenet::Friends::SocialNetworkConnect::ToString() const return "Battlenet::Friends::SocialNetworkConnect"; } -void Battlenet::Friends::SocialNetworkConnect::CallHandler(Session* session) const -{ - session->LogUnhandledPacket(*this); -} - std::string Battlenet::Friends::SocialNetworkConnectResult::ToString() const { return "Battlenet::Friends::SocialNetworkConnectResult"; @@ -84,11 +79,6 @@ std::string Battlenet::Friends::GetFriendsOfFriend::ToString() const return "Battlenet::Friends::GetFriendsOfFriend"; } -void Battlenet::Friends::GetFriendsOfFriend::CallHandler(Session* session) const -{ - session->LogUnhandledPacket(*this); -} - void Battlenet::Friends::RealIdFriendInvite::Read() { _stream.Read(32); @@ -139,7 +129,7 @@ std::string Battlenet::Friends::RealIdFriendInvite::ToString() const return "Battlenet::Friends::RealIdFriendInvite Mail: " + Email + " Message: " + Message; } -void Battlenet::Friends::RealIdFriendInvite::CallHandler(Session* session) const +void Battlenet::Friends::RealIdFriendInvite::CallHandler(Session* session) { FriendInviteResult* result = new FriendInviteResult(); session->AsyncWrite(result); diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h index ec20f202098..a35b02e616d 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.h +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -59,12 +59,11 @@ namespace Battlenet public: SocialNetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { - ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialnetworkConnect"); + ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialNetworkConnect"); } void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; }; class SocialNetworkConnectResult final : public ServerPacket @@ -88,7 +87,7 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; uint32 SocialNetworkId; }; @@ -117,7 +116,6 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; }; class FriendsOfFriend final : public ServerPacket @@ -141,7 +139,7 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; std::string Email; std::string Message; diff --git a/src/server/bnetserver/Packets/PacketFactory.h b/src/server/bnetserver/Packets/PacketFactory.h index 418e56abea4..9d710101332 100644 --- a/src/server/bnetserver/Packets/PacketFactory.h +++ b/src/server/bnetserver/Packets/PacketFactory.h @@ -55,6 +55,8 @@ namespace Battlenet _creators[PacketHeader(Connection::CMSG_PING, CONNECTION)] = &New; _creators[PacketHeader(Connection::CMSG_ENABLE_ENCRYPTION, CONNECTION)] = &New; _creators[PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION)] = &New; + _creators[PacketHeader(Connection::CMSG_DISCONNECT_REQUEST, CONNECTION)] = &New; + _creators[PacketHeader(Connection::CMSG_CONNECTION_CLOSING, CONNECTION)] = &New; _creators[PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM)] = &New; _creators[PacketHeader(WoWRealm::CMSG_LIST_UNSUBSCRIBE, WOWREALM)] = &New; diff --git a/src/server/bnetserver/Packets/PacketsBase.cpp b/src/server/bnetserver/Packets/PacketsBase.cpp index 6471337060c..7eee6a6a9ba 100644 --- a/src/server/bnetserver/Packets/PacketsBase.cpp +++ b/src/server/bnetserver/Packets/PacketsBase.cpp @@ -36,3 +36,9 @@ Battlenet::ServerPacket::~ServerPacket() { delete &_stream; } + +void Battlenet::ClientPacket::CallHandler(Session* session) +{ + session->LogUnhandledPacket(*this); + _handled = false; +} diff --git a/src/server/bnetserver/Packets/PacketsBase.h b/src/server/bnetserver/Packets/PacketsBase.h index 839a10548e9..a225c3ebfa1 100644 --- a/src/server/bnetserver/Packets/PacketsBase.h +++ b/src/server/bnetserver/Packets/PacketsBase.h @@ -97,10 +97,14 @@ namespace Battlenet class ClientPacket : public Packet { public: - ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } + ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream), _handled(true) { } void Write() override final { ASSERT(!"Write not implemented for this packet."); } - virtual void CallHandler(Session* session) const = 0; + virtual void CallHandler(Session* session); + bool WasHandled() const { return _handled; } + + private: + bool _handled; }; class ServerPacket : public Packet diff --git a/src/server/bnetserver/Packets/PresencePackets.cpp b/src/server/bnetserver/Packets/PresencePackets.cpp index da49f41af76..b72bf8daca8 100644 --- a/src/server/bnetserver/Packets/PresencePackets.cpp +++ b/src/server/bnetserver/Packets/PresencePackets.cpp @@ -28,11 +28,6 @@ std::string Battlenet::Presence::UpdateRequest::ToString() const return "Battlenet::Presence::UpdateRequest"; } -void Battlenet::Presence::UpdateRequest::CallHandler(Session* session) const -{ - session->LogUnhandledPacket(*this); -} - void Battlenet::Presence::StatisticSubscribe::Read() { } @@ -41,8 +36,3 @@ std::string Battlenet::Presence::StatisticSubscribe::ToString() const { return "Battlenet::Presence::StatisticSubscribe"; } - -void Battlenet::Presence::StatisticSubscribe::CallHandler(Session* session) const -{ - session->LogUnhandledPacket(*this); -} diff --git a/src/server/bnetserver/Packets/PresencePackets.h b/src/server/bnetserver/Packets/PresencePackets.h index c934228a3cb..45b8f3e0e82 100644 --- a/src/server/bnetserver/Packets/PresencePackets.h +++ b/src/server/bnetserver/Packets/PresencePackets.h @@ -44,7 +44,6 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; }; class StatisticSubscribe final : public ClientPacket @@ -57,7 +56,6 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; }; } } diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index 95176963c18..4d11dd0a11f 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -25,7 +25,7 @@ std::string Battlenet::WoWRealm::ListSubscribeRequest::ToString() const return "Battlenet::WoWRealm::ListSubscribeRequest"; } -void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session) const +void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session) { session->HandleListSubscribeRequest(*this); } @@ -35,7 +35,7 @@ std::string Battlenet::WoWRealm::ListUnsubscribe::ToString() const return "Battlenet::WoWRealm::ListUnsubscribe"; } -void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) const +void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) { session->HandleListUnsubscribe(*this); } @@ -152,7 +152,7 @@ std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const return stream.str().c_str(); } -void Battlenet::WoWRealm::JoinRequestV2::CallHandler(Session* session) const +void Battlenet::WoWRealm::JoinRequestV2::CallHandler(Session* session) { session->HandleJoinRequestV2(*this); } diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index a27601f7478..fe211d6fea4 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -50,7 +50,7 @@ namespace Battlenet void Read() override { } std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; }; class ListUnsubscribe final : public ClientPacket @@ -63,7 +63,7 @@ namespace Battlenet void Read() override { } std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; }; class JoinRequestV2 final : public ClientPacket @@ -76,7 +76,7 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) const override; + void CallHandler(Session* session) override; uint32 ClientSeed; RealmId Realm; diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 301a6b9bae1..42d5b6a5a06 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -396,6 +396,10 @@ void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /* LoginDatabase.Execute(stmt); } +void Battlenet::Session::HandleConnectionClosing(Connection::ConnectionClosing const& /*connectionClosing*/) +{ +} + void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/) { WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); @@ -497,8 +501,10 @@ void Battlenet::Session::ReadHandler() if (ClientPacket* packet = sPacketFactory.Create(header, stream)) { - TC_LOG_TRACE("server.battlenet", "Battlenet::Session::ReadDataHandler %s", packet->ToString().c_str()); packet->CallHandler(this); + if (packet->WasHandled()) + TC_LOG_TRACE("server.battlenet", "Battlenet::Session::ReadDataHandler %s", packet->ToString().c_str()); + delete packet; } else diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 7def3c70460..3f5e53389b8 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -71,6 +71,7 @@ namespace Battlenet void HandlePing(Connection::Ping const& ping); void HandleEnableEncryption(Connection::EnableEncryption const& enableEncryption); void HandleLogoutRequest(Connection::LogoutRequest const& logoutRequest); + void HandleConnectionClosing(Connection::ConnectionClosing const& connectionClosing); // WoWRealm void HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& listSubscribeRequest); -- cgit v1.2.3 From 241fdc49a7c49bdf627aeb0d14b0e6540090a81a Mon Sep 17 00:00:00 2001 From: Vincent-Michael Date: Sun, 12 Oct 2014 02:02:40 +0200 Subject: Core: Fix non pch build --- src/server/bnetserver/Packets/AuthenticationPackets.cpp | 1 + src/server/bnetserver/Packets/PacketsBase.cpp | 1 + src/server/bnetserver/Realms/RealmList.h | 1 + 3 files changed, 3 insertions(+) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/AuthenticationPackets.cpp b/src/server/bnetserver/Packets/AuthenticationPackets.cpp index c1362cd5f03..f5704f67153 100644 --- a/src/server/bnetserver/Packets/AuthenticationPackets.cpp +++ b/src/server/bnetserver/Packets/AuthenticationPackets.cpp @@ -16,6 +16,7 @@ */ #include "AuthenticationPackets.h" +#include "Session.h" #include "Util.h" void Battlenet::Authentication::LogonRequest::Read() diff --git a/src/server/bnetserver/Packets/PacketsBase.cpp b/src/server/bnetserver/Packets/PacketsBase.cpp index 7eee6a6a9ba..6845fbfb0f0 100644 --- a/src/server/bnetserver/Packets/PacketsBase.cpp +++ b/src/server/bnetserver/Packets/PacketsBase.cpp @@ -16,6 +16,7 @@ */ #include "Packets.h" +#include "Session.h" #include std::string Battlenet::PacketHeader::ToString() const diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index c7108101056..a4d3d77ff56 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "Common.h" using namespace boost::asio; -- cgit v1.2.3 From 7679ecd7b3f9cff718023bee80eb6558fdf17b6e Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 12 Oct 2014 15:34:01 +0200 Subject: Core/Battle.net: Improved logging - use separate filters instead of throwing everything to one logger --- src/server/bnetserver/Packets/FriendsPackets.cpp | 12 ++--- src/server/bnetserver/Packets/FriendsPackets.h | 1 - src/server/bnetserver/Packets/WoWRealmPackets.cpp | 14 ++++-- src/server/bnetserver/Packets/WoWRealmPackets.h | 2 +- src/server/bnetserver/Realms/RealmList.cpp | 20 +++++---- src/server/bnetserver/Server/Session.cpp | 55 ++++++++++++++--------- src/server/bnetserver/Server/Session.h | 5 ++- src/server/bnetserver/bnetserver.conf.dist | 3 ++ 8 files changed, 66 insertions(+), 46 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index 7a4bd7dd64f..ec7078f9b02 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -117,10 +117,10 @@ void Battlenet::Friends::RealIdFriendInvite::Read() } _stream.Read(1); - + if (_stream.Read(1)) Message = _stream.ReadString(9); - + _stream.Read(32); } @@ -129,12 +129,6 @@ std::string Battlenet::Friends::RealIdFriendInvite::ToString() const return "Battlenet::Friends::RealIdFriendInvite Mail: " + Email + " Message: " + Message; } -void Battlenet::Friends::RealIdFriendInvite::CallHandler(Session* session) -{ - FriendInviteResult* result = new FriendInviteResult(); - session->AsyncWrite(result); -} - std::string Battlenet::Friends::FriendInviteResult::ToString() const { return "Battlenet::Friends::RealIdFriendInviteResult"; @@ -150,7 +144,7 @@ void Battlenet::Friends::FriendInviteResult::Write() _stream.WriteString("Testing2", 8); } _stream.Write(5, 32); - + _stream.Write(0, 0xC); // Ignored _stream.Write(1, 16); diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h index a35b02e616d..692ab5a860b 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.h +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -139,7 +139,6 @@ namespace Battlenet void Read() override; std::string ToString() const override; - void CallHandler(Session* session) override; std::string Email; std::string Message; diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index 4d11dd0a11f..beeeb14895c 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -128,11 +128,17 @@ void Battlenet::WoWRealm::ListUpdate::Write() std::string Battlenet::WoWRealm::ListUpdate::ToString() const { std::ostringstream stream; - stream << "Battlenet::WoWRealm::ListUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name - << " Flags " << uint32(Flags) << " Region " << uint32(Id.Region) << " Battlegroup " << uint32(Id.Battlegroup) << " Index " << Id.Index; + stream << "Battlenet::WoWRealm::ListUpdate"; + if (UpdateState == UPDATE) + { + stream << " Timezone: " << Timezone << " Population: " << Population << " Lock: " << uint32(Lock) << " Type: " << Type << " Name: " << Name + << " Flags: " << uint32(Flags) << " Region: " << uint32(Id.Region) << " Battlegroup: " << uint32(Id.Battlegroup) << " Index: " << Id.Index; - if (!Version.empty()) - stream << " Version " << Version; + if (!Version.empty()) + stream << " Version: " << Version; + } + else + stream << " Delete realm [Region: " << uint32(Id.Region) << " Battlegroup : " << uint32(Id.Battlegroup) << " Index : " << Id.Index << "]"; return stream.str().c_str(); } diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index fe211d6fea4..403ca71279f 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -163,7 +163,7 @@ namespace Battlenet }; JoinResponseV2() : ServerPacket(PacketHeader(SMSG_JOIN_RESPONSE_V2, WOWREALM)), - ServerSeed(0), Response(SUCCESS), ResponseCode(26) + Response(SUCCESS), ResponseCode(26), ServerSeed(0) { } diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index 8d6edb12b5c..2bf93e12cb3 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -97,7 +97,6 @@ void RealmList::UpdateRealm(Battlenet::RealmId const& id, const std::string& nam Realm& realm = _realms[id]; realm.Keep = true; - realm.Updated = false; realm.Id = id; UpdateField(realm.Name, name, realm.Updated); @@ -117,7 +116,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) if (error) return; - TC_LOG_INFO("server.bnetserver", "Updating Realm List..."); + TC_LOG_DEBUG("realmlist", "Updating Realm List..."); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); PreparedQueryResult result = LoginDatabase.Query(stmt); @@ -139,7 +138,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) boost::asio::ip::tcp::resolver::iterator endPoint = _resolver->resolve(externalAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[2].GetString().c_str()); + TC_LOG_ERROR("realmlist", "Could not resolve address %s", fields[2].GetString().c_str()); continue; } @@ -149,7 +148,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) endPoint = _resolver->resolve(localAddressQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[3].GetString().c_str()); + TC_LOG_ERROR("realmlist", "Could not resolve address %s", fields[3].GetString().c_str()); continue; } @@ -159,7 +158,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) endPoint = _resolver->resolve(localSubmaskQuery, ec); if (endPoint == end || ec) { - TC_LOG_ERROR("server.bnetserver", "Could not resolve address %s", fields[4].GetString().c_str()); + TC_LOG_ERROR("realmlist", "Could not resolve address %s", fields[4].GetString().c_str()); continue; } @@ -181,11 +180,11 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); - //TC_LOG_INFO("server.bnetserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[id].ExternalAddress.to_string().c_str(), port); + TC_LOG_TRACE("realmlist", "Realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port); } catch (std::exception& ex) { - TC_LOG_ERROR("server.bnetserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); + TC_LOG_ERROR("realmlist", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what()); ASSERT(false); } } @@ -195,12 +194,15 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) std::vector updatedRealms; std::vector deletedRealms; - for (RealmMap::value_type const& pair : _realms) + for (RealmMap::value_type& pair : _realms) { if (pair.second.Updated) updatedRealms.push_back(&pair.second); - if (!pair.second.Keep) + else if (!pair.second.Keep) deletedRealms.push_back(pair.first); + + pair.second.Updated = false; + pair.second.Keep = false; } for (Battlenet::RealmId const& deleted : deletedRealms) diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 42d5b6a5a06..fa678165cf3 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -64,7 +64,6 @@ Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _ Battlenet::Session::~Session() { sSessionMgr.RemoveSession(this); - TC_LOG_TRACE("server.battlenet", "Battlenet::Session::OnClose"); } void Battlenet::Session::_SetVSFields(std::string const& pstr) @@ -91,7 +90,7 @@ void Battlenet::Session::_SetVSFields(std::string const& pstr) void Battlenet::Session::LogUnhandledPacket(ClientPacket const& packet) { - TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::LogUnhandledPacket %s", packet.ToString().c_str()); + TC_LOG_DEBUG("session.packets", "%s Received unhandled packet %s", GetClientInfo().c_str(), packet.ToString().c_str()); } void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& logonRequest) @@ -107,7 +106,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); - TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); return; } @@ -184,7 +183,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& // If the IP is 'locked', check that the player comes indeed from the correct IP address if (fields[2].GetUInt8() == 1) // if ip is locked { - TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) { @@ -196,10 +195,10 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& } else { - TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); std::string accountCountry = fields[3].GetString(); if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("server.battlenet", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.c_str()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.c_str()); else if (!accountCountry.empty()) { uint32 ip = inet_addr(ip_address.c_str()); @@ -210,7 +209,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.battlenet", "[Battlenet::AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); + TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); if (loginCountry != accountCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); @@ -237,7 +236,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } else @@ -245,7 +244,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } } @@ -494,7 +493,7 @@ void Battlenet::Session::ReadHandler() if (header.Channel != AUTHENTICATION && !_authed) { - TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::ReadDataHandler Received not allowed packet %s", header.ToString().c_str()); + TC_LOG_DEBUG("session.packets", "%s Received not allowed %s. Client has not authed yet.", GetClientInfo().c_str(), header.ToString().c_str()); CloseSocket(); return; } @@ -503,13 +502,13 @@ void Battlenet::Session::ReadHandler() { packet->CallHandler(this); if (packet->WasHandled()) - TC_LOG_TRACE("server.battlenet", "Battlenet::Session::ReadDataHandler %s", packet->ToString().c_str()); + TC_LOG_TRACE("session.packets", "%s Received %s", GetClientInfo().c_str(), packet->ToString().c_str()); delete packet; } else { - TC_LOG_DEBUG("server.battlenet", "Battlenet::Session::ReadDataHandler Unhandled opcode %s", header.ToString().c_str()); + TC_LOG_DEBUG("session.packets", "%s Received unknown %s", GetClientInfo().c_str(), header.ToString().c_str()); break; } @@ -517,7 +516,7 @@ void Battlenet::Session::ReadHandler() } catch (BitStreamPositionException const& e) { - TC_LOG_ERROR("server.battlenet", "Battlenet::Session::ReadDataHandler Exception: %s", e.what()); + TC_LOG_ERROR("session.packets", "%s Exception thrown during packet processing %s", GetClientInfo().c_str(), e.what()); CloseSocket(); return; } @@ -529,7 +528,7 @@ void Battlenet::Session::ReadHandler() void Battlenet::Session::Start() { - TC_LOG_TRACE("server.battlenet", "Battlenet::Session::Start"); + TC_LOG_TRACE("session", "Accepted connection from %s", GetRemoteIpAddress().to_string().c_str()); AsyncRead(); } @@ -541,7 +540,7 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet) return; } - TC_LOG_TRACE("server.battlenet", "Battlenet::Session::AsyncWrite %s", packet->ToString().c_str()); + TC_LOG_TRACE("session.packets", "%s Sending %s", GetClientInfo().c_str(), packet->ToString().c_str()); packet->Write(); @@ -752,12 +751,12 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke if (fields[2].GetUInt32() == fields[3].GetUInt32()) { logonResponse->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } ReplaceResponse(response, logonResponse); @@ -824,12 +823,12 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se if (fields[2].GetUInt32() == fields[3].GetUInt32()) { logonResponse->SetAuthResult(LOGIN_BANNED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); - TC_LOG_DEBUG("server.battlenet", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); + TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str()); } ReplaceResponse(response, logonResponse); @@ -935,7 +934,7 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* stmt->setString(0, _accountName); LoginDatabase.Execute(stmt); - TC_LOG_DEBUG("server.battlenet", "[Battlenet::Resume] Invalid proof!"); + TC_LOG_DEBUG("session", "[Battlenet::Resume] Invalid proof!"); Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse(); resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); ReplaceResponse(response, resumeResponse); @@ -975,6 +974,7 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket* bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket** response) { + TC_LOG_ERROR("session.packets", "Unhandled module."); Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); @@ -1026,3 +1026,18 @@ Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const listUpdate->Id = realm->Id; return listUpdate; } + +std::string Battlenet::Session::GetClientInfo() const +{ + std::ostringstream stream; + stream << '[' << GetRemoteIpAddress() << ':' << GetRemotePort(); + if (!_accountName.empty()) + stream << ", Account: " << _accountName; + + if (!_gameAccountName.empty()) + stream << ", Game account: " << _gameAccountName; + + stream << ']'; + + return stream.str(); +} diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 3f5e53389b8..764ef7e0c73 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -85,14 +85,14 @@ namespace Battlenet void UpdateRealms(std::vector& realms, std::vector& deletedRealms); - void AsyncWrite(ServerPacket* packet); - uint32 GetAccountId() const { return _accountId; } uint32 GetGameAccountId() const { return _gameAccountId; } bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; } protected: + void AsyncWrite(ServerPacket* packet); + void ReadHandler() override; private: @@ -108,6 +108,7 @@ namespace Battlenet bool UnhandledModule(BitStream* dataStream, ServerPacket** response); WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const; + std::string GetClientInfo() const; uint32 _accountId; std::string _accountName; diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index ac02a06c918..84456c117b3 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -245,6 +245,9 @@ Appender.Bnet=2,2,0,Bnet.log,w # Logger.root=3,Console Bnet +Logger.realmlist=3,Console Bnet +Logger.session=3,Console Bnet +Logger.session.packets=3,Console Bnet # ################################################################################################### -- cgit v1.2.3 From 679e663df1d595b06d568c169b1fe19234fe8ff1 Mon Sep 17 00:00:00 2001 From: Sebastian Valle Herrera Date: Sun, 12 Oct 2014 10:32:49 -0500 Subject: Bnet/Friends: Send the "proper" error message in SocialNetworkCheckConnectedResult --- src/server/bnetserver/Packets/FriendsPackets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index ec7078f9b02..42036c3d7a4 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -64,7 +64,7 @@ std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() co void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() { _stream.Write(0, 23); // Ignored - _stream.Write(0, 16); // Unknown + _stream.Write(4601, 16); // Result, 4601 = The Facebook add friend service is unavailable right now. Please try again later. _stream.Write(SocialNetworkId, 32); } -- cgit v1.2.3 From cf521de9cb4da0c3a490684875196f7187d9b4cd Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 12 Oct 2014 20:58:25 +0200 Subject: Battle.net/Packets: Added packet name mapping for logging --- src/server/bnetserver/Packets/FriendsPackets.cpp | 69 +++---- src/server/bnetserver/Packets/FriendsPackets.h | 70 +++---- src/server/bnetserver/Packets/PacketFactory.h | 86 -------- src/server/bnetserver/Packets/PacketManager.cpp | 242 +++++++++++++++++++++++ src/server/bnetserver/Packets/PacketManager.h | 105 ++++++++++ src/server/bnetserver/Packets/PacketsBase.cpp | 3 +- src/server/bnetserver/Packets/PacketsBase.h | 8 +- src/server/bnetserver/Packets/WoWRealmPackets.h | 2 +- src/server/bnetserver/Server/Session.cpp | 37 +++- src/server/bnetserver/Server/Session.h | 2 +- 10 files changed, 428 insertions(+), 196 deletions(-) delete mode 100644 src/server/bnetserver/Packets/PacketFactory.h create mode 100644 src/server/bnetserver/Packets/PacketManager.cpp create mode 100644 src/server/bnetserver/Packets/PacketManager.h (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index 42036c3d7a4..14c5fb3a665 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -18,65 +18,30 @@ #include "Session.h" #include "FriendsPackets.h" -void Battlenet::Friends::SocialNetworkCheckConnected::Read() -{ - SocialNetworkId = _stream.Read(32); -} - -std::string Battlenet::Friends::SocialNetworkCheckConnected::ToString() const -{ - return "Battlenet::Friends::SocialNetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); -} - -void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) -{ - session->HandleSocialNetworkCheckConnected(*this); -} - -void Battlenet::Friends::SocialNetworkConnect::Read() -{ - int32 unk1 = _stream.Read(32); - uint32 size1 = _stream.Read(9); - auto data1 = _stream.ReadBytes(size1); - uint32 size2 = _stream.Read(7); - auto data2 = _stream.ReadBytes(size2); -} - -std::string Battlenet::Friends::SocialNetworkConnect::ToString() const -{ - return "Battlenet::Friends::SocialNetworkConnect"; -} - -std::string Battlenet::Friends::SocialNetworkConnectResult::ToString() const -{ - return "Battlenet::Friends::SocialNetworkConnectResult"; -} - -void Battlenet::Friends::SocialNetworkConnectResult::Write() +void Battlenet::Friends::GetFriendsOfFriend::Read() { + uint8 unk = _stream.Read(2); + uint32 unk1 = _stream.Read(32); } -std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() const +std::string Battlenet::Friends::GetFriendsOfFriend::ToString() const { - return "Battlenet::Friends::SocialNetworkCheckConnectedResult"; + return "Battlenet::Friends::GetFriendsOfFriend"; } -void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() +void Battlenet::Friends::SocialNetworkCheckConnected::Read() { - _stream.Write(0, 23); // Ignored - _stream.Write(4601, 16); // Result, 4601 = The Facebook add friend service is unavailable right now. Please try again later. - _stream.Write(SocialNetworkId, 32); + SocialNetworkId = _stream.Read(32); } -void Battlenet::Friends::GetFriendsOfFriend::Read() +std::string Battlenet::Friends::SocialNetworkCheckConnected::ToString() const { - uint8 unk = _stream.Read(2); - uint32 unk1 = _stream.Read(32); + return "Battlenet::Friends::SocialNetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); } -std::string Battlenet::Friends::GetFriendsOfFriend::ToString() const +void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) { - return "Battlenet::Friends::GetFriendsOfFriend"; + session->HandleSocialNetworkCheckConnected(*this); } void Battlenet::Friends::RealIdFriendInvite::Read() @@ -159,3 +124,15 @@ void Battlenet::Friends::FriendInviteResult::Write() _stream.WriteString("Testing3", 7, 2); } } + +std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() const +{ + return "Battlenet::Friends::SocialNetworkCheckConnectedResult"; +} + +void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() +{ + _stream.Write(0, 23); // Ignored + _stream.Write(Result, 16); + _stream.Write(SocialNetworkId, 32); +} diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h index 692ab5a860b..ea4d6d2ea92 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.h +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -34,9 +34,9 @@ namespace Battlenet CMSG_BLOCK_ADD = 0x08, // Not implemented CMSG_BLOCK_REMOVE = 0x0A, // Not implemented CMSG_GET_FRIENDS_OF_FRIEND = 0x0B, // Not implemented - CMSG_GET_SOCIAL_NETWORK_FRIENDS = 0x0D, // Not implemented - CMSG_SOCIAL_NETWORK_CONNECT = 0x0F, // Not implemented - CMSG_SOCIAL_NETWORK_DISCONNECT = 0x11, // Not implemented + CMSG_GET_SOCIAL_NETWORK_FRIENDS = 0x0D, // Won't support + CMSG_SOCIAL_NETWORK_CONNECT = 0x0F, // Won't support + CMSG_SOCIAL_NETWORK_DISCONNECT = 0x11, // Won't support CMSG_SOCIAL_NETWORK_CHECK_CONNECTED = 0x13, CMSG_REALID_FRIEND_INVITE = 0x16, // Not implemented @@ -46,37 +46,26 @@ namespace Battlenet SMSG_BLOCK_INVITE_NOTIFY = 0x07, // Not implemented SMSG_BLOCK_ADD_FAILURE = 0x09, // Not implemented SMSG_FRIENDS_OF_FRIEND = 0x0C, // Not implemented - SMSG_SOCIAL_NETWORK_FRIENDS = 0x0E, // Not implemented - SMSG_SOCIAL_NETWORK_CONNECT_RESULT = 0x10, // Not implemented - SMSG_SOCIAL_NETWORK_DISCONNECT_RESULT = 0x12, // Not implemented + SMSG_SOCIAL_NETWORK_FRIENDS = 0x0E, // Won't support + SMSG_SOCIAL_NETWORK_CONNECT_RESULT = 0x10, // Won't support + SMSG_SOCIAL_NETWORK_DISCONNECT_RESULT = 0x12, // Won't support SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT = 0x14, SMSG_MAX_FRIENDS_NOTIFY = 0x15, // Not implemented SMSG_FRIENDS_LIST_NOTIFY_3 = 0x18 // Not implemented }; - class SocialNetworkConnect final : public ClientPacket + class GetFriendsOfFriend final : public ClientPacket { public: - SocialNetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + GetFriendsOfFriend(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { - ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialNetworkConnect"); + ASSERT(header == PacketHeader(CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS) && "Invalid packet header for GetFriendsOfFriend"); } void Read() override; std::string ToString() const override; }; - class SocialNetworkConnectResult final : public ServerPacket - { - public: - SocialNetworkConnectResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CONNECT_RESULT, FRIENDS)) - { - } - - void Write() override; - std::string ToString() const override; - }; - class SocialNetworkCheckConnected final : public ClientPacket { public: @@ -92,29 +81,29 @@ namespace Battlenet uint32 SocialNetworkId; }; - class SocialNetworkCheckConnectedResult final : public ServerPacket + class RealIdFriendInvite final : public ClientPacket { public: - SocialNetworkCheckConnectedResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), - SocialNetworkId(0) + RealIdFriendInvite(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { + ASSERT(header == PacketHeader(CMSG_REALID_FRIEND_INVITE, FRIENDS) && "Invalid packet header for RealIdFriendInvite"); } - void Write() override; + void Read() override; std::string ToString() const override; - uint32 SocialNetworkId; + std::string Email; + std::string Message; }; - class GetFriendsOfFriend final : public ClientPacket + class FriendInviteResult final : public ServerPacket { public: - GetFriendsOfFriend(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + FriendInviteResult() : ServerPacket(PacketHeader(SMSG_FRIEND_INVITE_RESULT, FRIENDS)) { - ASSERT(header == PacketHeader(CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS) && "Invalid packet header for GetFriendsOfFriend"); } - void Read() override; + void Write() override; std::string ToString() const override; }; @@ -129,30 +118,19 @@ namespace Battlenet std::string ToString() const override; }; - class RealIdFriendInvite final : public ClientPacket - { - public: - RealIdFriendInvite(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) - { - ASSERT(header == PacketHeader(CMSG_REALID_FRIEND_INVITE, FRIENDS) && "Invalid packet header for RealIdFriendInvite"); - } - - void Read() override; - std::string ToString() const override; - - std::string Email; - std::string Message; - }; - - class FriendInviteResult final : public ServerPacket + class SocialNetworkCheckConnectedResult final : public ServerPacket { public: - FriendInviteResult() : ServerPacket(PacketHeader(SMSG_FRIEND_INVITE_RESULT, FRIENDS)) + SocialNetworkCheckConnectedResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), + Result(4601), SocialNetworkId(0) // 4601 = The Facebook add friend service is unavailable right now. Please try again later. { } void Write() override; std::string ToString() const override; + + uint16 Result; + uint32 SocialNetworkId; }; } } diff --git a/src/server/bnetserver/Packets/PacketFactory.h b/src/server/bnetserver/Packets/PacketFactory.h deleted file mode 100644 index 9d710101332..00000000000 --- a/src/server/bnetserver/Packets/PacketFactory.h +++ /dev/null @@ -1,86 +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 PacketFactory_h__ -#define PacketFactory_h__ - -#include "Packets.h" -#include - -namespace Battlenet -{ - class PacketFactory - { - typedef ClientPacket*(*PacketCreateFn)(PacketHeader const& header, BitStream& stream); - - public: - ClientPacket* Create(PacketHeader const& header, BitStream& stream) - { - auto creator = _creators.find(header); - if (creator == _creators.end()) - return nullptr; - - ClientPacket* packet = creator->second(header, stream); - packet->Read(); - return packet; - } - - static PacketFactory& Instance() - { - static PacketFactory instance; - return instance; - } - - private: - PacketFactory() - { - _creators[PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION)] = &New; - _creators[PacketHeader(Authentication::CMSG_RESUME_REQUEST, AUTHENTICATION)] = &New; - _creators[PacketHeader(Authentication::CMSG_PROOF_RESPONSE, AUTHENTICATION)] = &New; - - _creators[PacketHeader(Connection::CMSG_PING, CONNECTION)] = &New; - _creators[PacketHeader(Connection::CMSG_ENABLE_ENCRYPTION, CONNECTION)] = &New; - _creators[PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION)] = &New; - _creators[PacketHeader(Connection::CMSG_DISCONNECT_REQUEST, CONNECTION)] = &New; - _creators[PacketHeader(Connection::CMSG_CONNECTION_CLOSING, CONNECTION)] = &New; - - _creators[PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM)] = &New; - _creators[PacketHeader(WoWRealm::CMSG_LIST_UNSUBSCRIBE, WOWREALM)] = &New; - _creators[PacketHeader(WoWRealm::CMSG_JOIN_REQUEST_V2, WOWREALM)] = &New; - - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New; - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New; - _creators[PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS)] = &New; - _creators[PacketHeader(Friends::CMSG_REALID_FRIEND_INVITE, FRIENDS)] = &New; - - _creators[PacketHeader(Presence::CMSG_UPDATE_REQUEST, PRESENCE)] = &New; - _creators[PacketHeader(Presence::CMSG_STATISTIC_SUBSCRIBE, PRESENCE)] = &New; - } - - template - static ClientPacket* New(PacketHeader const& header, BitStream& stream) - { - return new PacketType(header, stream); - } - - std::map _creators; - }; -} - -#define sPacketFactory Battlenet::PacketFactory::Instance() - -#endif // PacketFactory_h__ diff --git a/src/server/bnetserver/Packets/PacketManager.cpp b/src/server/bnetserver/Packets/PacketManager.cpp new file mode 100644 index 00000000000..af31b596192 --- /dev/null +++ b/src/server/bnetserver/Packets/PacketManager.cpp @@ -0,0 +1,242 @@ +/* + * 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 "PacketManager.h" + +Battlenet::ClientPacket* Battlenet::PacketManager::CreateClientPacket(PacketHeader const& header, BitStream& stream) +{ + auto packetInfo = _clientPacketTable.find(header); + if (packetInfo == _clientPacketTable.end()) + return nullptr; + + if (!packetInfo->second.Constructor) + return nullptr; + + ClientPacket* packet = packetInfo->second.Constructor(header, stream); + packet->Read(); + return packet; +} + +char const* Battlenet::PacketManager::GetClientPacketName(PacketHeader const& header) +{ + auto packetInfo = _clientPacketTable.find(header); + if (packetInfo == _clientPacketTable.end()) + return nullptr; + + return packetInfo->second.Name; +} + +char const* Battlenet::PacketManager::GetServerPacketName(PacketHeader const& header) +{ + auto packetInfo = _serverPacketTable.find(header); + if (packetInfo == _serverPacketTable.end()) + return nullptr; + + return packetInfo->second.Name; +} + +bool Battlenet::PacketManager::IsHandled(PacketHeader const& header) +{ + auto packetInfo = _clientPacketTable.find(header); + if (packetInfo == _clientPacketTable.end()) + return false; + + return packetInfo->second.HasHandler; +} + +Battlenet::PacketManager::PacketManager() +{ + RegisterAuthenticationPackets(); + RegisterConnectionPackets(); + RegisterWoWRealmPackets(); + RegisterFriendsPackets(); + RegisterPresencePackets(); + RegisterChatPackets(); + RegisterSupportPackets(); + RegisterCachePackets(); + RegisterAchievementPackets(); + RegisterProfilePackets(); +} + +#define REGISTER_CLIENT_PACKET(header, packetClass) RegisterClientPacket(header, #packetClass) +#define REGISTER_SERVER_PACKET(header, packetClass) RegisterPacketName(_serverPacketTable, header, #packetClass) +#define REGISTER_CLIENT_PACKET_NAME(header, name) RegisterPacketName(_clientPacketTable, header, name) +#define REGISTER_SERVER_PACKET_NAME(header, name) RegisterPacketName(_serverPacketTable, header, name) + +void Battlenet::PacketManager::RegisterAuthenticationPackets() +{ + REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION), Authentication::LogonRequest); + REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_RESUME_REQUEST, AUTHENTICATION), Authentication::ResumeRequest); + REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_PROOF_RESPONSE, AUTHENTICATION), Authentication::ProofResponse); + + REGISTER_SERVER_PACKET(PacketHeader(Authentication::SMSG_LOGON_RESPONSE, AUTHENTICATION), Authentication::LogonResponse); + REGISTER_SERVER_PACKET(PacketHeader(Authentication::SMSG_RESUME_RESPONSE, AUTHENTICATION), Authentication::ResumeResponse); + REGISTER_SERVER_PACKET(PacketHeader(Authentication::SMSG_PROOF_REQUEST, AUTHENTICATION), Authentication::ProofRequest); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Authentication::SMSG_PATCH, AUTHENTICATION), "Authentication::Patch"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Authentication::SMSG_AUTHORIZED_LICENSES, AUTHENTICATION), "Authentication::AuthorizedLicenses"); +} + +void Battlenet::PacketManager::RegisterConnectionPackets() +{ + REGISTER_CLIENT_PACKET(PacketHeader(Connection::CMSG_PING, CONNECTION), Connection::Ping); + REGISTER_CLIENT_PACKET(PacketHeader(Connection::CMSG_ENABLE_ENCRYPTION, CONNECTION), Connection::EnableEncryption); + REGISTER_CLIENT_PACKET(PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION), Connection::LogoutRequest); + REGISTER_CLIENT_PACKET(PacketHeader(Connection::CMSG_DISCONNECT_REQUEST, CONNECTION), Connection::DisconnectRequest); + REGISTER_CLIENT_PACKET(PacketHeader(Connection::CMSG_CONNECTION_CLOSING, CONNECTION), Connection::ConnectionClosing); + + REGISTER_SERVER_PACKET(PacketHeader(Connection::SMSG_PONG, CONNECTION), Connection::Pong); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Connection::SMSG_BOOM, CONNECTION), "Connection::Boom"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Connection::SMSG_REGULATOR_UPDATE, CONNECTION), "Connection::RegulatorUpdate"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Connection::SMSG_SERVER_VERSION, CONNECTION), "Connection::ServerVersion"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Connection::SMSG_STUN_SERVERS, CONNECTION), "Connection::STUNServers"); +} + +void Battlenet::PacketManager::RegisterWoWRealmPackets() +{ + REGISTER_CLIENT_PACKET(PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM), WoWRealm::ListSubscribeRequest); + REGISTER_CLIENT_PACKET(PacketHeader(WoWRealm::CMSG_LIST_UNSUBSCRIBE, WOWREALM), WoWRealm::ListUnsubscribe); + REGISTER_CLIENT_PACKET(PacketHeader(WoWRealm::CMSG_JOIN_REQUEST_V2, WOWREALM), WoWRealm::JoinRequestV2); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(WoWRealm::CMSG_MULTI_LOGON_REQUEST_V2, WOWREALM), "WoWRealm::MultiLogonRequestV2"); + + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_SUBSCRIBE_RESPONSE, WOWREALM), WoWRealm::ListSubscribeResponse); + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_UPDATE, WOWREALM), WoWRealm::ListUpdate); + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_COMPLETE, WOWREALM), WoWRealm::ListComplete); + REGISTER_SERVER_PACKET_NAME(PacketHeader(WoWRealm::SMSG_TOON_READY, WOWREALM), "WoWRealm::ToonReady"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(WoWRealm::SMSG_TOON_LOGGED_OUT, WOWREALM), "WoWRealm::ToonLoggedOut"); + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_JOIN_RESPONSE_V2, WOWREALM), WoWRealm::JoinResponseV2); +} + +void Battlenet::PacketManager::RegisterFriendsPackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_FRIEND_INVITE, FRIENDS), "Friends::FriendInvite"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_FRIEND_INVITE_RESPONSE, FRIENDS), "Friends::FriendInviteResponse"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_FRIEND_REMOVE, FRIENDS), "Friends::FriendRemove"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_FRIEND_NOTE, FRIENDS), "Friends::FriendNote"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_TOONS_OF_FRIEND_REQUEST, FRIENDS), "Friends::ToonsOfFriendRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_BLOCK_ADD, FRIENDS), "Friends::BlockAdd"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_BLOCK_REMOVE, FRIENDS), "Friends::BlockRemove"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS), "Friends::GetFriendsOfFriend"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_GET_SOCIAL_NETWORK_FRIENDS, FRIENDS), "Friends::GetSocialNetworkFriends"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS), "Friends::SocialNetworkConnect"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Friends::CMSG_SOCIAL_NETWORK_DISCONNECT, FRIENDS), "Friends::SocialNetworkDisconnect"); + REGISTER_CLIENT_PACKET(PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS), Friends::SocialNetworkCheckConnected); + REGISTER_CLIENT_PACKET(PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS), Friends::GetFriendsOfFriend); + REGISTER_CLIENT_PACKET(PacketHeader(Friends::CMSG_REALID_FRIEND_INVITE, FRIENDS), Friends::RealIdFriendInvite); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_FRIEND_INVITE_NOTIFY, FRIENDS), "Friends::FriendInviteNotify"); + REGISTER_SERVER_PACKET(PacketHeader(Friends::SMSG_FRIEND_INVITE_RESULT, FRIENDS), Friends::FriendInviteResult); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_TOONS_OF_FRIEND_NOTIFY, FRIENDS), "Friends::ToonsOfFriendNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_BLOCK_INVITE_NOTIFY, FRIENDS), "Friends::BlockInviteNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_BLOCK_ADD_FAILURE, FRIENDS), "Friends::BlockAddFailure"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_FRIENDS_OF_FRIEND, FRIENDS), "Friends::FriendsOfFriend"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_SOCIAL_NETWORK_FRIENDS, FRIENDS), "Friends::SocialNetworkFriends"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_SOCIAL_NETWORK_CONNECT_RESULT, FRIENDS), "Friends::SocialNetworkConnectResult"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_SOCIAL_NETWORK_DISCONNECT_RESULT, FRIENDS), "Friends::SocialNetworkDisconnectResult"); + REGISTER_SERVER_PACKET(PacketHeader(Friends::SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS), Friends::SocialNetworkCheckConnectedResult); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_MAX_FRIENDS_NOTIFY, FRIENDS), "Friends::MaxFriendsNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Friends::SMSG_FRIENDS_LIST_NOTIFY_3, FRIENDS), "Friends::FriendsListNotify3"); +} + +void Battlenet::PacketManager::RegisterPresencePackets() +{ + REGISTER_CLIENT_PACKET(PacketHeader(Presence::CMSG_UPDATE_REQUEST, PRESENCE), Presence::UpdateRequest); + REGISTER_CLIENT_PACKET(PacketHeader(Presence::CMSG_STATISTIC_SUBSCRIBE, PRESENCE), Presence::StatisticSubscribe); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Presence::SMSG_UPDATE_NOTIFY, PRESENCE), "Presence::UpdateNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Presence::SMSG_FIELD_SPEC_ANNOUNCE, PRESENCE), "Presence::FieldSpecAnnounce"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Presence::SMSG_STATISTICS_UPDATE, PRESENCE), "Presence::StatisticsUpdate"); +} + +void Battlenet::PacketManager::RegisterChatPackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_JOIN_REQUEST_2, CHAT), "Chat::JoinRequest2"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_LEAVE_REQUEST, CHAT), "Chat::LeaveRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_INVITE_REQUEST, CHAT), "Chat::InviteRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_CREATE_AND_INVITE_REQUEST, CHAT), "Chat::CreateAndInviteRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_MESSAGE_SEND, CHAT), "Chat::MessageSend"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_DATAGRAM_CONNECTION_UPDATE, CHAT), "Chat::DatagramConnectionUpdate"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_REPORT_SPAM_REQUEST, CHAT), "Chat::ReportSpamRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_WHISPER_SEND, CHAT), "Chat::WhisperSend"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_ENUM_CATEGORY_DESCRIPTIONS, CHAT), "Chat::EnumCategoryDescriptions"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_ENUM_CONFERENCE_DESCRIPTIONS, CHAT), "Chat::EnumConferenceDescriptions"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_ENUM_CONFERENCE_MEMBER_COUNTS, CHAT), "Chat::EnumConferenceMemberCounts"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Chat::CMSG_MODIFY_CHANNEL_LIST_REQUEST, CHAT), "Chat::ModifyChannelListRequest"); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_MEMBERSHIP_CHANGE_NOTIFY, CHAT), "Chat::MembershipChangeNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_INVITE_NOTIFY, CHAT), "Chat::InviteNotify"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_INVITE_CANCELED, CHAT), "Chat::InviteCanceled"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_MESSAGE_RECV, CHAT), "Chat::MessageRecv"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_MESSAGE_UNDELIVERABLE, CHAT), "Chat::MessageUndeliverable"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_DATAGRAM_CONNECTION_UPDATE, CHAT), "Chat::DatagramConnectionUpdate"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_INVITE_FAILURE, CHAT), "Chat::InviteFailed"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_SYSTEM_MESSAGE, CHAT), "Chat::SystemMessage"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_MESSAGE_BLOCKED, CHAT), "Chat::MessageBlocked"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_WHISPER_RECV, CHAT), "Chat::WhisperRecv"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_WHISPER_UNDELIVERABLE, CHAT), "Chat::WhisperUndeliverable"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_CATEGORY_DESCRIPTIONS, CHAT), "Chat::CategoryDescriptions"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_CONFERENCE_DESCRIPTIONS, CHAT), "Chat::ConferenceDescriptions"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_CONFERENCE_MEMBER_COUNTS, CHAT), "Chat::ConferenceMemberCounts"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_JOIN_NOTIFY_2, CHAT), "Chat::JoinNotify2"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_MODIFY_CHANNEL_LIST_RESPONSE, CHAT), "Chat::ModifyChannelListResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Chat::SMSG_CONFIG_CHANGED, CHAT), "Chat::ConfigChanged"); +} + +void Battlenet::PacketManager::RegisterSupportPackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Support::CMSG_COMPLAINT_REQUEST, SUPPORT), "Support::ComplaintRequest"); +} + +void Battlenet::PacketManager::RegisterAchievementPackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Achievement::CMSG_LISTEN_REQUEST, ACHIEVEMENT), "Achievement::ListenRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Achievement::CMSG_CRITERIA_FLUSH_REQUEST, ACHIEVEMENT), "Achievement::CriteriaFlushRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Achievement::CMSG_CHANGE_TROPHY_CASE_REQUEST, ACHIEVEMENT), "Achievement::ChangeTrophyCaseRequest"); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Achievement::SMSG_DATA, ACHIEVEMENT), "Achievement::Data"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Achievement::SMSG_CRITERIA_FLUSH_RESPONSE, ACHIEVEMENT), "Achievement::CriteriaFlushResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Achievement::SMSG_ACHIEVEMENT_HANDLE_UPDATE, ACHIEVEMENT), "Achievement::AchievementHandleUpdate"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Achievement::SMSG_CHANGE_TROPHY_CASE_RESULT, ACHIEVEMENT), "Achievement::ChangeTrophyCaseResult"); +} + +void Battlenet::PacketManager::RegisterCachePackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_GATEWAY_LOOKUP_REQUEST, CACHE), "Cache::GatewayLookupRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_CONNECT_REQUEST, CACHE), "Cache::ConnectRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_DATA_CHUNK, CACHE), "Cache::DataChunk"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::SMSG_GET_STREAM_ITEMS_REQUEST, CACHE), "Cache::GetStreamItemsRequest"); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_GATEWAY_LOOKUP_RESPONSE, CACHE), "Cache::GatewayLookupResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_CONNECT_RESPONSE, CACHE), "Cache::ConnectResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_PUBLISH_LIST_RESPONSE, CACHE), "Cache::PublishListResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_RESULT, CACHE), "Cache::Result"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_GET_STREAM_ITEMS_RESPONSE, CACHE), "Cache::GetStreamItemsResponse"); +} + +void Battlenet::PacketManager::RegisterProfilePackets() +{ + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Profile::CMSG_READ_REQUEST, PROFILE), "Profile::ReadRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Profile::CMSG_ADDRESS_QUERY_REQUEST, PROFILE), "Profile::AddressQueryRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Profile::CMSG_RESOLVE_TOON_HANDLE_TO_NAME_REQUEST, PROFILE), "Profile::ResolveHandleToToonNameRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Profile::CMSG_RESOLVE_TOON_NAME_TO_HANDLE_REQUEST, PROFILE), "Profile::ResolveToonNameToHandleRequest"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Profile::CMSG_CHANGE_SETTINGS, PROFILE), "Profile::ChangeSettings"); + + REGISTER_SERVER_PACKET_NAME(PacketHeader(Profile::SMSG_READ_RESPONSE, PROFILE), "Profile::ReadResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Profile::SMSG_ADDRESS_QUERY_RESPONSE, PROFILE), "Profile::AddressQueryResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Profile::SMSG_RESOLVE_TOON_HANDLE_TO_NAME_RESPONSE, PROFILE), "Profile::ResolveHandleToToonNameResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Profile::SMSG_RESOLVE_TOON_NAME_TO_HANDLE_RESPONSE, PROFILE), "Profile::ResolveToonNameToHandleResponse"); + REGISTER_SERVER_PACKET_NAME(PacketHeader(Profile::SMSG_SETTINGS_AVAILABLE, PROFILE), "Profile::SettingsAvailable"); +} diff --git a/src/server/bnetserver/Packets/PacketManager.h b/src/server/bnetserver/Packets/PacketManager.h new file mode 100644 index 00000000000..1e64e6a502c --- /dev/null +++ b/src/server/bnetserver/Packets/PacketManager.h @@ -0,0 +1,105 @@ +/* + * 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 PacketManager_h__ +#define PacketManager_h__ + +#include "Packets.h" +#include +#include + +template +struct has_call_handler +{ + template struct test_has_call_handler { }; + template static char Test(test_has_call_handler*); + template static int Test(...); + static const bool value = sizeof(Test(nullptr)) == sizeof(char); +}; + +namespace Battlenet +{ + class PacketManager + { + typedef ClientPacket*(*PacketCreateFn)(PacketHeader const& header, BitStream& stream); + + struct PacketInfo + { + PacketCreateFn Constructor; + char const* Name; + bool HasHandler; + }; + + PacketManager(); + + void RegisterAuthenticationPackets(); + void RegisterConnectionPackets(); + void RegisterWoWRealmPackets(); + void RegisterFriendsPackets(); + void RegisterPresencePackets(); + void RegisterChatPackets(); + void RegisterSupportPackets(); + void RegisterAchievementPackets(); + void RegisterCachePackets(); + void RegisterProfilePackets(); + + template + static ClientPacket* New(PacketHeader const& header, BitStream& stream) + { + return new PacketType(header, stream); + } + + void RegisterPacketName(std::map& packetTable, PacketHeader const& header, char const* name) + { + PacketInfo& info = packetTable[header]; + info.Constructor = nullptr; + info.Name = name; + info.HasHandler = false; + } + + template + void RegisterClientPacket(PacketHeader const& header, char const* name) + { + PacketInfo& info = _clientPacketTable[header]; + info.Constructor = &New; + info.Name = name; + info.HasHandler = has_call_handler::value; + } + + public: + ClientPacket* CreateClientPacket(PacketHeader const& header, BitStream& stream); + + char const* GetClientPacketName(PacketHeader const& header); + char const* GetServerPacketName(PacketHeader const& header); + + bool IsHandled(PacketHeader const& header); + + static PacketManager& Instance() + { + static PacketManager instance; + return instance; + } + + private: + std::map _clientPacketTable; + std::map _serverPacketTable; + }; +} + +#define sPacketManager Battlenet::PacketManager::Instance() + +#endif // PacketManager_h__ diff --git a/src/server/bnetserver/Packets/PacketsBase.cpp b/src/server/bnetserver/Packets/PacketsBase.cpp index 6845fbfb0f0..fd3bebcf471 100644 --- a/src/server/bnetserver/Packets/PacketsBase.cpp +++ b/src/server/bnetserver/Packets/PacketsBase.cpp @@ -40,6 +40,5 @@ Battlenet::ServerPacket::~ServerPacket() void Battlenet::ClientPacket::CallHandler(Session* session) { - session->LogUnhandledPacket(*this); - _handled = false; + session->LogUnhandledPacket(GetHeader()); } diff --git a/src/server/bnetserver/Packets/PacketsBase.h b/src/server/bnetserver/Packets/PacketsBase.h index a225c3ebfa1..0f86621d6a6 100644 --- a/src/server/bnetserver/Packets/PacketsBase.h +++ b/src/server/bnetserver/Packets/PacketsBase.h @@ -97,14 +97,10 @@ namespace Battlenet class ClientPacket : public Packet { public: - ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream), _handled(true) { } + ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { } - void Write() override final { ASSERT(!"Write not implemented for this packet."); } + void Write() override final { ASSERT(!"Write not implemented for client packets."); } virtual void CallHandler(Session* session); - bool WasHandled() const { return _handled; } - - private: - bool _handled; }; class ServerPacket : public Packet diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index 403ca71279f..2b1390a9067 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -28,7 +28,7 @@ namespace Battlenet enum Opcode { CMSG_LIST_SUBSCRIBE_REQUEST = 0x0, - CMSG_LIST_UNSUBSCRIBE = 0x1, // Not implemented + CMSG_LIST_UNSUBSCRIBE = 0x1, CMSG_JOIN_REQUEST_V2 = 0x8, CMSG_MULTI_LOGON_REQUEST_V2 = 0x9, // Not implemented diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index fa678165cf3..7090c1f0ca7 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -17,7 +17,7 @@ #include "AuthCodes.h" #include "BitStream.h" -#include "PacketFactory.h" +#include "PacketManager.h" #include "SessionManager.h" #include "Database/DatabaseEnv.h" #include "HmacHash.h" @@ -88,9 +88,9 @@ void Battlenet::Session::_SetVSFields(std::string const& pstr) LoginDatabase.Execute(stmt); } -void Battlenet::Session::LogUnhandledPacket(ClientPacket const& packet) +void Battlenet::Session::LogUnhandledPacket(PacketHeader const& header) { - TC_LOG_DEBUG("session.packets", "%s Received unhandled packet %s", GetClientInfo().c_str(), packet.ToString().c_str()); + TC_LOG_DEBUG("session.packets", "%s Received unhandled packet %s", GetClientInfo().c_str(), sPacketManager.GetClientPacketName(header)); } void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const& logonRequest) @@ -477,6 +477,22 @@ void Battlenet::Session::HandleSocialNetworkCheckConnected(Friends::SocialNetwor AsyncWrite(socialNetworkCheckConnectedResult); } +inline std::string PacketToStringHelper(Battlenet::ClientPacket const* packet) +{ + if (sLog->ShouldLog("session.packets", LOG_LEVEL_TRACE)) + return packet->ToString(); + + return sPacketManager.GetClientPacketName(packet->GetHeader()); +} + +inline std::string PacketToStringHelper(Battlenet::ServerPacket const* packet) +{ + if (sLog->ShouldLog("session.packets", LOG_LEVEL_TRACE)) + return packet->ToString(); + + return sPacketManager.GetServerPacketName(packet->GetHeader()); +} + void Battlenet::Session::ReadHandler() { BitStream stream(std::move(GetReadBuffer())); @@ -498,14 +514,19 @@ void Battlenet::Session::ReadHandler() return; } - if (ClientPacket* packet = sPacketFactory.Create(header, stream)) + if (ClientPacket* packet = sPacketManager.CreateClientPacket(header, stream)) { - packet->CallHandler(this); - if (packet->WasHandled()) - TC_LOG_TRACE("session.packets", "%s Received %s", GetClientInfo().c_str(), packet->ToString().c_str()); + if (sPacketManager.IsHandled(header)) + TC_LOG_DEBUG("session.packets", "%s Received %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str()); + packet->CallHandler(this); delete packet; } + else if (sPacketManager.GetClientPacketName(header)) + { + LogUnhandledPacket(header); + break; + } else { TC_LOG_DEBUG("session.packets", "%s Received unknown %s", GetClientInfo().c_str(), header.ToString().c_str()); @@ -540,7 +561,7 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet) return; } - TC_LOG_TRACE("session.packets", "%s Sending %s", GetClientInfo().c_str(), packet->ToString().c_str()); + TC_LOG_DEBUG("session.packets", "%s Sending %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str()); packet->Write(); diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 764ef7e0c73..b2546c70cc6 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -60,7 +60,7 @@ namespace Battlenet explicit Session(tcp::socket&& socket); ~Session(); - void LogUnhandledPacket(ClientPacket const& packet); + void LogUnhandledPacket(PacketHeader const& header); // Authentication void HandleLogonRequest(Authentication::LogonRequest const& logonRequest); -- cgit v1.2.3 From 1ef31ba752ed2ab7bcc30c11265d217b383dec4b Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 13 Oct 2014 17:22:24 +0200 Subject: Battle.net: Implemented cache stream items --- sql/base/auth_database.sql | 23 ++++++- sql/updates/auth/2014_10_13_00_auth_434.sql | 24 +++++++ src/server/bnetserver/Packets/CachePackets.cpp | 83 +++++++++++++++++++++++++ src/server/bnetserver/Packets/CachePackets.h | 37 ++++++++++- src/server/bnetserver/Packets/PacketManager.cpp | 4 +- src/server/bnetserver/Server/ModuleManager.cpp | 3 +- src/server/bnetserver/Server/Session.cpp | 11 ++++ src/server/bnetserver/Server/Session.h | 3 + src/server/bnetserver/Server/SessionManager.cpp | 2 + src/server/bnetserver/Server/SessionManager.h | 2 + 10 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 sql/updates/auth/2014_10_13_00_auth_434.sql create mode 100644 src/server/bnetserver/Packets/CachePackets.cpp (limited to 'src/server/bnetserver') diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index e5f45f9ff5c..5513c23bb95 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -241,7 +241,7 @@ CREATE TABLE `battlenet_modules` ( `Type` varchar(8) NOT NULL, `System` varchar(8) NOT NULL, `Data` text, - PRIMARY KEY (`Hash`), + PRIMARY KEY (`Name`,`System`), UNIQUE KEY `uk_name_type_system` (`Name`,`Type`,`System`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; @@ -276,7 +276,26 @@ INSERT INTO `battlenet_modules` VALUES ('bfe4ceb47700aa872e815e007e27df955d4cd4bc1fe731039ee6498ce209f368','Resume','auth','Win',NULL), ('00ffd88a437afbb88d7d4b74be2e3b43601605ee229151aa9f4bebb29ef66280','Resume','auth','Mac',NULL), ('898166926805f897804bdbbf40662c9d768590a51a0b26c40dbcdf332ba11974','Resume','auth','Wn64',NULL), -('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL); +('304627d437c38500c0b5ca0c6220eeade91390e52a2b005ff3f7754afa1f93cd','Resume','auth','Mc64',NULL), +('cc654428261322763f4cada5b7f4b3b67660e85639bea916986b3f366fe8adc2','ERRS','xml','enGB','AA6C50D3'), +('2753d31092f1978bdd78ebd4fae2d189364ad7108ceb22fbf1413be1f43bef04','PFTY','pfty','zhCN','DF6C50D3'), +('5813f318f7e40a07a7cdfeeec9827942e6fdc5ccee0d4171148443e429ad0ead','PFTY','pfty','ruRU','DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03','PFTY','pfty','enSG','DF6C50D3'), +('870f53d10b4e1b09d6b622cd5671ba4ff1ad69512dfa2c676072c52e45c7f0f9','PFTY','pfty','esES','DF6C50D3'), +('305bbdab1953e65974a249e276867e13ad2c3cabca3668983cb5ed406251bb7b','PFTY','pfty','frFR','DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03','PFTY','pfty','enGB','DF6C50D3'), +('a2ec4b41148214037a2e89a2e557af716d085241b81f5244494bdc77a891ca38','PFTY','pfty','csCZ','DF6C50D3'), +('a8c77051991b1a6c5dfe412e9f46d8f584349996fbde37c4f2a527c192163502','PFTY','pfty','plPL','DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03','PFTY','pfty','enUS','DF6C50D3'), +('7466b2db3f03768aa2527535d4b3c6c9ef9e8fb07c6db88b1019f3d25a2942e8','PFTY','pfty','koKR','DF6C50D3'), +('a2ec4b41148214037a2e89a2e557af716d085241b81f5244494bdc77a891ca38','PFTY','pfty','jaJP','DF6C50D3'), +('3e381d4f83201f4e3c482eb74da12e5ff9dd924da2413d8fb33f5eea9a02c2c2','PFTY','pfty','zhTW','DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03','PFTY','pfty','enTH','DF6C50D3'), +('b72e65b6b34d8f859e79b5f28952e26553a796d5e1d75c2b5930bc0daeaa728c','PFTY','pfty','itIT','DF6C50D3'), +('e8b82becbe0a0a1bbb5561df69320edbd770897a8deaab23caa6736255e0dc33','PFTY','pfty','esMX','DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03','PFTY','pfty','enAU','DF6C50D3'), +('0a3f6f3f0535ea21dbe620085192afc796203047e270e0e1b76f15a739fe1797','PFTY','pfty','ptBR','DF6C50D3'), +('047329d08d433da2622e9fc2ee96c8dd8f35e7770699d07cf74855b9c8ea9125','PFTY','pfty','deDE','DF6C50D3'); /*!40000 ALTER TABLE `battlenet_modules` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2014_10_13_00_auth_434.sql b/sql/updates/auth/2014_10_13_00_auth_434.sql new file mode 100644 index 00000000000..e7c984d70f6 --- /dev/null +++ b/sql/updates/auth/2014_10_13_00_auth_434.sql @@ -0,0 +1,24 @@ +ALTER TABLE `battlenet_modules` + DROP PRIMARY KEY, + ADD PRIMARY KEY (`Name`, `System`); +DELETE FROM `battlenet_modules` WHERE `Name` IN ('ERRS','PFTY'); +INSERT INTO `battlenet_modules` (`Hash`,`Name`,`Type`,`System`,`Data`) VALUES +('cc654428261322763f4cada5b7f4b3b67660e85639bea916986b3f366fe8adc2', 'ERRS', 'xml', 'enGB', 'AA6C50D3'), +('2753d31092f1978bdd78ebd4fae2d189364ad7108ceb22fbf1413be1f43bef04', 'PFTY', 'pfty', 'zhCN', 'DF6C50D3'), +('5813f318f7e40a07a7cdfeeec9827942e6fdc5ccee0d4171148443e429ad0ead', 'PFTY', 'pfty', 'ruRU', 'DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03', 'PFTY', 'pfty', 'enSG', 'DF6C50D3'), +('870f53d10b4e1b09d6b622cd5671ba4ff1ad69512dfa2c676072c52e45c7f0f9', 'PFTY', 'pfty', 'esES', 'DF6C50D3'), +('305bbdab1953e65974a249e276867e13ad2c3cabca3668983cb5ed406251bb7b', 'PFTY', 'pfty', 'frFR', 'DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03', 'PFTY', 'pfty', 'enGB', 'DF6C50D3'), +('a2ec4b41148214037a2e89a2e557af716d085241b81f5244494bdc77a891ca38', 'PFTY', 'pfty', 'csCZ', 'DF6C50D3'), +('a8c77051991b1a6c5dfe412e9f46d8f584349996fbde37c4f2a527c192163502', 'PFTY', 'pfty', 'plPL', 'DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03', 'PFTY', 'pfty', 'enUS', 'DF6C50D3'), +('7466b2db3f03768aa2527535d4b3c6c9ef9e8fb07c6db88b1019f3d25a2942e8', 'PFTY', 'pfty', 'koKR', 'DF6C50D3'), +('a2ec4b41148214037a2e89a2e557af716d085241b81f5244494bdc77a891ca38', 'PFTY', 'pfty', 'jaJP', 'DF6C50D3'), +('3e381d4f83201f4e3c482eb74da12e5ff9dd924da2413d8fb33f5eea9a02c2c2', 'PFTY', 'pfty', 'zhTW', 'DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03', 'PFTY', 'pfty', 'enTH', 'DF6C50D3'), +('b72e65b6b34d8f859e79b5f28952e26553a796d5e1d75c2b5930bc0daeaa728c', 'PFTY', 'pfty', 'itIT', 'DF6C50D3'), +('e8b82becbe0a0a1bbb5561df69320edbd770897a8deaab23caa6736255e0dc33', 'PFTY', 'pfty', 'esMX', 'DF6C50D3'), +('83663d54444eadad40d43725e59bde8eda10276e76fc3c4e6f2ca56332ee8f03', 'PFTY', 'pfty', 'enAU', 'DF6C50D3'), +('0a3f6f3f0535ea21dbe620085192afc796203047e270e0e1b76f15a739fe1797', 'PFTY', 'pfty', 'ptBR', 'DF6C50D3'), +('047329d08d433da2622e9fc2ee96c8dd8f35e7770699d07cf74855b9c8ea9125', 'PFTY', 'pfty', 'deDE', 'DF6C50D3'); diff --git a/src/server/bnetserver/Packets/CachePackets.cpp b/src/server/bnetserver/Packets/CachePackets.cpp new file mode 100644 index 00000000000..cd5aa05fed6 --- /dev/null +++ b/src/server/bnetserver/Packets/CachePackets.cpp @@ -0,0 +1,83 @@ +/* + * 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 "CachePackets.h" + +void Battlenet::Cache::GetStreamItemsRequest::Read() +{ + if (_stream.Read(1)) + { + _stream.Read(11); // padding + ItemName = _stream.ReadFourCC(); + Channel = _stream.ReadFourCC(); + } + else + _stream.Read(16); + + _stream.Read(1); // StreamDirection + ReferenceTime = _stream.Read(32) - std::numeric_limits::min(); + Locale = _stream.ReadFourCC(); + Index = _stream.Read(32); + _stream.Read(6); // Module count, always 0 +} + +std::string Battlenet::Cache::GetStreamItemsRequest::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Cache::GetStreamItemsRequest Channel: " << Channel << ", ItemName: " << ItemName + << ", Locale: " << Locale << ", Index: " << Index; + return stream.str(); +} + +void Battlenet::Cache::GetStreamItemsRequest::CallHandler(Session* session) +{ + session->HandleGetStreamItemsRequest(*this); +} + +Battlenet::Cache::GetStreamItemsResponse::~GetStreamItemsResponse() +{ + for (size_t i = 0; i < Modules.size(); ++i) + delete Modules[i]; +} + +void Battlenet::Cache::GetStreamItemsResponse::Write() +{ + _stream.Write(0, 16); + _stream.Write(Modules.size(), 6); + for (ModuleInfo const* info : Modules) + { + _stream.WriteBytes(info->Type.c_str(), 4); + _stream.WriteFourCC(info->Region); + _stream.WriteBytes(info->ModuleId, 32); + _stream.WriteBytes(info->Data, 4); + } + + _stream.Write(Index, 32); + _stream.Write(0, 17); // padding + _stream.Write(1, 16); + _stream.Write(0, 2); +} + +std::string Battlenet::Cache::GetStreamItemsResponse::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::Cache::GetStreamItemsResponse modules " << Modules.size(); + for (ModuleInfo const* module : Modules) + stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize); + + return stream.str(); +} diff --git a/src/server/bnetserver/Packets/CachePackets.h b/src/server/bnetserver/Packets/CachePackets.h index 2e473df4e72..ba4153fe623 100644 --- a/src/server/bnetserver/Packets/CachePackets.h +++ b/src/server/bnetserver/Packets/CachePackets.h @@ -29,7 +29,7 @@ namespace Battlenet CMSG_GATEWAY_LOOKUP_REQUEST = 0x2, // Not implemented CMSG_CONNECT_REQUEST = 0x4, // Not implemented CMSG_DATA_CHUNK = 0x7, // Not implemented - SMSG_GET_STREAM_ITEMS_REQUEST = 0x9, // Not implemented + CMSG_GET_STREAM_ITEMS_REQUEST = 0x9, // Not implemented SMSG_GATEWAY_LOOKUP_RESPONSE = 0x3, // Not implemented SMSG_CONNECT_RESPONSE = 0x4, // Not implemented @@ -37,6 +37,41 @@ namespace Battlenet SMSG_RESULT = 0x8, // Not implemented SMSG_GET_STREAM_ITEMS_RESPONSE = 0x9 // Not implemented }; + + class GetStreamItemsRequest final : public ClientPacket + { + public: + GetStreamItemsRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_GET_STREAM_ITEMS_REQUEST, CACHE) && "Invalid packet header for GetStreamItemsRequest"); + } + + void Read() override; + std::string ToString() const override; + void CallHandler(Session* session); + + std::string Channel; + std::string ItemName; + std::string Locale; + uint32 Index; + int32 ReferenceTime; + }; + + class GetStreamItemsResponse final : public ServerPacket + { + public: + GetStreamItemsResponse() : ServerPacket(PacketHeader(SMSG_GET_STREAM_ITEMS_RESPONSE, CACHE)) + { + } + + ~GetStreamItemsResponse(); + + void Write() override; + std::string ToString() const override; + + uint32 Index; + std::vector Modules; + }; } } diff --git a/src/server/bnetserver/Packets/PacketManager.cpp b/src/server/bnetserver/Packets/PacketManager.cpp index af31b596192..019cf48ac30 100644 --- a/src/server/bnetserver/Packets/PacketManager.cpp +++ b/src/server/bnetserver/Packets/PacketManager.cpp @@ -217,13 +217,13 @@ void Battlenet::PacketManager::RegisterCachePackets() REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_GATEWAY_LOOKUP_REQUEST, CACHE), "Cache::GatewayLookupRequest"); REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_CONNECT_REQUEST, CACHE), "Cache::ConnectRequest"); REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::CMSG_DATA_CHUNK, CACHE), "Cache::DataChunk"); - REGISTER_CLIENT_PACKET_NAME(PacketHeader(Cache::SMSG_GET_STREAM_ITEMS_REQUEST, CACHE), "Cache::GetStreamItemsRequest"); + REGISTER_CLIENT_PACKET(PacketHeader(Cache::CMSG_GET_STREAM_ITEMS_REQUEST, CACHE), Cache::GetStreamItemsRequest); REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_GATEWAY_LOOKUP_RESPONSE, CACHE), "Cache::GatewayLookupResponse"); REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_CONNECT_RESPONSE, CACHE), "Cache::ConnectResponse"); REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_PUBLISH_LIST_RESPONSE, CACHE), "Cache::PublishListResponse"); REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_RESULT, CACHE), "Cache::Result"); - REGISTER_SERVER_PACKET_NAME(PacketHeader(Cache::SMSG_GET_STREAM_ITEMS_RESPONSE, CACHE), "Cache::GetStreamItemsResponse"); + REGISTER_SERVER_PACKET(PacketHeader(Cache::SMSG_GET_STREAM_ITEMS_RESPONSE, CACHE), Cache::GetStreamItemsResponse); } void Battlenet::PacketManager::RegisterProfilePackets() diff --git a/src/server/bnetserver/Server/ModuleManager.cpp b/src/server/bnetserver/Server/ModuleManager.cpp index 8dc43136739..05cee2ff42e 100644 --- a/src/server/bnetserver/Server/ModuleManager.cpp +++ b/src/server/bnetserver/Server/ModuleManager.cpp @@ -51,7 +51,8 @@ void Battlenet::ModuleManager::Load() Battlenet::ModuleInfo* Battlenet::ModuleManager::CreateModule(std::string const& os, std::string const& name) const { ModuleKey key { os, name }; - ASSERT(_modules.count(key)); + if (!_modules.count(key)) + return nullptr; return new ModuleInfo(*_modules.at(key)); } diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 7090c1f0ca7..9a5f60b296e 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -477,6 +477,17 @@ void Battlenet::Session::HandleSocialNetworkCheckConnected(Friends::SocialNetwor AsyncWrite(socialNetworkCheckConnectedResult); } +void Battlenet::Session::HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest) +{ + if (ModuleInfo* module = sModuleMgr->CreateModule(getStreamItemsRequest.Locale, getStreamItemsRequest.ItemName)) + { + Cache::GetStreamItemsResponse* getStreamItemsResponse = new Cache::GetStreamItemsResponse(); + getStreamItemsResponse->Index = getStreamItemsRequest.Index; + getStreamItemsResponse->Modules.push_back(module); + AsyncWrite(getStreamItemsResponse); + } +} + inline std::string PacketToStringHelper(Battlenet::ClientPacket const* packet) { if (sLog->ShouldLog("session.packets", LOG_LEVEL_TRACE)) diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index b2546c70cc6..a2c587841a4 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -81,6 +81,9 @@ namespace Battlenet // Friends void HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected); + // Cache + void HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest); + void Start() override; void UpdateRealms(std::vector& realms, std::vector& deletedRealms); diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index caa17364038..8dcee55ec6c 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -40,10 +40,12 @@ void Battlenet::SessionManager::AddSession(Session* session) { std::unique_lock lock(_sessionMutex); _sessions[{ session->GetAccountId(), session->GetGameAccountId() }] = session; + _sessionsByAccountId[session->GetAccountId()].push_back(session); } void Battlenet::SessionManager::RemoveSession(Session* session) { std::unique_lock lock(_sessionMutex); _sessions.erase({ session->GetAccountId(), session->GetGameAccountId() }); + _sessionsByAccountId[session->GetAccountId()].remove(session); } diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index 4f8e0d9fa97..bbd78c052d2 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -44,6 +44,7 @@ namespace Battlenet { typedef SocketMgr BaseSocketMgr; typedef std::map SessionMap; + typedef std::map> SessionByAccountMap; public: static SessionManager& Instance() @@ -74,6 +75,7 @@ namespace Battlenet static void OnSocketAccept(tcp::socket&& sock); SessionMap _sessions; + SessionByAccountMap _sessionsByAccountId; boost::shared_mutex _sessionMutex; }; } -- cgit v1.2.3 From cc27497ea7793cbedff2065028fcc8b3aab28f58 Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 14 Oct 2014 16:53:44 +0200 Subject: Battle.net: Removed not implemented comment from stream items opcodes --- src/server/bnetserver/Packets/CachePackets.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/CachePackets.h b/src/server/bnetserver/Packets/CachePackets.h index ba4153fe623..4d9987a0f0e 100644 --- a/src/server/bnetserver/Packets/CachePackets.h +++ b/src/server/bnetserver/Packets/CachePackets.h @@ -29,13 +29,13 @@ namespace Battlenet CMSG_GATEWAY_LOOKUP_REQUEST = 0x2, // Not implemented CMSG_CONNECT_REQUEST = 0x4, // Not implemented CMSG_DATA_CHUNK = 0x7, // Not implemented - CMSG_GET_STREAM_ITEMS_REQUEST = 0x9, // Not implemented + CMSG_GET_STREAM_ITEMS_REQUEST = 0x9, SMSG_GATEWAY_LOOKUP_RESPONSE = 0x3, // Not implemented SMSG_CONNECT_RESPONSE = 0x4, // Not implemented SMSG_PUBLISH_LIST_RESPONSE = 0x7, // Not implemented SMSG_RESULT = 0x8, // Not implemented - SMSG_GET_STREAM_ITEMS_RESPONSE = 0x9 // Not implemented + SMSG_GET_STREAM_ITEMS_RESPONSE = 0x9 }; class GetStreamItemsRequest final : public ClientPacket -- cgit v1.2.3 From f773a9e05340d4de7dd16d0e375a12611c3995b6 Mon Sep 17 00:00:00 2001 From: Shauren Date: Fri, 17 Oct 2014 22:48:06 +0200 Subject: Core: Implemented IPC (Inter-process communication) between worldserver and bnetserver using ZeroMQ library. * Implemented ToonReady and ToonLoggedOut battle.net packets --- CMakeLists.txt | 1 + cmake/macros/FindZMQ.cmake | 75 +++ dep/CMakeLists.txt | 1 + dep/PackageList.txt | 4 + dep/zmqpp/CMakeLists.txt | 31 + dep/zmqpp/zmqpp/compatibility.hpp | 97 +++ dep/zmqpp/zmqpp/context.cpp | 54 ++ dep/zmqpp/zmqpp/context.hpp | 184 ++++++ dep/zmqpp/zmqpp/context_options.hpp | 26 + dep/zmqpp/zmqpp/exception.hpp | 87 +++ dep/zmqpp/zmqpp/frame.cpp | 95 +++ dep/zmqpp/zmqpp/frame.hpp | 58 ++ dep/zmqpp/zmqpp/inet.hpp | 171 +++++ dep/zmqpp/zmqpp/message.cpp | 454 +++++++++++++ dep/zmqpp/zmqpp/message.hpp | 253 ++++++++ dep/zmqpp/zmqpp/poller.cpp | 182 ++++++ dep/zmqpp/zmqpp/poller.hpp | 186 ++++++ dep/zmqpp/zmqpp/socket.cpp | 758 ++++++++++++++++++++++ dep/zmqpp/zmqpp/socket.hpp | 500 ++++++++++++++ dep/zmqpp/zmqpp/socket_options.hpp | 80 +++ dep/zmqpp/zmqpp/socket_types.hpp | 148 +++++ dep/zmqpp/zmqpp/zmqpp.cpp | 30 + dep/zmqpp/zmqpp/zmqpp.hpp | 111 ++++ src/server/CMakeLists.txt | 1 + src/server/bnetserver/CMakeLists.txt | 6 + src/server/bnetserver/Main.cpp | 16 +- src/server/bnetserver/Packets/BitStream.h | 12 +- src/server/bnetserver/Packets/FriendsPackets.cpp | 2 +- src/server/bnetserver/Packets/PacketManager.cpp | 4 +- src/server/bnetserver/Packets/WoWRealmPackets.cpp | 52 +- src/server/bnetserver/Packets/WoWRealmPackets.h | 27 + src/server/bnetserver/Realms/RealmList.cpp | 24 +- src/server/bnetserver/Realms/RealmList.h | 11 +- src/server/bnetserver/Realms/WorldListener.cpp | 109 ++++ src/server/bnetserver/Realms/WorldListener.h | 63 ++ src/server/bnetserver/Server/Session.h | 2 +- src/server/bnetserver/Server/SessionManager.cpp | 19 + src/server/bnetserver/Server/SessionManager.h | 3 + src/server/bnetserver/bnetserver.conf.dist | 7 + src/server/collision/CMakeLists.txt | 1 + src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 2 +- src/server/game/CMakeLists.txt | 3 + src/server/game/Chat/Chat.cpp | 2 +- src/server/game/Handlers/CharacterHandler.cpp | 7 +- src/server/game/Handlers/MiscHandler.cpp | 2 +- src/server/game/Server/BattlenetServerManager.cpp | 66 ++ src/server/game/Server/BattlenetServerManager.h | 55 ++ src/server/game/Server/WorldSession.cpp | 12 +- src/server/game/Server/WorldSocket.cpp | 4 +- src/server/game/World/World.cpp | 12 +- src/server/game/World/World.h | 3 +- src/server/ipc/CMakeLists.txt | 24 + src/server/ipc/Commands.cpp | 81 +++ src/server/ipc/Commands.h | 83 +++ src/server/ipc/ZMQTask.cpp | 93 +++ src/server/ipc/ZMQTask.h | 52 ++ src/server/ipc/ZmqContext.cpp | 52 ++ src/server/ipc/ZmqContext.h | 55 ++ src/server/ipc/ZmqListener.cpp | 69 ++ src/server/ipc/ZmqListener.h | 51 ++ src/server/ipc/ZmqMux.cpp | 67 ++ src/server/ipc/ZmqMux.h | 47 ++ src/server/ipc/ZmqWorker.cpp | 70 ++ src/server/ipc/ZmqWorker.h | 44 ++ src/server/scripts/CMakeLists.txt | 1 + src/server/scripts/Commands/cs_gm.cpp | 2 +- src/server/scripts/Commands/cs_misc.cpp | 2 +- src/server/scripts/Commands/cs_rbac.cpp | 2 +- src/server/scripts/Commands/cs_ticket.cpp | 6 +- src/server/worldserver/CMakeLists.txt | 6 + src/server/worldserver/Main.cpp | 49 +- src/server/worldserver/worldserver.conf.dist | 21 + 72 files changed, 4922 insertions(+), 68 deletions(-) create mode 100644 cmake/macros/FindZMQ.cmake create mode 100644 dep/zmqpp/CMakeLists.txt create mode 100644 dep/zmqpp/zmqpp/compatibility.hpp create mode 100644 dep/zmqpp/zmqpp/context.cpp create mode 100644 dep/zmqpp/zmqpp/context.hpp create mode 100644 dep/zmqpp/zmqpp/context_options.hpp create mode 100644 dep/zmqpp/zmqpp/exception.hpp create mode 100644 dep/zmqpp/zmqpp/frame.cpp create mode 100644 dep/zmqpp/zmqpp/frame.hpp create mode 100644 dep/zmqpp/zmqpp/inet.hpp create mode 100644 dep/zmqpp/zmqpp/message.cpp create mode 100644 dep/zmqpp/zmqpp/message.hpp create mode 100644 dep/zmqpp/zmqpp/poller.cpp create mode 100644 dep/zmqpp/zmqpp/poller.hpp create mode 100644 dep/zmqpp/zmqpp/socket.cpp create mode 100644 dep/zmqpp/zmqpp/socket.hpp create mode 100644 dep/zmqpp/zmqpp/socket_options.hpp create mode 100644 dep/zmqpp/zmqpp/socket_types.hpp create mode 100644 dep/zmqpp/zmqpp/zmqpp.cpp create mode 100644 dep/zmqpp/zmqpp/zmqpp.hpp create mode 100644 src/server/bnetserver/Realms/WorldListener.cpp create mode 100644 src/server/bnetserver/Realms/WorldListener.h create mode 100644 src/server/game/Server/BattlenetServerManager.cpp create mode 100644 src/server/game/Server/BattlenetServerManager.h create mode 100644 src/server/ipc/CMakeLists.txt create mode 100644 src/server/ipc/Commands.cpp create mode 100644 src/server/ipc/Commands.h create mode 100644 src/server/ipc/ZMQTask.cpp create mode 100644 src/server/ipc/ZMQTask.h create mode 100644 src/server/ipc/ZmqContext.cpp create mode 100644 src/server/ipc/ZmqContext.h create mode 100644 src/server/ipc/ZmqListener.cpp create mode 100644 src/server/ipc/ZmqListener.h create mode 100644 src/server/ipc/ZmqMux.cpp create mode 100644 src/server/ipc/ZmqMux.h create mode 100644 src/server/ipc/ZmqWorker.cpp create mode 100644 src/server/ipc/ZmqWorker.h (limited to 'src/server/bnetserver') diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e91c7da4ec..905d92996bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ set(OPENSSL_EXPECTED_VERSION 1.0.0) find_package(PCHSupport) find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED) +find_package(ZMQ REQUIRED) include(ConfigureBoost) find_package(MySQL REQUIRED) diff --git a/cmake/macros/FindZMQ.cmake b/cmake/macros/FindZMQ.cmake new file mode 100644 index 00000000000..6039dd56e2c --- /dev/null +++ b/cmake/macros/FindZMQ.cmake @@ -0,0 +1,75 @@ +# +# Find the ZMQ includes and library +# + +# This module defines +# ZMQ_INCLUDE_DIR, where to find zmq.h +# ZMQ_LIBRARY, the library needed to use ZMQ +# ZMQ_FOUND, if false, you cannot build anything that requires ZMQ. + +set(ZMQ_FOUND 0) + +if (PLATFORM EQUAL 64) + set(ZMQ_REGISTRY_PATH + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ (x64);DisplayIcon]" + ) +else() + set(ZMQ_REGISTRY_PATH + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayIcon]" + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayIcon]" + ) +endif() + +find_path(ZMQ_INCLUDE_DIR + NAMES + zmq.h + HINTS + "${ZMQ_REGISTRY_PATH}/include" + PATHS + /usr/include + /usr/local/include +) + +if (MSVC) + # Read registry key holding version + if (PLATFORM EQUAL 64) + get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ (x64);DisplayVersion]" NAME) + else() + get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayVersion]" NAME) + if (${ZMQ_NAME} MATCHES "registry") # if key was not found, the string "registry" is returned + get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayVersion]" NAME) + endif() + endif() + + # Replace dots with underscores + string(REGEX REPLACE "\\." "_" ZMQ_NAME ${ZMQ_NAME}) + + # Get Visual studio version number + string(REGEX REPLACE "Visual Studio ([0-9]+).*" "\\1" ZMQ_VS_VERSION ${CMAKE_GENERATOR}) + + # Format ZMQ library file name + set(ZMQ_LIBRARY_NAME "libzmq-v${ZMQ_VS_VERSION}0-mt-${ZMQ_NAME}") +endif() + +find_library(ZMQ_LIBRARY + NAMES + zmq + ${ZMQ_LIBRARY_NAME} + HINTS + "${ZMQ_REGISTRY_PATH}/lib" + PATHS + /lib + /usr/lib + /usr/local/lib +) + +if (ZMQ_INCLUDE_DIR AND ZMQ_LIBRARY) + set(ZMQ_FOUND 1) + message(STATUS "Found ZMQ library: ${ZMQ_LIBRARY}") + message(STATUS "Found ZMQ headers: ${ZMQ_INCLUDE_DIR}") +else() + message(FATAL_ERROR "Could not find ZMQ libraries/headers! Please install ZMQ with libraries and headers") +endif() + +# show the ZMQ_INCLUDE_DIR and ZMQ_LIBRARY variables only in the advanced view +mark_as_advanced(ZMQ_INCLUDE_DIR ZMQ_LIBRARY ZMQ_FOUND) diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 8ae2e7ac6d7..e304171560b 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -36,6 +36,7 @@ endif() if(SERVERS) add_subdirectory(gsoap) + add_subdirectory(zmqpp) endif() if(TOOLS) diff --git a/dep/PackageList.txt b/dep/PackageList.txt index 6c17867a929..aac1e5eb7b1 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -39,3 +39,7 @@ recastnavigation (Recast is state of the art navigation mesh construction toolse StormLib (a pack of modules, written in C++, which are able to read and also to write files from/to the MPQ archives) http://www.zezula.net/en/mpq/stormlib.html Version: 8.04 + +zmqpp (C++ binding for 0mq/zmq is a 'high-level' library that hides most of the c-style interface core 0mq provides.) + https://github.com/zeromq/zmqpp + Version: 3.2.0 17e9f6afa98f56ecac1e3f3eecbfc112357a6732 diff --git a/dep/zmqpp/CMakeLists.txt b/dep/zmqpp/CMakeLists.txt new file mode 100644 index 00000000000..6b6bd35b6e7 --- /dev/null +++ b/dep/zmqpp/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2008-2014 TrinityCore +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +file(GLOB_RECURSE sources_zmqpp zmqpp/*.cpp zmqpp/*.hpp zmqpp/*.h) + +set(zmqpp_STAT_SRCS + ${sources_zmqpp} +) + +include_directories(${ZMQ_INCLUDE_DIR}) + +add_library(zmqpp STATIC + ${zmqpp_STAT_SRCS} +) + +if (WIN32) + add_definitions(-DBUILD_VERSION=\\"3.2.0\\") +else() + add_definitions(-DBUILD_VERSION='"3.2.0"') +endif() + +add_definitions(-DBUILD_VERSION_MAJOR=3) +add_definitions(-DBUILD_VERSION_MINOR=2) +add_definitions(-DBUILD_VERSION_REVISION=0) diff --git a/dep/zmqpp/zmqpp/compatibility.hpp b/dep/zmqpp/zmqpp/compatibility.hpp new file mode 100644 index 00000000000..103b2c82ebd --- /dev/null +++ b/dep/zmqpp/zmqpp/compatibility.hpp @@ -0,0 +1,97 @@ +/** + * \file + * + * \date 10 Sep 2011 + * \author ron + * \author Ben Gray (\@benjamg) + * + * A fair number of C++0x (or more accurately C++11) features are used in this + * library and as this project is used where I work on older compilers this + * file was created to help. + * + * C++ features and their workaround where not supported: + * \li lambda functions - disabled, these are only used in the test anyway. + * \li typesafe enums - replaced with enum where comparisons needed. + * \li nullptr - defined to null. + * + * As of the port to version 3.1 (libzmqpp version 1.1.0) this file will also + * be used to maintain compatablity with multiple versions of 0mq + */ + +#ifndef ZMQPP_COMPATIBILITY_HPP_ +#define ZMQPP_COMPATIBILITY_HPP_ + +#include +#include + +// Currently we require at least 0mq version 2.2.x +#define ZMQPP_REQUIRED_ZMQ_MAJOR 2 +#define ZMQPP_REQUIRED_ZMQ_MINOR 2 + +#if (ZMQ_VERSION_MAJOR < ZMQPP_REQUIRED_ZMQ_MAJOR) || ((ZMQ_VERSION_MAJOR == ZMQPP_REQUIRED_ZMQ_MAJOR) && (ZMQ_VERSION_MINOR < ZMQPP_REQUIRED_ZMQ_MINOR)) +#error zmqpp requires a later version of 0mq +#endif + +// Experimental feature support +#if (ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR == 0) +#define ZMQ_EXPERIMENTAL_LABELS +#endif + +// Deal with older versions of gcc +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ == 4 + +// Deal with older gcc not supporting C++0x typesafe enum class name {} comparison +#if __GNUC_MINOR__ < 4 +#define ZMQPP_COMPARABLE_ENUM enum +#endif + +#if __GNUC_MINOR__ == 4 +#if __GNUC_PATCHLEVEL__ < 1 +#undef ZMQPP_COMPARABLE_ENUM +#define ZMQPP_COMPARABLE_ENUM enum +#endif // if __GNUC_PATCHLEVEL__ < 1 +#endif // if __GNUC_MINOR__ == 4 + +// Deal with older gcc not supporting C++0x lambda function +#if __GNUC_MINOR__ < 5 +#define ZMQPP_IGNORE_LAMBDA_FUNCTION_TESTS +#define ZMQPP_EXPLICITLY_DELETED +#endif // if __GNUC_MINOR__ < 5 + +// Deal with older gcc not supporting C++0x nullptr +#if __GNUC_MINOR__ < 6 +#define nullptr NULL +#define NOEXCEPT +#endif // if __GNUC_MINOR__ < 6 + +#endif // if __GNUC_ == 4 +#endif // if defined(__GNUC__) && !defined(__clang__) + +#if defined(_MSC_VER) +#define NOEXCEPT throw() +#if _MSC_VER < 1800 +#define ZMQPP_EXPLICITLY_DELETED +#endif // if _MSC_VER < 1800 +#if _MSC_VER < 1600 +#define nullptr NULL +#define ZMQPP_IGNORE_LAMBDA_FUNCTION_TESTS +#define ZMQPP_COMPARABLE_ENUM enum +#endif // if _MSC_VER < 1600 +#endif // if defined(_MSC_VER) + +// Generic state, assume a modern compiler +#ifndef ZMQPP_COMPARABLE_ENUM +#define ZMQPP_COMPARABLE_ENUM enum class +#endif + +#ifndef ZMQPP_EXPLICITLY_DELETED +#define ZMQPP_EXPLICITLY_DELETED = delete +#endif + +#ifndef NOEXCEPT +#define NOEXCEPT noexcept +#endif + +#endif /* ZMQPP_COMPATIBILITY_HPP_ */ + diff --git a/dep/zmqpp/zmqpp/context.cpp b/dep/zmqpp/zmqpp/context.cpp new file mode 100644 index 00000000000..32c657199dc --- /dev/null +++ b/dep/zmqpp/zmqpp/context.cpp @@ -0,0 +1,54 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#include "context.hpp" + +namespace zmqpp +{ + +void context::terminate() +{ + int result; + do + { +#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + result = zmq_term(_context); +#else + result = zmq_ctx_destroy(_context); +#endif + } while (result != 0 && zmq_errno() == EINTR); + if (result != 0) { throw zmq_internal_exception(); } + _context = nullptr; +} + +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +void context::set(context_option const option, int const value) +{ + if (nullptr == _context) { throw invalid_instance("context is invalid"); } + + if (0 != zmq_ctx_set(_context, static_cast(option), value)) + { + throw zmq_internal_exception(); + } +} + +int context::get(context_option const option) +{ + if (nullptr == _context) { throw invalid_instance("context is invalid"); } + + int result = zmq_ctx_get(_context, static_cast(option)); + + if (result < 0) + { + throw zmq_internal_exception(); + } + + return result; +} +#endif + +} diff --git a/dep/zmqpp/zmqpp/context.hpp b/dep/zmqpp/zmqpp/context.hpp new file mode 100644 index 00000000000..3ffaf791440 --- /dev/null +++ b/dep/zmqpp/zmqpp/context.hpp @@ -0,0 +1,184 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_CONTEXT_HPP_ +#define ZMQPP_CONTEXT_HPP_ + +#include + +#include + +#include "compatibility.hpp" +#include "exception.hpp" +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#include "context_options.hpp" +#endif + +namespace zmqpp +{ + +/*! + * The context class represents internal zmq context and io threads. + * + * By default the context class will create one thread, however this can be + * overridden in the constructor. + * + * The context class is the only object that can be considered thread safe. + * + * All sockets using endpoints other than inproc require the context to have + * at least one thread. + * + * This class is c++0x move supporting and cannot be copied. + */ +class context +{ +public: + +#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + /*! + * Initialise the 0mq context. + * + * If only inproc is used then the context may be created with zero threads. + * Any inproc endpoint using sockets must be created using the same context. + * + * The context is thread safe an may be used anywhere in your application, + * however there is no requirement (other than inproc restrictions) for you + * to do this. + * + * \param threads an integer argument for the number of required threads. Defaults to 1. + */ + context(int const& threads = 1) +#else + /*! + * Initialise the 0mq context. + * + * The context is thread safe an may be used anywhere in your application, + * however there is no requirement (other than inproc restrictions) for you + * to do this. + */ + context() +#endif + : _context(nullptr) + { +#if (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + _context = zmq_init(threads); +#else + _context = zmq_ctx_new(); +#endif + + if (nullptr == _context) + { + throw zmq_internal_exception(); + } + } + + /*! + * Closes the 0mq context. + * + * Any blocking calls other than a socket close will return with an error. + * + * If there are open sockets will block while zmq internal buffers are + * processed up to a limit specified by that sockets linger option. + */ + ~context() NOEXCEPT + { + if (nullptr != _context) + { + terminate(); + } + } + + /*! + * Move supporting constructor. + * + * Allows zero-copy move semantics to be used with this class. + * + * \param source a rvalue instance of the object who's internals we wish to steal. + */ + context(context&& source) NOEXCEPT + : _context(source._context) + { + source._context = nullptr; + } + + /*! + * Move supporting operator. + * + * Allows zero-copy move semantics to be used with this class. + * + * \param source an rvalue instance of the context who's internals we wish to steal. + */ + context& operator=(context&& source) NOEXCEPT + { + std::swap( _context, source._context ); + return *this; + } + + /*! + * Terminate the current context. + * + * Any blocking calls other than a socket close will return with an error. + * + * If there are open sockets will block while zmq internal buffers are + * processed up to a limit specified by that sockets linger option. + */ + void terminate(); + +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) + /*! + * Set the value of an option in the underlaying zmq context. + * + * \param option a valid ::context_option + * \param value to set the option to + */ + void set(context_option const option, int const value); + + /*! + * Get a context option from the underlaying zmq context. + * + * \param option a valid ::context_option + * \return context option value + */ + int get(context_option const option); +#endif + + /*! + * Validity checking of the context + * + * Checks if the underlying 0mq context for this instance is valid. + * + * Contexts should always be valid unless people are doing 'fun' things with + * std::move. + * + * \return boolean true if the object is valid. + */ + operator bool() const NOEXCEPT + { + return nullptr != _context; + } + + /*! + * Access to the raw 0mq context + * + * \return void pointer to the underlying 0mq context. + */ + operator void*() const NOEXCEPT + { + return _context; + } + +private: + void* _context; + + // No copy - private and not implemented + context(context const&) ZMQPP_EXPLICITLY_DELETED; + context& operator=(context const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; +}; + +} + +#endif /* ZMQPP_CONTEXT_HPP_ */ diff --git a/dep/zmqpp/zmqpp/context_options.hpp b/dep/zmqpp/zmqpp/context_options.hpp new file mode 100644 index 00000000000..b2e2cf4805f --- /dev/null +++ b/dep/zmqpp/zmqpp/context_options.hpp @@ -0,0 +1,26 @@ +/** + * \file + * + * \date 3 Jul 2013 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_CONTEXT_OPTIONS_HPP_ +#define ZMQPP_CONTEXT_OPTIONS_HPP_ + +namespace zmqpp +{ + +/** \todo Expand the information on the options to make it actually useful. */ +/*! + * \brief possible Context options in zmq + */ + +enum class context_option { + io_threads = ZMQ_IO_THREADS, /*!< I/O thread count */ + max_sockets = ZMQ_MAX_SOCKETS, /*!< Maximum supported sockets */ +}; + +} + +#endif /* ZMQPP_CONTEXT_OPTIONS_HPP_ */ diff --git a/dep/zmqpp/zmqpp/exception.hpp b/dep/zmqpp/zmqpp/exception.hpp new file mode 100644 index 00000000000..a0b234769ce --- /dev/null +++ b/dep/zmqpp/zmqpp/exception.hpp @@ -0,0 +1,87 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_EXCEPTION_HPP_ +#define ZMQPP_EXCEPTION_HPP_ + +#include +#include + +#include + +namespace zmqpp +{ + +/** \todo Have a larger variety of exceptions with better state debug information */ + +/*! + * Represents the base zmqpp exception. + * + * All zmqpp runtime exceptions are children of this class. + * The class itself does not provide any special access fields but it only + * for convince when catching exceptions. + * + * The class extends std::runtime_error. + * + */ +class exception : public std::runtime_error +{ +public: + /*! + * Standard exception constructor. + * + * \param message a string representing the error message. + */ + exception(std::string const& message) + : std::runtime_error(message) + { } +}; + +/*! + * Represents an attempt to use an invalid object. + * + * Objects may be invalid initially or after a shutdown or close. + */ +class invalid_instance : public exception +{ +public: + invalid_instance(std::string const& message) + : exception(message) + { } +}; + +/*! + * Represents internal zmq errors. + * + * Any error response from the zmq bindings will be wrapped in this error. + * + * The class provides access to the zmq error number via zmq_error(). + */ +class zmq_internal_exception : public exception +{ +public: + /*! + * Uses the zmq functions to pull out error messages and numbers. + */ + zmq_internal_exception() + : exception(zmq_strerror(zmq_errno())) + , _error(zmq_errno()) + { } + + /*! + * Retrieve the zmq error number associated with this exception. + * \return zmq error number + */ + int zmq_error() const { return _error; } + +private: + int _error; +}; + +} + +#endif /* ZMQPP_EXCEPTION_HPP_ */ diff --git a/dep/zmqpp/zmqpp/frame.cpp b/dep/zmqpp/zmqpp/frame.cpp new file mode 100644 index 00000000000..4c512ae1010 --- /dev/null +++ b/dep/zmqpp/zmqpp/frame.cpp @@ -0,0 +1,95 @@ +/** + * \file + * + * \date 8 Jan 2014 + * \author Ben Gray (\@benjamg) + */ + +#include +#include + +#include "exception.hpp" +#include "frame.hpp" + +namespace zmqpp { + +frame::frame() + : _sent( false ) +{ + if( 0 != zmq_msg_init( &_msg ) ) + { + throw zmq_internal_exception(); + } +} + +frame::frame(size_t const size) + : _sent( false ) +{ + if( 0 != zmq_msg_init_size( &_msg, size ) ) + { + throw zmq_internal_exception(); + } +} + +frame::frame(void const* part, size_t const size) + : _sent( false ) +{ + if( 0 != zmq_msg_init_size( &_msg, size ) ) + { + throw zmq_internal_exception(); + } + + void* msg_data = zmq_msg_data( &_msg ); + memcpy( msg_data, part, size ); +} + +frame::frame(void* part, size_t const size, zmq_free_fn *ffn, void *hint) + : _sent( false ) +{ + if( 0 != zmq_msg_init_data( &_msg, part, size, ffn, hint ) ) + { + throw zmq_internal_exception(); + } +} + +frame::~frame() +{ +#ifndef NDEBUG // unused assert variable in release + int result = zmq_msg_close( &_msg ); + assert(0 == result); +#else + zmq_msg_close( &_msg ); +#endif // NDEBUG +} + +frame::frame(frame&& other) + : _sent( other._sent ) +{ + zmq_msg_init( &_msg ); + zmq_msg_move( &_msg, &other._msg ); + other._sent = false; +} + +frame& frame::operator=(frame&& other) +{ + zmq_msg_init( &_msg ); + zmq_msg_move( &_msg, &other._msg ); + std::swap( _sent, other._sent ); + + return *this; +} + +frame frame::copy() const +{ + frame other( size() ); + other._sent = _sent; + + if( 0 != zmq_msg_copy( &other._msg, const_cast(&_msg) ) ) + { + throw zmq_internal_exception(); + } + + return other; +} + +} // namespace zmqpp diff --git a/dep/zmqpp/zmqpp/frame.hpp b/dep/zmqpp/zmqpp/frame.hpp new file mode 100644 index 00000000000..c9e4b9b7d82 --- /dev/null +++ b/dep/zmqpp/zmqpp/frame.hpp @@ -0,0 +1,58 @@ +/** + * \file + * + * \date 8 Jan 2014 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_MESSAGE_FRAME_HPP_ +#define ZMQPP_MESSAGE_FRAME_HPP_ + +#include + +#include "compatibility.hpp" + +namespace zmqpp { + +/*! + * \brief an internal frame wrapper for a single zmq message + * + * This frame wrapper consists of a zmq message and meta data it is used + * by the zmqpp message class to keep track of parts in the internal + * queue. It is unlikely you need to use this class. + */ +class frame +{ +public: + frame(); + frame(size_t const size); + frame(void const* part, size_t const size); + frame(void* part, size_t const size, zmq_free_fn *ffn, void *hint); + + ~frame(); + + bool is_sent() const { return _sent; } + void const* data() const { return zmq_msg_data( const_cast(&_msg) ); } + size_t size() const { return zmq_msg_size( const_cast(&_msg) ); } + + void mark_sent() { _sent = true; } + zmq_msg_t& msg() { return _msg; } + + // Move operators + frame(frame&& other); + frame& operator=(frame&& other); + + frame copy() const; + +private: + bool _sent; + zmq_msg_t _msg; + + // Disable implicit copy support, code must request a copy to clone + frame(frame const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; + frame& operator=(frame const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; +}; + +} // namespace zmqpp + +#endif /* ZMQPP_MESSAGE_FRAME_HPP_ */ diff --git a/dep/zmqpp/zmqpp/inet.hpp b/dep/zmqpp/zmqpp/inet.hpp new file mode 100644 index 00000000000..5245aa4143c --- /dev/null +++ b/dep/zmqpp/zmqpp/inet.hpp @@ -0,0 +1,171 @@ +/** + * \file + * + * \date 10 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_INET_HPP_ +#define ZMQPP_INET_HPP_ + +/** \todo cross-platform version of including headers. */ +// We get htons and htonl from here +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "compatibility.hpp" + +namespace zmqpp +{ + +/*! + * \brief Possible byte order types. + * + * An enumeration of all the known order types, all two of them. + * There is also an entry for unknown which is just used as a default. + */ +ZMQPP_COMPARABLE_ENUM order { + big_endian, /*!< byte order is big endian */ + little_endian /*!< byte order is little endian */ +}; + +/*! + * Common code for the 64bit versions of htons/htons and ntohs/ntohl + * + * As htons and ntohs (or htonl and ntohs) always just do the same thing, ie + * swap bytes if the host order differs from network order or otherwise don't + * do anything, it seemed silly to type the code twice. + * + * \note This code assumes network order is always big endian. Which it is. + * \note The host endian is only checked once and afterwards assumed to remain + * the same. + * + * \param value_to_check unsigned 64 bit integer to swap + * \return swapped (or not) unsigned 64 bit integer + */ +inline uint64_t swap_if_needed(uint64_t const value_to_check) +{ + static order host_order = (htonl(42) == 42) ? order::big_endian : order::little_endian; + + if (order::big_endian == host_order) + { + return value_to_check; + } + + union { + uint64_t integer; + uint8_t bytes[8]; + } value { value_to_check }; + + std::swap(value.bytes[0], value.bytes[7]); + std::swap(value.bytes[1], value.bytes[6]); + std::swap(value.bytes[2], value.bytes[5]); + std::swap(value.bytes[3], value.bytes[4]); + + return value.integer; +} + +/*! + * 64 bit version of the htons/htonl + * + * I've used the name htonll to try and keep with the htonl naming scheme. + * + * \param hostlonglong unsigned 64 bit host order integer + * \return unsigned 64 bit network order integer + */ +inline uint64_t htonll(uint64_t const hostlonglong) +{ + return zmqpp::swap_if_needed(hostlonglong); +} + +/*! + * 64 bit version of the ntohs/ntohl + * + * I've used the name htonll to try and keep with the htonl naming scheme. + * + * \param networklonglong unsigned 64 bit network order integer + * \return unsigned 64 bit host order integer + */ +inline uint64_t ntohll(uint64_t const networklonglong) +{ + return zmqpp::swap_if_needed(networklonglong); +} + +/*! + * floating point version of the htons/htonl + * + * \param value host order floating point + * \returns network order floating point + */ +inline float htonf(float value) +{ + assert(sizeof(float) == sizeof(uint32_t)); + + uint32_t temp; + memcpy(&temp, &value, sizeof(uint32_t)); + temp = htonl( temp ); + memcpy(&value, &temp, sizeof(uint32_t)); + + return value; +} + +/*! + * floating point version of the ntohs/ntohl + * + * \param value network order float + * \returns host order float + */ +inline float ntohf(float value) +{ + assert(sizeof(float) == sizeof(uint32_t)); + + uint32_t temp; + memcpy(&temp, &value, sizeof(uint32_t)); + temp = ntohl( temp ); + memcpy(&value, &temp, sizeof(uint32_t)); + + return value; +} + +/*! + * double precision floating point version of the htons/htonl + * + * \param value host order double precision floating point + * \returns network order double precision floating point + */ +inline double htond(double value) +{ + assert(sizeof(double) == sizeof(uint64_t)); + + uint64_t temp; + memcpy(&temp, &value, sizeof(uint64_t)); + temp = zmqpp::htonll(temp); + memcpy(&value, &temp, sizeof(uint64_t)); + + return value; +} + +/*! + * double precision floating point version of the ntohs/ntohl + * + * \param value network order double precision floating point + * \returns host order double precision floating point + */ +inline double ntohd(double value) +{ + assert(sizeof(double) == sizeof(uint64_t)); + + uint64_t temp; + memcpy(&temp, &value, sizeof(uint64_t)); + temp = zmqpp::ntohll(temp); + memcpy(&value, &temp, sizeof(uint64_t)); + + return value; +} + +} + +#endif /* INET_HPP_ */ diff --git a/dep/zmqpp/zmqpp/message.cpp b/dep/zmqpp/zmqpp/message.cpp new file mode 100644 index 00000000000..58587307364 --- /dev/null +++ b/dep/zmqpp/zmqpp/message.cpp @@ -0,0 +1,454 @@ +/* + * Created on: 9 Aug 2011 + * Author: Ben Gray (@benjamg) + */ + +#include +#include + +#include "exception.hpp" +#include "inet.hpp" +#include "message.hpp" + +namespace zmqpp +{ + +/*! + * \brief internal construct + * \internal handles bubbling callback from zmq c style to the c++ functor provided + */ +struct callback_releaser +{ + message::release_function func; +}; + +message::message() + : _parts() + , _read_cursor(0) +{ +} + +message::~message() +{ + _parts.clear(); +} + +size_t message::parts() const +{ + return _parts.size(); +} + +/* + * The two const_casts in size and raw_data are a little bit hacky + * but neither of these methods called this way actually modify data + * so accurately represent the intent of these calls. + */ + +size_t message::size(size_t const part /* = 0 */) const +{ + if(part >= _parts.size()) + { + throw exception("attempting to request a message part outside the valid range"); + } + + return _parts[part].size(); +} + +void const* message::raw_data(size_t const part /* = 0 */) const +{ + if(part >= _parts.size()) + { + throw exception("attempting to request a message part outside the valid range"); + } + + return _parts[part].data(); +} + +zmq_msg_t& message::raw_msg(size_t const part /* = 0 */) +{ + if(part >= _parts.size()) + { + throw exception("attempting to request a message part outside the valid range"); + } + + return _parts[part].msg(); +} + +zmq_msg_t& message::raw_new_msg() +{ + _parts.push_back( frame() ); + + return _parts.back().msg(); +} + +zmq_msg_t& message::raw_new_msg(size_t const reserve_data_size) +{ + _parts.push_back( frame(reserve_data_size) ); + + return _parts.back().msg(); +} + +std::string message::get(size_t const part /* = 0 */) const +{ + return std::string(static_cast(raw_data(part)), size(part)); +} + + +// Move operators will take ownership of message parts without copying +void message::move(void* part, size_t const size, release_function const& release) +{ + callback_releaser* hint = new callback_releaser(); + hint->func = release; + + _parts.push_back( frame( part, size, &message::release_callback, hint ) ); +} + +// Stream reader style +void message::reset_read_cursor() +{ + _read_cursor = 0; +} + +void message::get(int8_t& integer, size_t const part) const +{ + assert(sizeof(int8_t) == size(part)); + + int8_t const* byte = static_cast(raw_data(part)); + integer = *byte; +} + +void message::get(int16_t& integer, size_t const part) const +{ + assert(sizeof(int16_t) == size(part)); + + uint16_t const* network_order = static_cast(raw_data(part)); + integer = static_cast(ntohs(*network_order)); +} + +void message::get(int32_t& integer, size_t const part) const +{ + assert(sizeof(int32_t) == size(part)); + + uint32_t const* network_order = static_cast(raw_data(part)); + integer = static_cast(htonl(*network_order)); +} + +void message::get(int64_t& integer, size_t const part) const +{ + assert(sizeof(int64_t) == size(part)); + + uint64_t const* network_order = static_cast(raw_data(part)); + integer = static_cast(zmqpp::htonll(*network_order)); +} + +void message::get(uint8_t& unsigned_integer, size_t const part) const +{ + assert(sizeof(uint8_t) == size(part)); + + uint8_t const* byte = static_cast(raw_data(part)); + unsigned_integer = *byte; +} + +void message::get(uint16_t& unsigned_integer, size_t const part) const +{ + assert(sizeof(uint16_t) == size(part)); + + uint16_t const* network_order = static_cast(raw_data(part)); + unsigned_integer = ntohs(*network_order); +} + +void message::get(uint32_t& unsigned_integer, size_t const part) const +{ + assert(sizeof(uint32_t) == size(part)); + + uint32_t const* network_order = static_cast(raw_data(part)); + unsigned_integer = ntohl(*network_order); +} + +void message::get(uint64_t& unsigned_integer, size_t const part) const +{ + assert(sizeof(uint64_t) == size(part)); + + uint64_t const* network_order = static_cast(raw_data(part)); + unsigned_integer = zmqpp::ntohll(*network_order); +} + +void message::get(float& floating_point, size_t const part) const +{ + assert(sizeof(float) == size(part)); + + float const* network_order = static_cast(raw_data(part)); + floating_point = zmqpp::ntohf(*network_order); +} + +void message::get(double& double_precision, size_t const part) const +{ + assert(sizeof(double) == size(part)); + + double const* network_order = static_cast(raw_data(part)); + double_precision = zmqpp::ntohd(*network_order); +} + +void message::get(bool& boolean, size_t const part) const +{ + assert(sizeof(uint8_t) == size(part)); + + uint8_t const* byte = static_cast(raw_data(part)); + boolean = (*byte != 0); +} + +void message::get(std::string& string, size_t const part) const +{ + string.assign( get(part) ); +} + + +// Stream writer style - these all use copy styles +message& message::operator<<(int8_t const integer) +{ + add(reinterpret_cast(&integer), sizeof(int8_t)); + return *this; +} + +message& message::operator<<(int16_t const integer) +{ + uint16_t network_order = htons(static_cast(integer)); + add(reinterpret_cast(&network_order), sizeof(uint16_t)); + + return *this; +} + +message& message::operator<<(int32_t const integer) +{ + uint32_t network_order = htonl(static_cast(integer)); + add(reinterpret_cast(&network_order), sizeof(uint32_t)); + + return *this; +} + +message& message::operator<<(int64_t const integer) +{ + uint64_t network_order = zmqpp::htonll(static_cast(integer)); + add(reinterpret_cast(&network_order), sizeof(uint64_t)); + + return *this; +} + + +message& message::operator<<(uint8_t const unsigned_integer) +{ + add(reinterpret_cast(&unsigned_integer), sizeof(uint8_t)); + return *this; +} + +message& message::operator<<(uint16_t const unsigned_integer) +{ + uint16_t network_order = htons(unsigned_integer); + add(reinterpret_cast(&network_order), sizeof(uint16_t)); + + return *this; +} + +message& message::operator<<(uint32_t const unsigned_integer) +{ + uint32_t network_order = htonl(unsigned_integer); + add(reinterpret_cast(&network_order), sizeof(uint32_t)); + + return *this; +} + +message& message::operator<<(uint64_t const unsigned_integer) +{ + uint64_t network_order = zmqpp::htonll(unsigned_integer); + add(reinterpret_cast(&network_order), sizeof(uint64_t)); + + return *this; +} + +message& message::operator<<(float const floating_point) +{ + assert(sizeof(float) == 4); + + float network_order = zmqpp::htonf(floating_point); + add(&network_order, sizeof(float)); + + return *this; +} + +message& message::operator<<(double const double_precision) +{ + assert(sizeof(double) == 8); + + double network_order = zmqpp::htond(double_precision); + add(&network_order, sizeof(double)); + + return *this; +} + +message& message::operator<<(bool const boolean) +{ + uint8_t byte = (boolean) ? 1 : 0; + add(reinterpret_cast(&byte), sizeof(uint8_t)); + + return *this; +} + +message& message::operator<<(char const* c_string) +{ + add(reinterpret_cast(c_string), strlen(c_string)); + return *this; +} + +message& message::operator<<(std::string const& string) +{ + add(reinterpret_cast(string.data()), string.size()); + return *this; +} + +void message::push_front(void const* part, size_t const size) +{ + _parts.emplace( _parts.begin(), part, size ); +} + +void message::push_front(int8_t const integer) +{ + push_front(&integer, sizeof(int8_t)); +} + +void message::push_front(int16_t const integer) +{ + uint16_t network_order = htons(static_cast(integer)); + push_front(&network_order, sizeof(uint16_t)); +} + +void message::push_front(int32_t const integer) +{ + uint32_t network_order = htonl(static_cast(integer)); + push_front(&network_order, sizeof(uint32_t)); +} + +void message::push_front(int64_t const integer) +{ + uint64_t network_order = zmqpp::htonll(static_cast(integer)); + push_front(&network_order, sizeof(uint64_t)); +} + + +void message::push_front(uint8_t const unsigned_integer) +{ + push_front(&unsigned_integer, sizeof(uint8_t)); +} + +void message::push_front(uint16_t const unsigned_integer) +{ + uint16_t network_order = htons(unsigned_integer); + push_front(&network_order, sizeof(uint16_t)); +} + +void message::push_front(uint32_t const unsigned_integer) +{ + uint32_t network_order = htonl(unsigned_integer); + push_front(&network_order, sizeof(uint32_t)); +} + +void message::push_front(uint64_t const unsigned_integer) +{ + uint64_t network_order = zmqpp::htonll(unsigned_integer); + push_front(&network_order, sizeof(uint64_t)); +} + +void message::push_front(float const floating_point) +{ + assert(sizeof(float) == 4); + + float network_order = zmqpp::htonf(floating_point); + push_front(&network_order, sizeof(float)); +} + +void message::push_front(double const double_precision) +{ + assert(sizeof(double) == 8); + + double network_order = zmqpp::htond(double_precision); + push_front(&network_order, sizeof(double)); +} + +void message::push_front(bool const boolean) +{ + uint8_t byte = (boolean) ? 1 : 0; + push_front(&byte, sizeof(uint8_t)); +} + +void message::push_front(char const* c_string) +{ + push_front(c_string, strlen(c_string)); +} + +void message::push_front(std::string const& string) +{ + push_front(string.data(), string.size()); +} + +void message::pop_front() +{ + _parts.erase( _parts.begin() ); +} + +void message::pop_back() +{ + _parts.pop_back(); +} + +message::message(message&& source) NOEXCEPT + : _parts() + , _read_cursor(0) +{ + std::swap(_parts, source._parts); +} + +message& message::operator=(message&& source) NOEXCEPT +{ + std::swap(_parts, source._parts); + return *this; +} + +message message::copy() const +{ + message msg; + msg.copy(*this); + return msg; +} + +void message::copy(message const& source) +{ + _parts.resize( source._parts.size() ); + for(size_t i = 0; i < source._parts.size(); ++i) + { + _parts[i] = source._parts[i].copy(); + } + + // we don't need a copy of the releasers as we did data copies of the internal data, + //_releasers = source._releasers; + //_strings = source._strings +} + +// Used for internal tracking +void message::sent(size_t const part) +{ + // sanity check + assert(!_parts[part].is_sent()); + _parts[part].mark_sent(); +} + +// Note that these releasers are not thread safe, the only safety is provided by +// the socket class taking ownership so no updates can happen while zmq does it's thing +// If used in a custom class this has to be dealt with. +void message::release_callback(void* data, void* hint) +{ + callback_releaser* releaser = static_cast(hint); + releaser->func(data); + + delete releaser; +} + +} diff --git a/dep/zmqpp/zmqpp/message.hpp b/dep/zmqpp/zmqpp/message.hpp new file mode 100644 index 00000000000..c232e032ee0 --- /dev/null +++ b/dep/zmqpp/zmqpp/message.hpp @@ -0,0 +1,253 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_MESSAGE_HPP_ +#define ZMQPP_MESSAGE_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include "compatibility.hpp" +#include "frame.hpp" + +namespace zmqpp +{ + +/*! + * \brief a zmq message with optional multipart support + * + * A zmq message is made up of one or more parts which are sent together to + * the target endpoints. zmq guarantees either the whole message or none + * of the message will be delivered. + */ +class message +{ +public: + /*! + * \brief callback to release user allocated data. + * + * The release function will be called on any void* moved part. + * It must be thread safe to the extent that the callback may occur on + * one of the context threads. + * + * The function called will be passed a single variable which is the + * pointer to the memory allocated. + */ + typedef std::function release_function; + + message(); + ~message(); + + template + message(T const &part, Args &&...args) + : message() + { + add(part, std::forward(args)...); + } + + size_t parts() const; + size_t size(size_t const part) const; + std::string get(size_t const part) const; + + void get(int8_t& integer, size_t const part) const; + void get(int16_t& integer, size_t const part) const; + void get(int32_t& integer, size_t const part) const; + void get(int64_t& integer, size_t const part) const; + + void get(uint8_t& unsigned_integer, size_t const part) const; + void get(uint16_t& unsigned_integer, size_t const part) const; + void get(uint32_t& unsigned_integer, size_t const part) const; + void get(uint64_t& unsigned_integer, size_t const part) const; + + void get(float& floating_point, size_t const part) const; + void get(double& double_precision, size_t const part) const; + void get(bool& boolean, size_t const part) const; + + void get(std::string& string, size_t const part) const; + + // Warn: If a pointer type is requested the message (well zmq) still 'owns' + // the data and will release it when the message object is freed. + template + Type get(size_t const part) + { + Type value; + get(value, part); + return value; + } + + template + void extract(T &nextpart, Args &...args) + { + assert(part < parts()); + get(nextpart,part); + extract(args...); + } + + template + void extract(T &nextpart) + { + assert(part < parts()); + get(nextpart,part); + } + + // Raw get data operations, useful with data structures more than anything else + // Warn: The message (well zmq) still 'owns' the data and will release it + // when the message object is freed. + template + void get(Type*& value, size_t const part) const + { + value = static_cast(raw_data(part)); + } + + // Warn: The message (well zmq) still 'owns' the data and will release it + // when the message object is freed. + template + void get(Type** value, size_t const part) const + { + *value = static_cast(raw_data(part)); + } + + // Move operators will take ownership of message parts without copying + void move(void* part, size_t const size, release_function const& release); + + // Raw move data operation, useful with data structures more than anything else + template + void move(Object *part) + { + move(part, sizeof(Object), &deleter_callback); + } + + // Copy operators will take copies of any data + template + void add(Type *part, size_t const size) + { + _parts.push_back( frame( part, size ) ); + } + + + template + void add(Type const& part, Args &&...args) + { + *this << part; + add(std::forward(args)...); + } + + template + void add(Type const part) + { + *this << part; + } + + // Stream reader style + void reset_read_cursor(); + + template + message& operator>>(Type& value) + { + get(value, _read_cursor++); + return *this; + } + + // Stream writer style - these all use copy styles + message& operator<<(int8_t const integer); + message& operator<<(int16_t const integer); + message& operator<<(int32_t const integer); + message& operator<<(int64_t const integer); + + message& operator<<(uint8_t const unsigned_integer); + message& operator<<(uint16_t const unsigned_integer); + message& operator<<(uint32_t const unsigned_integer); + message& operator<<(uint64_t const unsigned_integer); + + message& operator<<(float const floating_point); + message& operator<<(double const double_precision); + message& operator<<(bool const boolean); + + message& operator<<(char const* c_string); + message& operator<<(std::string const& string); + + // Queue manipulation + void push_front(void const* part, size_t const size); + + // TODO: unify conversion of types with the stream operators + void push_front(int8_t const integer); + void push_front(int16_t const integer); + void push_front(int32_t const integer); + void push_front(int64_t const integer); + + void push_front(uint8_t const unsigned_integer); + void push_front(uint16_t const unsigned_integer); + void push_front(uint32_t const unsigned_integer); + void push_front(uint64_t const unsigned_integer); + + void push_front(float const floating_point); + void push_front(double const double_precision); + void push_front(bool const boolean); + + void push_front(char const* c_string); + void push_front(std::string const& string); + + void pop_front(); + + void push_back(void const* part, size_t const size) + { + add( part, size ); + } + + template + void push_back(Type const part) + { + *this << part; + } + + void pop_back(); + + void remove(size_t const part); + + // Move supporting + message(message&& source) NOEXCEPT; + message& operator=(message&& source) NOEXCEPT; + + // Copy support + message copy() const; + void copy(message const& source); + + // Used for internal tracking + void sent(size_t const part); + + // Access to raw zmq details + void const* raw_data(size_t const part = 0) const; + zmq_msg_t& raw_msg(size_t const part = 0); + zmq_msg_t& raw_new_msg(); + zmq_msg_t& raw_new_msg(size_t const reserve_data_size); + +private: + typedef std::vector parts_type; + parts_type _parts; + size_t _read_cursor; + + // Disable implicit copy support, code must request a copy to clone + message(message const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; + message& operator=(message const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; + + static void release_callback(void* data, void* hint); + + template + static void deleter_callback(void* data) + { + delete static_cast(data); + } +}; + +} + +#endif /* ZMQPP_MESSAGE_HPP_ */ diff --git a/dep/zmqpp/zmqpp/poller.cpp b/dep/zmqpp/zmqpp/poller.cpp new file mode 100644 index 00000000000..a6340c9bd61 --- /dev/null +++ b/dep/zmqpp/zmqpp/poller.cpp @@ -0,0 +1,182 @@ +/* + * Created on: 16 Aug 2011 + * Author: Ben Gray (@benjamg) + */ + +#include "exception.hpp" +#include "socket.hpp" +#include "poller.hpp" + +#include + +namespace zmqpp +{ + +const long poller::wait_forever = -1; +const short poller::poll_none = 0; +const short poller::poll_in = ZMQ_POLLIN; +const short poller::poll_out = ZMQ_POLLOUT; +const short poller::poll_error = ZMQ_POLLERR; + +poller::poller() + : _items() + , _index() + , _fdindex() +{ + +} + +poller::~poller() +{ + _items.clear(); + _index.clear(); + _fdindex.clear(); +} + +void poller::add(socket& socket, short const event /* = POLL_IN */) +{ + zmq_pollitem_t item { socket, 0, event, 0 }; + + size_t index = _items.size(); + _items.push_back(item); + _index[socket] = index; +} + +void poller::add(int const descriptor, short const event /* = POLL_IN */) +{ + zmq_pollitem_t item { nullptr, descriptor, event, 0 }; + + size_t index = _items.size(); + _items.push_back(item); + _fdindex[descriptor] = index; +} + +bool poller::has(socket_t const& socket) +{ + return _index.find(socket) != _index.end(); +} + +bool poller::has(int const descriptor) +{ + return _fdindex.find(descriptor) != _fdindex.end(); +} + +void poller::reindex(size_t const index) +{ + if ( nullptr != _items[index].socket ) + { + auto found = _index.find( _items[index].socket ); + if (_index.end() == found) { throw exception("unable to reindex socket in poller"); } + found->second = index; + } + else + { + auto found = _fdindex.find( _items[index].fd ); + if (_fdindex.end() == found) { throw exception("unable to reindex file descriptor in poller"); } + found->second = index; + } +} + +void poller::remove(socket_t const& socket) +{ + auto found = _index.find(socket); + if (_index.end() == found) { return; } + + if ( _items.size() - 1 == found->second ) + { + _items.pop_back(); + _index.erase(found); + return; + } + + std::swap(_items[found->second], _items.back()); + _items.pop_back(); + + auto index = found->second; + _index.erase(found); + + reindex( index ); +} + +void poller::remove(int const descriptor) +{ + auto found = _fdindex.find(descriptor); + if (_fdindex.end() == found) { return; } + + if ( _items.size() - 1 == found->second ) + { + _items.pop_back(); + _fdindex.erase(found); + return; + } + + std::swap(_items[found->second], _items.back()); + _items.pop_back(); + + auto index = found->second; + _fdindex.erase(found); + + reindex( index ); +} + +void poller::check_for(socket const& socket, short const event) +{ + auto found = _index.find(socket); + if (_index.end() == found) + { + throw exception("this socket is not represented within this poller"); + } + + _items[found->second].events = event; +} + +void poller::check_for(int const descriptor, short const event) +{ + auto found = _fdindex.find(descriptor); + if (_fdindex.end() == found) + { + throw exception("this socket is not represented within this poller"); + } + + _items[found->second].events = event; +} + +bool poller::poll(long timeout /* = WAIT_FOREVER */) +{ + int result = zmq_poll(_items.data(), _items.size(), timeout); + if (result < 0) + { + if(EINTR == zmq_errno()) + { + return false; + } + + throw zmq_internal_exception(); + } + + return (result > 0); +} + +short poller::events(socket const& socket) const +{ + auto found = _index.find(socket); + if (_index.end() == found) + { + throw exception("this socket is not represented within this poller"); + } + + return _items[found->second].revents; +} + +short poller::events(int const descriptor) const +{ + auto found = _fdindex.find(descriptor); + if (_fdindex.end() == found) + { + throw exception("this file descriptor is not represented within this poller"); + } + + return _items[found->second].revents; +} + +} diff --git a/dep/zmqpp/zmqpp/poller.hpp b/dep/zmqpp/zmqpp/poller.hpp new file mode 100644 index 00000000000..a19063a091d --- /dev/null +++ b/dep/zmqpp/zmqpp/poller.hpp @@ -0,0 +1,186 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_POLLER_HPP_ +#define ZMQPP_POLLER_HPP_ + +#include +#include + +#include "compatibility.hpp" + +namespace zmqpp +{ + +class socket; +typedef socket socket_t; + +/*! + * Polling wrapper. + * + * Allows access to polling for any number of sockets or file descriptors. + */ +class poller +{ +public: + static const long wait_forever; /*!< Block forever flag, default setting. */ + + static const short poll_none; /*!< No polling flags set. */ + static const short poll_in; /*!< Monitor inbound flag. */ + static const short poll_out; /*!< Monitor output flag. */ + static const short poll_error; /*!< Monitor error flag.\n Only for file descriptors. */ + + /*! + * Construct an empty polling model. + */ + poller(); + + /*! + * Cleanup poller. + * + * Any sockets will need to be closed separately. + */ + ~poller(); + + /*! + * Add a socket to the polling model and set which events to monitor. + * + * \param socket the socket to monitor. + * \param event the event flags to monitor on the socket. + */ + void add(socket_t& socket, short const event = poll_in); + + /*! + * Add a file descriptor to the polling model and set which events to monitor. + * + * \param descriptor the file descriptor to monitor. + * \param event the event flags to monitor. + */ + void add(int const descriptor, short const event = poll_in | poll_error); + + /*! + * Check if we are monitoring a given socket with this poller. + * + * \param socket the socket to check. + * \return true if it is there. + */ + bool has(socket_t const& socket); + + /*! + * Check if we are monitoring a given file descriptor with this poller. + * + * \param descriptor the file descriptor to check. + * \return true if it is there. + */ + bool has(int const descriptor); + + /*! + * Stop monitoring a socket. + * + * \param socket the socket to stop monitoring. + */ + void remove(socket_t const& socket); + + /*! + * Stop monitoring a file descriptor. + * + * \param descriptor the file descriptor to stop monitoring. + */ + void remove(int const descriptor); + + /*! + * Update the monitored event flags for a given socket. + * + * \param socket the socket to update event flags. + * \param event the event flags to monitor on the socket. + */ + void check_for(socket_t const& socket, short const event); + + /*! + * Update the monitored event flags for a given file descriptor. + * + * \param descriptor the file descriptor to update event flags. + * \param event the event flags to monitor on the socket. + */ + void check_for(int const descriptor, short const event); + + /*! + * Poll for monitored events. + * + * By default this method will block forever or until at least one of the monitored + * sockets or file descriptors has events. + * + * If a timeout is set and was reached then this function returns false. + * + * \param timeout milliseconds to timeout. + * \return true if there is an event.. + */ + bool poll(long timeout = wait_forever); + + /*! + * Get the event flags triggered for a socket. + * + * \param socket the socket to get triggered event flags for. + * \return the event flags. + */ + short events(socket_t const& socket) const; + + /*! + * Get the event flags triggered for a file descriptor. + * + * \param descriptor the file descriptor to get triggered event flags for. + * \return the event flags. + */ + short events(int const descriptor) const; + + /*! + * Check either a file descriptor or socket for input events. + * + * Templated helper method that calls through to event and checks for a given flag + * + * \param watchable either a file descriptor or socket known to the poller. + * \return true if there is input. + */ + template + bool has_input(Watched const& watchable) const { return events(watchable) & poll_in; } + + /*! + * Check either a file descriptor or socket for output events. + * + * Templated helper method that calls through to event and checks for a given flag + * + * \param watchable either a file descriptor or socket known to the poller. + * \return true if there is output. + */ + template + bool has_output(Watched const& watchable) const { return events(watchable) & poll_out; } + + /*! + * Check a file descriptor. + * + * Templated helper method that calls through to event and checks for a given flag + * + * Technically this template works for sockets as well but the error flag is never set for + * sockets so I have no idea why someone would call it. + * + * \param watchable a file descriptor know to the poller. + * \return true if there is an error. + */ + template + bool has_error(Watched const& watchable) const { return events(watchable) & poll_error; } + +private: + std::vector _items; + std::unordered_map _index; + std::unordered_map _fdindex; + + void reindex(size_t const index); +}; + +} + +#endif /* ZMQPP_POLLER_HPP_ */ diff --git a/dep/zmqpp/zmqpp/socket.cpp b/dep/zmqpp/zmqpp/socket.cpp new file mode 100644 index 00000000000..0c6a795966c --- /dev/null +++ b/dep/zmqpp/zmqpp/socket.cpp @@ -0,0 +1,758 @@ +/* + * Created on: 9 Aug 2011 + * Author: Ben Gray (@benjamg) + */ + +#include +#include +#include +#include + +#include "context.hpp" +#include "exception.hpp" +#include "message.hpp" +#include "socket.hpp" + +namespace zmqpp +{ + +const int socket::normal = 0; +#if (ZMQ_VERSION_MAJOR == 2) +const int socket::dont_wait = ZMQ_NOBLOCK; +#else +const int socket::dont_wait = ZMQ_DONTWAIT; +#endif +const int socket::send_more = ZMQ_SNDMORE; +#ifdef ZMQ_EXPERIMENTAL_LABELS +const int socket::send_label = ZMQ_SNDLABEL; +#endif + +const int max_socket_option_buffer_size = 256; +const int max_stream_buffer_size = 4096; + +socket::socket(const context& context, socket_type const type) + : _socket(nullptr) + , _type(type) + , _recv_buffer() +{ + _socket = zmq_socket(context, static_cast(type)); + if(nullptr == _socket) + { + throw zmq_internal_exception(); + } + + zmq_msg_init(&_recv_buffer); +} + +socket::~socket() +{ + zmq_msg_close(&_recv_buffer); + + if (nullptr != _socket) + { + +#ifndef NDEBUG // unused assert variable in release + int result = zmq_close(_socket); + assert(0 == result); +#else + zmq_close(_socket); +#endif // NDEBUG + + _socket = nullptr; + } +} + +void socket::bind(endpoint_t const& endpoint) +{ + int result = zmq_bind(_socket, endpoint.c_str()); + + if (0 != result) + { + throw zmq_internal_exception(); + } +} + +void socket::unbind(endpoint_t const& endpoint) +{ + int result = zmq_unbind(_socket, endpoint.c_str()); + + if (0 != result) + { + throw zmq_internal_exception(); + } +} + +void socket::connect(endpoint_t const& endpoint) +{ + int result = zmq_connect(_socket, endpoint.c_str()); + + if (0 != result) + { + throw zmq_internal_exception(); + } +} + +void socket::disconnect(endpoint_t const& endpoint) +{ + int result = zmq_disconnect(_socket, endpoint.c_str()); + + if (0 != result) + { + throw zmq_internal_exception(); + } +} + +void socket::close() +{ + int result = zmq_close(_socket); + + if (0 != result) + { + throw zmq_internal_exception(); + } + + _socket = nullptr; +} + +bool socket::send(message& message, bool const dont_block /* = false */) +{ + size_t parts = message.parts(); + if (parts == 0) + { + throw std::invalid_argument("sending requires messages have at least one part"); + } + + bool dont_wait = dont_block; + for(size_t i = 0; i < parts; ++i) + { + int flag = socket::normal; + if(dont_wait) { flag |= socket::dont_wait; } + if(i < (parts - 1)) { flag |= socket::send_more; } + +#if (ZMQ_VERSION_MAJOR == 2) + int result = zmq_send( _socket, &message.raw_msg(i), flag ); +#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + int result = zmq_sendmsg( _socket, &message.raw_msg(i), flag ); +#else + int result = zmq_msg_send( &message.raw_msg(i), _socket, flag ); +#endif + + if (result < 0) + { + // the zmq framework should not block if the first part is accepted + // so we should only ever get this error on the first part + if((0 == i) && (EAGAIN == zmq_errno())) + { + return false; + } + + if(EINTR == zmq_errno()) + { + if (0 == message.parts()) + { + return false; + } + + // If we have an interrupt but it's not on the first part then we + // know we can safely send out the rest of the message as we can + // enforce that it won't wait on a blocking action + dont_wait = true; + continue; + } + + // sanity checking + assert(EAGAIN != zmq_errno()); + + throw zmq_internal_exception(); + } + + message.sent(i); + } + + // Leave message reference in a stable state + zmqpp::message local; + std::swap(local, message); + return true; +} + +bool socket::receive(message& message, bool const dont_block /* = false */) +{ + if (message.parts() > 0) + { + // swap and discard old message + zmqpp::message local; + std::swap(local, message); + } + + int flags = (dont_block) ? socket::dont_wait : socket::normal; + bool more = true; + + while(more) + { +#if (ZMQ_VERSION_MAJOR == 2) + int result = zmq_recv( _socket, &_recv_buffer, flags ); +#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + int result = zmq_recvmsg( _socket, &_recv_buffer, flags ); +#else + int result = zmq_msg_recv( &_recv_buffer, _socket, flags ); +#endif + + if(result < 0) + { + if ((0 == message.parts()) && (EAGAIN == zmq_errno())) + { + return false; + } + + if(EINTR == zmq_errno()) + { + if (0 == message.parts()) + { + return false; + } + + // If we have an interrupt but it's not on the first part then we + // know we can safely pull out the rest of the message as it will + // not be blocking + continue; + } + + assert(EAGAIN != zmq_errno()); + + throw zmq_internal_exception(); + } + + zmq_msg_t& dest = message.raw_new_msg(); + zmq_msg_move(&dest, &_recv_buffer); + + get(socket_option::receive_more, more); + } + + return true; +} + + +bool socket::send(std::string const& string, int const flags /* = NORMAL */) +{ + return send_raw(string.data(), string.size(), flags); +} + +bool socket::receive(std::string& string, int const flags /* = NORMAL */) +{ +#if (ZMQ_VERSION_MAJOR == 2) + int result = zmq_recv( _socket, &_recv_buffer, flags ); +#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + int result = zmq_recvmsg( _socket, &_recv_buffer, flags ); +#else + int result = zmq_msg_recv( &_recv_buffer, _socket, flags ); +#endif + + if(result >= 0) + { + string.reserve(zmq_msg_size(&_recv_buffer)); + string.assign(static_cast(zmq_msg_data(&_recv_buffer)), zmq_msg_size(&_recv_buffer)); + + return true; + } + + if (EAGAIN == zmq_errno() || EINTR == zmq_errno()) + { + return false; + } + + throw zmq_internal_exception(); +} + + +bool socket::send_raw(char const* buffer, int const length, int const flags /* = NORMAL */) +{ +#if (ZMQ_VERSION_MAJOR == 2) + zmq_msg_t msg; + int result = zmq_msg_init_size(&msg, length); + if (result != 0) + { + zmq_internal_exception(); + } + + memcpy(zmq_msg_data(&msg), buffer, length); + result = zmq_send(_socket, &msg, flags); +#else + int result = zmq_send(_socket, buffer, length, flags); +#endif + if(result >= 0) + { + return true; + } + +#if (ZMQ_VERSION_MAJOR == 2) + // only actually need to close this on error + zmq_msg_close(&msg); +#endif + + if (EAGAIN == zmq_errno() || EINTR == zmq_errno()) + { + return false; + } + + throw zmq_internal_exception(); +} + +bool socket::receive_raw(char* buffer, int& length, int const flags /* = NORMAL */) +{ +#if (ZMQ_VERSION_MAJOR == 2) + int result = zmq_recv( _socket, &_recv_buffer, flags ); +#elif (ZMQ_VERSION_MAJOR < 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR < 2)) + int result = zmq_recvmsg( _socket, &_recv_buffer, flags ); +#else + int result = zmq_msg_recv( &_recv_buffer, _socket, flags ); +#endif + + if(result >= 0) + { + length = zmq_msg_size(&_recv_buffer); + memcpy(buffer, zmq_msg_data(&_recv_buffer), length); + + return true; + } + + if (EAGAIN == zmq_errno() || EINTR == zmq_errno()) + { + return false; + } + + throw zmq_internal_exception(); +} + + +// Helper +void socket::subscribe(std::string const& topic) +{ + set(socket_option::subscribe, topic); +} + +void socket::unsubscribe(std::string const& topic) +{ + set(socket_option::unsubscribe, topic); +} + +bool socket::has_more_parts() const +{ + return get(socket_option::receive_more); +} + + +// Set socket options for different types of option +void socket::set(socket_option const option, int const value) +{ + switch(option) + { + // unsigned 64bit Integers +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::high_water_mark: + case socket_option::send_buffer_size: + case socket_option::receive_buffer_size: +#endif + case socket_option::affinity: + if (value < 0) { throw exception("attempting to set an unsigned 64 bit integer option with a negative integer"); } + set(option, static_cast(value)); + break; + + // 64bit Integers +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::rate: + case socket_option::recovery_interval: + case socket_option::recovery_interval_seconds: + case socket_option::swap_size: +#else + case socket_option::max_messsage_size: +#endif + set(option, static_cast(value)); + break; + + // Boolean +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1)) + case socket_option::ipv4_only: +#endif +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::multicast_loopback: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#if (ZMQ_VERSION_MINOR == 2) + case socket_option::delay_attach_on_connect: +#else + case socket_option::immediate: +#endif + case socket_option::router_mandatory: + case socket_option::xpub_verbose: +#endif + if (value == 0) { set(option, false); } + else if (value == 1) { set(option, true); } + else { throw exception("attempting to set a boolean option with a non 0 or 1 integer"); } + break; + + // Default or Boolean +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) + case socket_option::tcp_keepalive: + if (value < -1 || value > 1) { throw exception("attempting to set a default or boolean option with a non -1, 0 or 1 integer"); } + if (0 != zmq_setsockopt(_socket, static_cast(option), &value, sizeof(value))) + { + throw zmq_internal_exception(); + } + break; +#endif + + // Integers that require +ve numbers +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::reconnect_interval_max: +#else + case socket_option::reconnect_interval_max: + case socket_option::send_buffer_size: + case socket_option::recovery_interval: + case socket_option::receive_buffer_size: + case socket_option::send_high_water_mark: + case socket_option::receive_high_water_mark: + case socket_option::multicast_hops: + case socket_option::rate: +#endif + case socket_option::backlog: + if (value < 0) { throw exception("attempting to set a positive only integer option with a negative integer"); } + // Integers + case socket_option::reconnect_interval: + case socket_option::linger: + case socket_option::receive_timeout: + case socket_option::send_timeout: +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) + case socket_option::tcp_keepalive_idle: + case socket_option::tcp_keepalive_count: + case socket_option::tcp_keepalive_interval: +#endif + if (0 != zmq_setsockopt(_socket, static_cast(option), &value, sizeof(value))) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to set a non signed integer option with a signed integer value"); + } +} + +void socket::set(socket_option const option, bool const value) +{ + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::multicast_loopback: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1)) + case socket_option::ipv4_only: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#if (ZMQ_VERSION_MINOR == 2) + case socket_option::delay_attach_on_connect: +#else + case socket_option::immediate: +#endif + case socket_option::router_mandatory: + case socket_option::xpub_verbose: +#endif + { + int ivalue = value ? 1 : 0; + if (0 != zmq_setsockopt(_socket, static_cast(option), &ivalue, sizeof(ivalue))) + { + throw zmq_internal_exception(); + } + break; + } + default: + throw exception("attempting to set a non boolean option with a boolean value"); + } +} + +void socket::set(socket_option const option, uint64_t const value) +{ + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + // unsigned 64bit Integers + case socket_option::high_water_mark: + case socket_option::send_buffer_size: + case socket_option::receive_buffer_size: +#endif + case socket_option::affinity: + if (0 != zmq_setsockopt(_socket, static_cast(option), &value, sizeof(value))) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to set a non unsigned 64 bit integer option with a unsigned 64 bit integer value"); + } +} + +void socket::set(socket_option const option, int64_t const value) +{ + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::rate: + case socket_option::recovery_interval: + case socket_option::recovery_interval_seconds: + case socket_option::swap_size: +#else + case socket_option::max_messsage_size: +#endif + // zmq only allowed +ve int64_t options + if (value < 0) { throw exception("attempting to set a positive only 64 bit integer option with a negative 64bit integer"); } + if (0 != zmq_setsockopt(_socket, static_cast(option), &value, sizeof(value))) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to set a non 64 bit integer option with a 64 bit integer value"); + } +} + +void socket::set(socket_option const option, char const* value, size_t const length) +{ + switch(option) + { + case socket_option::identity: + case socket_option::subscribe: + case socket_option::unsubscribe: +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) + case socket_option::tcp_accept_filter: +#endif + if (0 != zmq_setsockopt(_socket, static_cast(option), value, length)) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to set a non string option with a string value"); + } +} + +// Get socket options, multiple versions for easy of use +void socket::get(socket_option const option, int& value) const +{ + size_t value_size = sizeof(int); + + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::receive_more: + case socket_option::multicast_loopback: + value = static_cast(get(option)); + break; +#endif + case socket_option::type: + case socket_option::linger: + case socket_option::backlog: + case socket_option::reconnect_interval: + case socket_option::reconnect_interval_max: + case socket_option::receive_timeout: + case socket_option::send_timeout: + case socket_option::file_descriptor: + case socket_option::events: +#if (ZMQ_VERSION_MAJOR > 2) + case socket_option::receive_more: + case socket_option::send_buffer_size: + case socket_option::receive_buffer_size: + case socket_option::rate: + case socket_option::recovery_interval: + case socket_option::send_high_water_mark: + case socket_option::receive_high_water_mark: + case socket_option::multicast_hops: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1)) + case socket_option::ipv4_only: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#if (ZMQ_VERSION_MINOR == 2) + case socket_option::delay_attach_on_connect: +#else + case socket_option::immediate: +#endif + case socket_option::tcp_keepalive: + case socket_option::tcp_keepalive_idle: + case socket_option::tcp_keepalive_count: + case socket_option::tcp_keepalive_interval: +#endif +#ifdef ZMQ_EXPERIMENTAL_LABELS + case socket_option::receive_label: +#endif + if (0 != zmq_getsockopt(_socket, static_cast(option), &value, &value_size)) + { + throw zmq_internal_exception(); + } + + // sanity check + assert(value_size <= sizeof(int)); + break; + default: + throw exception("attempting to get a non integer option with an integer value"); + } +} + +void socket::get(socket_option const option, bool& value) const +{ +#if (ZMQ_VERSION_MAJOR == 2) + int64_t int_value = 0; + size_t value_size = sizeof(int64_t); +#else + int int_value = 0; + size_t value_size = sizeof(int); +#endif + + switch(option) + { + case socket_option::receive_more: +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::multicast_loopback: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1)) + case socket_option::ipv4_only: +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#if (ZMQ_VERSION_MINOR == 2) + case socket_option::delay_attach_on_connect: +#else + case socket_option::immediate: +#endif +#endif +#ifdef ZMQ_EXPERIMENTAL_LABELS + case socket_option::receive_label: +#endif + if (0 != zmq_getsockopt(_socket, static_cast(option), &int_value, &value_size)) + { + throw zmq_internal_exception(); + } + + value = (int_value == 1) ? true : false; + break; + default: + throw exception("attempting to get a non boolean option with a boolean value"); + } +} + +void socket::get(socket_option const option, uint64_t& value) const +{ + size_t value_size = sizeof(uint64_t); + + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::high_water_mark: + case socket_option::send_buffer_size: + case socket_option::receive_buffer_size: +#endif + case socket_option::affinity: + if(0 != zmq_getsockopt(_socket, static_cast(option), &value, &value_size)) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to get a non unsigned 64 bit integer option with an unsigned 64 bit integer value"); + } +} + +void socket::get(socket_option const option, int64_t& value) const +{ + size_t value_size = sizeof(int64_t); + + switch(option) + { +#if (ZMQ_VERSION_MAJOR == 2) + case socket_option::rate: + case socket_option::recovery_interval: + case socket_option::recovery_interval_seconds: + case socket_option::swap_size: + case socket_option::receive_more: + case socket_option::multicast_loopback: +#else + case socket_option::max_messsage_size: +#endif + if(0 != zmq_getsockopt(_socket, static_cast(option), &value, &value_size)) + { + throw zmq_internal_exception(); + } + break; + default: + throw exception("attempting to get a non 64 bit integer option with an 64 bit integer value"); + } +} + +void socket::get(socket_option const option, std::string& value) const +{ + static std::array buffer; + size_t size = max_socket_option_buffer_size; + + switch(option) + { + case socket_option::identity: +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) + case socket_option::last_endpoint: +#endif + if(0 != zmq_getsockopt(_socket, static_cast(option), buffer.data(), &size)) + { + throw zmq_internal_exception(); + } + + value.assign(buffer.data(), size); + break; + default: + throw exception("attempting to get a non string option with a string value"); + } +} + +socket::socket(socket&& source) NOEXCEPT + : _socket(source._socket) + , _type(source._type) + , _recv_buffer() +{ + // we steal the zmq_msg_t from the valid socket, we only init our own because it's cheap + // and zmq_msg_move does a valid check + zmq_msg_init(&_recv_buffer); + zmq_msg_move(&_recv_buffer, &source._recv_buffer); + + // Clean up source a little, we will handle the deinit, it doesn't need to + source._socket = nullptr; +} + +socket& socket::operator=(socket&& source) NOEXCEPT +{ + std::swap(_socket, source._socket); + + _type = source._type; // just clone? + + // we steal the zmq_msg_t from the valid socket, we only init our own because it's cheap + // and zmq_msg_move does a valid check + zmq_msg_init(&_recv_buffer); + zmq_msg_move(&_recv_buffer, &source._recv_buffer); + + return *this; +} + + +socket::operator bool() const +{ + return nullptr != _socket; +} + + +socket::operator void*() const +{ + return _socket; +} + +void socket::track_message(message const& /* message */, uint32_t const parts, bool& should_delete) +{ + if (parts == 0) + { + should_delete = true; + } +} + +} diff --git a/dep/zmqpp/zmqpp/socket.hpp b/dep/zmqpp/zmqpp/socket.hpp new file mode 100644 index 00000000000..279bf801f77 --- /dev/null +++ b/dep/zmqpp/zmqpp/socket.hpp @@ -0,0 +1,500 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_SOCKET_HPP_ +#define ZMQPP_SOCKET_HPP_ + +#include +#include +#include + +#include + +#include "compatibility.hpp" + +#include "socket_types.hpp" +#include "socket_options.hpp" + +namespace zmqpp +{ + +class context; +class message; + +typedef std::string endpoint_t; +typedef context context_t; +typedef message message_t; + +/*! + * The socket class represents the zmq sockets. + * + * A socket can be bound and/or connected to as many endpoints as required + * with the sole exception of a ::pair socket. + * + * The routing is handled by zmq based on the type set. + * + * The bound side of an inproc connection must occur first and inproc can only + * connect to other inproc sockets of the same context. + * + * This class is c++0x move supporting and cannot be copied. + */ +class socket +{ +public: + static const int normal; /*!< /brief default send type, no flags set */ +#if (ZMQ_VERSION_MAJOR == 2) + static const int dont_wait; /*!< /brief don't block if sending is not currently possible */ +#else + static const int dont_wait; /*!< /brief don't block if sending is not currently possible */ +#endif + static const int send_more; /*!< /brief more parts will follow this one */ +#ifdef ZMQ_EXPERIMENTAL_LABELS + static const int send_label; /*!< /brief this message part is an internal zmq label */ +#endif + + /*! + * Create a socket for a given type. + * + * \param context the zmq context under which the socket will live + * \param type a valid ::socket_type for the socket + */ + socket(context_t const& context, socket_type const type); + + /*! + * This will close any socket still open before returning + */ + ~socket(); + + /*! + * Get the type of the socket, this works on zmqpp types and not the zmq internal types. + * Use the socket::get method if you wish to intergoate the zmq internal ones. + * + * \return the type of the socket + */ + socket_type type() const { return _type; } + + /*! + * Asynchronously binds to an endpoint. + * + * \param endpoint the zmq endpoint to bind to + */ + void bind(endpoint_t const& endpoint); + + /*! + * Unbinds from a previously bound endpoint. + * + * \param endpoint the zmq endpoint to bind to + */ + void unbind(endpoint_t const& endpoint); + + /*! + * Asynchronously connects to an endpoint. + * If the endpoint is not inproc then zmq will happily keep trying + * to connect until there is something there. + * + * Inproc sockets must have a valid target already bound before connection + * will work. + * + * \param endpoint the zmq endpoint to connect to + */ + void connect(endpoint_t const& endpoint); + + /*! + * Asynchronously connects to multiple endpoints. + * If the endpoint is not inproc then zmq will happily keep trying + * to connect until there is something there. + * + * Inproc sockets must have a valid target already bound before connection + * will work. + * + * This is a helper function that wraps the single item connect in a loop + * + * \param connections_begin the starting iterator for zmq endpoints. + * \param connections_end the final iterator for zmq endpoints. + */ + template + void connect(InputIterator const& connections_begin, InputIterator const& connections_end) + { + for(InputIterator it = connections_begin; it != connections_end; ++it) + { + connect(*it); + } + } + + + /*! + * Disconnects a previously connected endpoint. + * + * \param endpoint the zmq endpoint to disconnect from + */ + void disconnect(endpoint_t const& endpoint); + + /*! + * Disconnects from multiple previously connected endpoints. + * + * This is a helper function that wraps the single item disconnect in a loop + * + * \param disconnections_begin the starting iterator for zmq endpoints. + * \param disconnections_end the final iterator for zmq endpoints. + */ + template + void disconnect(InputIterator const& disconnections_begin, InputIterator const& disconnections_end) + { + for(InputIterator it = disconnections_begin; it != disconnections_end; ++it) + { + disconnect(*it); + } + } + + /*! + * Closes the internal zmq socket and marks this instance + * as invalid. + */ + void close(); + + /*! + * Sends the message over the connection, this may be a multipart message. + * + * If dont_block is true and we are unable to add a new message then this + * function will return false. + * + * \param message message to send + * \param dont_block boolean to dictate if we wait while sending. + * \return true if message sent, false if it would have blocked + */ + bool send(message_t& message, bool const dont_block = false); + + /*! + * Gets a message from the connection, this may be a multipart message. + * + * If dont_block is true and we are unable to get a message then this + * function will return false. + * + * \param message reference to fill with received data + * \param dont_block boolean to dictate if we wait for data. + * \return true if message sent, false if it would have blocked + */ + bool receive(message_t& message, bool const dont_block = false); + + /*! + * Sends the byte data held by the string as the next message part. + * + * If the socket::DONT_WAIT flag and we are unable to add a new message to + * socket then this function will return false. + * + * \param string message part to send + * \param flags message send flags + * \return true if message part sent, false if it would have blocked + */ + bool send(std::string const& string, int const flags = normal); + + /*! + * If there is a message ready then get the next part as a string + * + * If the socket::DONT_WAIT flag and there is no message ready to receive + * then this function will return false. + * + * \param string message part to receive into + * \param flags message receive flags + * \return true if message part received, false if it would have blocked + */ + bool receive(std::string& string, int const flags = normal); + + /*! + * Sends the byte data pointed to by buffer as the next part of the message. + * + * If the socket::DONT_WAIT flag and we are unable to add a new message to + * socket then this function will return false. + * + * \param buffer byte buffer pointer to start writing from + * \param length max length of the buffer + * \param flags message send flags + * \return true if message part sent, false if it would have blocked + */ + bool send_raw(char const* buffer, int const length, int const flags = normal); + + /*! + * \warning If the buffer is not large enough for the message part then the + * data will be truncated. The rest of the part is lost forever. + * + * If there is a message ready then get the next part of it as a raw + * byte buffer. + * + * If the socket::DONT_WAIT flag and there is no message ready to receive + * then this function will return false. + * + * \param buffer byte buffer pointer to start writing to + * \param length max length of the buffer + * \param flags message receive flags + * \return true if message part received, false if it would have blocked + */ + bool receive_raw(char* buffer, int& length, int const flags = normal); + + /*! + * + * Subscribe to a topic + * + * Helper function that is equivalent of calling + * \code + * set(zmqpp::socket_option::subscribe, topic); + * \endcode + * + * This method is only useful for subscribe type sockets. + * + * \param topic the topic to subscribe to. + */ + void subscribe(std::string const& topic); + + /*! + * Subscribe to a topic + * + * Helper function that is equivalent of a loop calling + * \code + * set(zmqpp::socket_option::subscribe, topic); + * \endcode + * + * This method is only useful for subscribe type sockets. + * + * Generally this will be used with stl collections using begin() and + * end() functions to get the iterators. + * For this reason the end loop runs until the end iterator, not inclusive + * of it. + * + * \param topics_begin the starting iterator for topics. + * \param topics_end the final iterator for topics. + */ + template + void subscribe(InputIterator const& topics_begin, InputIterator const& topics_end) + { + for(InputIterator it = topics_begin; it != topics_end; ++it) + { + subscribe(*it); + } + } + + /*! + * Unsubscribe from a topic + * + * Helper function that is equivalent of calling + * \code + * set(zmqpp::socket_option::unsubscribe, topic); + * \endcode + * + * This method is only useful for subscribe type sockets. + * + * \param topic the topic to unsubscribe from. + */ + void unsubscribe(std::string const& topic); + + /*! + * Unsubscribe from a topic + * + * Helper function that is equivalent of a loop calling + * \code + * set(zmqpp::socket_option::unsubscribe, topic); + * \endcode + * + * This method is only useful for subscribe type sockets. + * + * Generally this will be used with stl collections using begin() and + * end() functions to get the iterators. + * For this reason the end loop runs until the end iterator, not inclusive + * of it. + * + * \param topics_begin the starting iterator for topics. + * \param topics_end the final iterator for topics. + */ + template + void unsubscribe(InputIterator const& topics_begin, InputIterator const& topics_end) + { + for(InputIterator it = topics_begin; it != topics_end; ++it) + { + unsubscribe(*it); + } + } + + /*! + * If the last receive part call to the socket resulted + * in a label or a non-terminating part of a multipart + * message this will return true. + * + * \return true if there are more parts + */ + bool has_more_parts() const; + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value to set the option to + */ + void set(socket_option const option, int const value); + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \since 2.0.0 (built against 0mq version 3.1.x or later) + * + * \param option a valid ::socket_option + * \param value to set the option to + */ + void set(socket_option const option, bool const value); + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value to set the option to + */ + void set(socket_option const option, uint64_t const value); + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value to set the option to + */ + void set(socket_option const option, int64_t const value); + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param pointer to raw byte value to set the option to + * \param length the size of the raw byte value + */ + void set(socket_option const option, char const* value, size_t const length); + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param pointer to null terminated cstring value to set the option to + */ + inline void set(socket_option const option, char const* value) { set(option, value, strlen(value)); } + + /*! + * Set the value of an option in the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value to set the option to + */ + inline void set(socket_option const option, std::string const value) { set(option, value.c_str(), value.length()); } + + /*! + * Get a socket option from the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value referenced int to return value in + */ + void get(socket_option const option, int& value) const; + + /*! + * Get a socket option from the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value referenced bool to return value in + */ + void get(socket_option const option, bool& value) const; + + /*! + * Get a socket option from the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value referenced uint64_t to return value in + */ + void get(socket_option const option, uint64_t& value) const; + + /*! + * Get a socket option from the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value referenced uint64_t to return value in + */ + void get(socket_option const option, int64_t& value) const; + + /*! + * Get a socket option from the underlaying zmq socket. + * + * \param option a valid ::socket_option + * \param value referenced std::string to return value in + */ + void get(socket_option const option, std::string& value) const; + + /*! + * For those that don't want to get into a referenced value this templated method + * will return the value instead. + * + * \param option a valid ::socket_option + * \return socket option value + */ + template + Type get(socket_option const option) const + { + Type value = Type(); + get(option, value); + return value; + } + + /*! + * Move constructor + * + * Moves the internals of source to this object, there is no guarantee + * that source will be left in a valid state. + * + * This constructor is noexcept and so will not throw exceptions + * + * \param source target socket to steal internals from + */ + socket(socket&& source) NOEXCEPT; + + /*! + * Move operator + * + * Moves the internals of source to this object, there is no guarantee + * that source will be left in a valid state. + * + * This function is noexcept and so will not throw exceptions + * + * \param source target socket to steal internals from + * \return socket reference to this + */ + socket& operator=(socket&& source) NOEXCEPT; + + /*! + * Check the socket is still valid + * + * This tests the internal state of the socket. + * If creation failed for some reason or if the move functions were used + * to move the socket internals to another instance this will return false. + * + * \return true if the socket is valid + */ + operator bool() const; + + /*! + * Access to the raw 0mq context + * + * \return void pointer to the underlying 0mq socket + */ + operator void*() const; + +private: + void* _socket; + socket_type _type; + zmq_msg_t _recv_buffer; + + // No copy + socket(socket const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; + socket& operator=(socket const&) NOEXCEPT ZMQPP_EXPLICITLY_DELETED; + + void track_message(message_t const&, uint32_t const, bool&); +}; + +} + +#endif /* ZMQPP_SOCKET_HPP_ */ diff --git a/dep/zmqpp/zmqpp/socket_options.hpp b/dep/zmqpp/zmqpp/socket_options.hpp new file mode 100644 index 00000000000..c5c8586cbc7 --- /dev/null +++ b/dep/zmqpp/zmqpp/socket_options.hpp @@ -0,0 +1,80 @@ +/** + * \file + * + * \date 23 Sep 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_SOCKET_OPTIONS_HPP_ +#define ZMQPP_SOCKET_OPTIONS_HPP_ + +namespace zmqpp +{ + +/** \todo Expand the information on the options to make it actually useful. */ +/*! + * \brief possible Socket options in zmq + */ + +enum class socket_option { + affinity = ZMQ_AFFINITY, /*!< I/O thread affinity */ + identity = ZMQ_IDENTITY, /*!< Socket identity */ + subscribe = ZMQ_SUBSCRIBE, /*!< Add topic subscription - set only */ + unsubscribe = ZMQ_UNSUBSCRIBE, /*!< Remove topic subscription - set only */ + rate = ZMQ_RATE, /*!< Multicast data rate */ + send_buffer_size = ZMQ_SNDBUF, /*!< Kernel transmission buffer size */ + receive_buffer_size = ZMQ_RCVBUF, /*!< Kernel receive buffer size */ + receive_more = ZMQ_RCVMORE, /*!< Can receive more parts - get only */ + file_descriptor = ZMQ_FD, /*!< Socket file descriptor - get only */ + events = ZMQ_EVENTS, /*!< Socket event flags - get only */ + type = ZMQ_TYPE, /*!< Socket type - get only */ + linger = ZMQ_LINGER, /*!< Socket linger timeout */ + backlog = ZMQ_BACKLOG, /*!< Maximum length of outstanding connections - get only */ +#if (ZMQ_VERSION_MAJOR == 2) + // Note that this is inverse of the zmq names for version 2.x + recovery_interval_seconds = ZMQ_RECOVERY_IVL, /*!< Multicast recovery interval in seconds */ + recovery_interval = ZMQ_RECOVERY_IVL_MSEC, /*!< Multicast recovery interval in milliseconds */ +#else + recovery_interval = ZMQ_RECOVERY_IVL, /*!< Multicast recovery interval in milliseconds */ +#endif + reconnect_interval = ZMQ_RECONNECT_IVL, /*!< Reconnection interval */ + reconnect_interval_max = ZMQ_RECONNECT_IVL_MAX, /*!< Maximum reconnection interval */ + receive_timeout = ZMQ_RCVTIMEO, /*!< Maximum inbound block timeout */ + send_timeout = ZMQ_SNDTIMEO, /*!< Maximum outbound block timeout */ +#if (ZMQ_VERSION_MAJOR == 2) + high_water_mark = ZMQ_HWM, /*!< High-water mark for all messages */ + swap_size = ZMQ_SWAP, /*!< Maximum socket swap size in bytes */ + multicast_loopback = ZMQ_MCAST_LOOP, /*!< Allow multicast packet loopback */ +#else + max_messsage_size = ZMQ_MAXMSGSIZE, /*!< Maximum inbound message size */ + send_high_water_mark = ZMQ_SNDHWM, /*!< High-water mark for outbound messages */ + receive_high_water_mark = ZMQ_RCVHWM, /*!< High-water mark for inbound messages */ + multicast_hops = ZMQ_MULTICAST_HOPS, /*!< Maximum number of multicast hops */ +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 1)) + ipv4_only = ZMQ_IPV4ONLY, +#endif +#if (ZMQ_VERSION_MAJOR > 3) || ((ZMQ_VERSION_MAJOR == 3) && (ZMQ_VERSION_MINOR >= 2)) +#if (ZMQ_VERSION_MINOR == 2) + delay_attach_on_connect = ZMQ_DELAY_ATTACH_ON_CONNECT, /*!< Delay buffer attachment until connect complete */ +#else + // ZMQ_DELAY_ATTACH_ON_CONNECT is renamed in ZeroMQ starting 3.3.x + immediate = ZMQ_IMMEDIATE, /*!< Block message sending until connect complete */ +#endif + last_endpoint = ZMQ_LAST_ENDPOINT, /*!< Last bound endpoint - get only */ + router_mandatory = ZMQ_ROUTER_MANDATORY, /*!< Require routable messages - set only */ + xpub_verbose = ZMQ_XPUB_VERBOSE, /*!< Pass on existing subscriptions - set only */ + tcp_keepalive = ZMQ_TCP_KEEPALIVE, /*!< Enable TCP keepalives */ + tcp_keepalive_idle = ZMQ_TCP_KEEPALIVE_IDLE, /*!< TCP keepalive idle count (generally retry count) */ + tcp_keepalive_count = ZMQ_TCP_KEEPALIVE_CNT, /*!< TCP keepalive retry count */ + tcp_keepalive_interval = ZMQ_TCP_KEEPALIVE_INTVL, /*!< TCP keepalive interval */ + tcp_accept_filter = ZMQ_TCP_ACCEPT_FILTER, /*!< Filter inbound connections - set only */ +#endif +#ifdef ZMQ_EXPERIMENTAL_LABELS + receive_label = ZMQ_RCVLABEL, /*!< Received label part - get only */ +#endif +}; + +} + +#endif /* ZMQPP_SOCKET_OPTIONS_HPP_ */ diff --git a/dep/zmqpp/zmqpp/socket_types.hpp b/dep/zmqpp/zmqpp/socket_types.hpp new file mode 100644 index 00000000000..e59e71ca0e1 --- /dev/null +++ b/dep/zmqpp/zmqpp/socket_types.hpp @@ -0,0 +1,148 @@ +/** + * \file + * + * \date 23 Sep 2011 + * \author Ben Gray (\@benjamg) + */ + +#ifndef ZMQPP_SOCKET_TYPES_HPP_ +#define ZMQPP_SOCKET_TYPES_HPP_ + +namespace zmqpp +{ + +/*! + * \brief Socket types allowed by zmq + * + * The socket type choose at creation must be one of these types. + * + * Each is designed for a different use and has different limitations. + */ +enum class socket_type { + /*! + * One to one - two way connection.\n + * Connect to ::pair.\n + * A \c pair socket has to be connected only one other pair socket and allows + * two way communication between them. + */ + pair = ZMQ_PAIR, + + /*! + * One to many - fan out.\n + * Connect to ::subscribe or ::xsubscribe.\n + * Socket is send only.\n + * Socket will drop messages and not block.\n + * \c publish sockets allow sending of the same message to many subscribers + * each subscriber can limit what is sent through the socket_option::subscribe + * settings. + */ + publish = ZMQ_PUB, + + /*! + * \note It seems doxygen can't work out which data is for the socket type and + * which is for the socket option so both get listed for both. + * + * One to many - fair-queued.\n + * Connect to ::publish or ::xpublish.\n + * Socket is receive only.\n + * The \c subscribe socket can connection to any number of publishers and will + * fairly pull messages from each. The socket_option::subscribe settings can + * be use to limit which messages are received and by default none are. + */ + subscribe = ZMQ_SUB, + + /*! + * One to many - fair-queued.\n + * Connect to ::push.\n + * Socket is receive only.\n + * The \c pull socket fairly pulls messages from all pushers it is connected + * to. + */ + pull = ZMQ_PULL, + + /*! + * One to many - load-balanced.\n + * Connect to ::pull.\n + * Socket is send only.\n + * Socket will block if unable to send.\n + * The \c push socket fairly distributes messages between any connected + * puller sockets. + */ + push = ZMQ_PUSH, + + /*! + * One to many - fair-queued outgoing, last peer incoming.\n + * Connect to ::reply or ::xreply.\n + * Socket flips between send and receive only.\n + * Socket will block if unable to send.\n + * The \c request socket will fairly balance requests sent out to a + * replier and then can only be used to receive until that replier + * sends a reply. + */ + request = ZMQ_REQ, + + /*! + * One to many - load-balanced incoming, last peer outgoing.\n + * Connect to ::request or ::xrequest.\n + * Socket flips between send and receive only.\n + * Socket will drop messages and not block.\n + * The \c reply socket can only receive until it pulls a message from a + * requester at which point it can only send until the reply is sent. + */ + reply = ZMQ_REP, + + /*! + * One to many - fan out.\n + * Connect to ::subscribe or ::xsubscribe.\n + * Socket is send only with the exception of special subscription messages.\n + * Socket will drop messages and not block.\n + * \c xpublish act the same as ::publish sockets however also allow special + * subscription messages to be received from subscribers. + */ + xpublish = ZMQ_XPUB, + + /*! + * One to many - fair-queued.\n + * Connect to ::publish or ::xpublish.\n + * Socket is receive only with the exception of special subscription messages\n + * \c xsubscribe act the same as ::subscribe sockets however also allow special + * subscription messages to be send to connected publishers. + */ + xsubscribe = ZMQ_XSUB, + + /*! + * One to many - fair-queued incoming, load-balanced outgoing.\n + * Connect to ::reply or ::xreply.\n + * Socket will block if unable to send.\n + * An \c xrequest socket balances requests between repliers and pulls replies + * back in a fair manner. Each request is expected to have exactly one reply. + */ + xrequest = ZMQ_XREQ, + + /*! + * One to many - fair-queued incoming, targeted outgoing.\n + * Connect to ::request or ::xrequest.\n + * Socket will drop messages and not block.\n + * An \c xreply socket fairly pulls in requests from requesters and will + * label requests so it can return replies back to the correct target. + */ + xreply = ZMQ_XREP, + + // To match for people who prefer the shorter versions + pub = ZMQ_PUB, /*!< version of ::publish to match zmq name convention */ + sub = ZMQ_SUB, /*!< version of ::subscribe to match zmq name convention */ + req = ZMQ_REQ, /*!< version of ::request to match zmq name convention */ + rep = ZMQ_REP, /*!< version of ::reply to match zmq name convention */ + xpub = ZMQ_XPUB, /*!< version of ::xpublish to match zmq name convention */ + xsub = ZMQ_XSUB, /*!< version of ::xsubscribe to match zmq name convention */ + xreq = ZMQ_XREQ, /*!< version of ::xrequest to match zmq name convention */ + xrep = ZMQ_XREP, /*!< version of ::xreply to match zmq name convention */ + + // For completion + router = ZMQ_ROUTER, /*!< \deprecated Matches zmq 2.x xrep functionality. */ + dealer = ZMQ_DEALER /*!< \deprecated Matches zmq 2.x xreq functionality. */ +}; + +} + +#endif /* ZMQPP_SOCKET_TYPES_HPP_ */ diff --git a/dep/zmqpp/zmqpp/zmqpp.cpp b/dep/zmqpp/zmqpp/zmqpp.cpp new file mode 100644 index 00000000000..216948e73e7 --- /dev/null +++ b/dep/zmqpp/zmqpp/zmqpp.cpp @@ -0,0 +1,30 @@ +/* + * Created on: 18 Aug 2011 + * Author: Ben Gray (@benjamg) + */ + +#include "zmqpp.hpp" + +namespace zmqpp +{ + +std::string version() +{ + return BUILD_VERSION; +} + +void version(uint8_t& major, uint8_t& minor, uint8_t& revision) +{ + major = ZMQPP_VERSION_MAJOR; + minor = ZMQPP_VERSION_MINOR; + revision = ZMQPP_VERSION_REVISION; +} + +void zmq_version(uint8_t& major, uint8_t& minor, uint8_t& patch) +{ + major = ZMQ_VERSION_MAJOR; + minor = ZMQ_VERSION_MINOR; + patch = ZMQ_VERSION_PATCH; +} + +} diff --git a/dep/zmqpp/zmqpp/zmqpp.hpp b/dep/zmqpp/zmqpp/zmqpp.hpp new file mode 100644 index 00000000000..92a47ce38bf --- /dev/null +++ b/dep/zmqpp/zmqpp/zmqpp.hpp @@ -0,0 +1,111 @@ +/** + * \file + * + * \date 9 Aug 2011 + * \author Ben Gray (\@benjamg) + * + * License: http://www.opensource.org/licenses/MIT + * + * Copyright (C) 2011 by Ben Gray + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef ZMQPP_ZMQPP_HPP_ +#define ZMQPP_ZMQPP_HPP_ + +/** + * \def ZMQPP_VERSION_MAJOR + * zmqpp major version number, generated at compile time + */ +#define ZMQPP_VERSION_MAJOR BUILD_VERSION_MAJOR + +/** + * \def ZMQPP_VERSION_MINOR + * zmqpp minor version number, generated at compile time + */ +#define ZMQPP_VERSION_MINOR BUILD_VERSION_MINOR + +/** + * \def ZMQPP_VERSION_REVISION + * zmqpp version revision number, generated at compile time + */ +#define ZMQPP_VERSION_REVISION BUILD_VERSION_REVISION + +#include + +#include "compatibility.hpp" +#include "context.hpp" +#include "exception.hpp" +#include "message.hpp" +#include "poller.hpp" +#include "socket.hpp" + +/*! + * \brief C++ wrapper around zmq + * + * All zmq++ / zmqpp functions, constants and classes live within this namespace, + */ +namespace zmqpp +{ + +/*! + * Returns the current major.minor.revision version number as a string. + * + * \return string version number. + */ +std::string version(); + +/*! + * Retrieve the parts of the zmqpp version number. + * + * Set the three parameters to values representing the zmqpp version number. + * These values are generated at library compile time. + * + * \param major an unsigned 8 bit reference to set to the major version. + * \param minor an unsigned 8 bit reference to set to the minor version. + * \param revision an unsigned 8 bit reference to set the current revision. + */ +void version(uint8_t& major, uint8_t& minor, uint8_t& revision); + +/*! + * Retrieve the parts of the 0mq version this library was built against. + * + * Because sections of the library are optionally compiled in or ignored + * depending on the version of 0mq it was compiled against this method is + * provided to allow sanity checking for usage. + * + * Set the three parameters to values representing the 0mq version number. + * These values are generated at library compile time. + * + * \param major an unsigned 8 bit reference to set to the major version. + * \param minor an unsigned 8 bit reference to set to the minor version. + * \param revision an unsigned 8 bit reference to set the current revision. + */ +void zmq_version(uint8_t& major, uint8_t& minor, uint8_t& patch); + +typedef context context_t; /*!< \brief context type */ +typedef std::string endpoint_t; /*!< \brief endpoint type */ +typedef message message_t; /*!< \brief message type */ +typedef poller poller_t; /*!< \brief poller type */ +typedef socket socket_t; /*!< \brief socket type */ + +} + +#endif /* ZMQPP_ZMQPP_HPP_ */ diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index ea2ad3abac7..e691b9527a5 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -25,6 +25,7 @@ if( SERVERS ) add_subdirectory(game) add_subdirectory(collision) add_subdirectory(authserver) + add_subdirectory(ipc) add_subdirectory(bnetserver) add_subdirectory(scripts) add_subdirectory(worldserver) diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index 9d99ac7f0c5..5b854018d47 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -45,6 +45,7 @@ endif() include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/zmqpp ${CMAKE_SOURCE_DIR}/src/server/shared ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Database @@ -56,6 +57,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Authentication ${CMAKE_CURRENT_SOURCE_DIR}/Realms @@ -64,6 +66,7 @@ include_directories( ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${VALGRIND_INCLUDE_DIR} + ${ZMQ_INCLUDE_DIR} ) add_executable(bnetserver @@ -80,9 +83,12 @@ if( NOT WIN32 ) endif() target_link_libraries(bnetserver + ipc shared + zmqpp ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} + ${ZMQ_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ) diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index ff891304bd3..ce90019c011 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -35,6 +35,7 @@ #include "RealmList.h" #include "SystemConfig.h" #include "Util.h" +#include "ZmqContext.h" #include #include #include @@ -94,12 +95,21 @@ int main(int argc, char** argv) } } + int32 worldListenPort = sConfigMgr->GetIntDefault("WorldserverListenPort", 1118); + if (worldListenPort < 0 || worldListenPort > 0xFFFF) + { + TC_LOG_ERROR("server.bnetserver", "Specified worldserver listen port (%d) out of allowed range (1-65535)", worldListenPort); + return 1; + } + // Initialize the database connection if (!StartDB()) return 1; + sIpcContext->Initialize(); + // Get the list of realms for the server - sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10)); + sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10), worldListenPort); // Start the listening port (acceptor) for auth connections int32 bnport = sConfigMgr->GetIntDefault("BattlenetPort", 1119); @@ -135,6 +145,10 @@ int main(int argc, char** argv) // Start the io service worker loop _ioService.run(); + sIpcContext->Close(); + + sRealmList->Close(); + // Close the Database Pool and library StopDB(); diff --git a/src/server/bnetserver/Packets/BitStream.h b/src/server/bnetserver/Packets/BitStream.h index 952ec5a39e2..54c61ab3bbf 100644 --- a/src/server/bnetserver/Packets/BitStream.h +++ b/src/server/bnetserver/Packets/BitStream.h @@ -212,14 +212,6 @@ namespace Battlenet } } - void SetReadPos(uint32 bits) - { - if (bits > _writePos) - throw BitStreamPositionException(true, bits, 0, _writePos); - - _readPos = bits; - } - bool IsRead() const { return _readPos >= _writePos; } uint8* GetBuffer() { return _buffer.data(); } @@ -227,6 +219,10 @@ namespace Battlenet size_t GetSize() const { return ((_writePos + 7) & ~7) / 8; } + // These methods are meant to only be used when their corresponding actions in the client ignore the value completely + void ReadSkip(uint32 bitCount) { _readPos += bitCount; } + void WriteSkip(uint32 bitCount) { Write(0, bitCount); } + private: uint32 _writePos; uint32 _readPos; diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index 14c5fb3a665..2659ec6204f 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -132,7 +132,7 @@ std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() co void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() { - _stream.Write(0, 23); // Ignored + _stream.WriteSkip(23); _stream.Write(Result, 16); _stream.Write(SocialNetworkId, 32); } diff --git a/src/server/bnetserver/Packets/PacketManager.cpp b/src/server/bnetserver/Packets/PacketManager.cpp index 019cf48ac30..e18f3dc5ffb 100644 --- a/src/server/bnetserver/Packets/PacketManager.cpp +++ b/src/server/bnetserver/Packets/PacketManager.cpp @@ -115,8 +115,8 @@ void Battlenet::PacketManager::RegisterWoWRealmPackets() REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_SUBSCRIBE_RESPONSE, WOWREALM), WoWRealm::ListSubscribeResponse); REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_UPDATE, WOWREALM), WoWRealm::ListUpdate); REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_LIST_COMPLETE, WOWREALM), WoWRealm::ListComplete); - REGISTER_SERVER_PACKET_NAME(PacketHeader(WoWRealm::SMSG_TOON_READY, WOWREALM), "WoWRealm::ToonReady"); - REGISTER_SERVER_PACKET_NAME(PacketHeader(WoWRealm::SMSG_TOON_LOGGED_OUT, WOWREALM), "WoWRealm::ToonLoggedOut"); + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_TOON_READY, WOWREALM), WoWRealm::ToonReady); + REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_TOON_LOGGED_OUT, WOWREALM), WoWRealm::ToonLoggedOut); REGISTER_SERVER_PACKET(PacketHeader(WoWRealm::SMSG_JOIN_RESPONSE_V2, WOWREALM), WoWRealm::JoinResponseV2); } diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index beeeb14895c..986152cbccb 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -40,6 +40,26 @@ void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) session->HandleListUnsubscribe(*this); } +void Battlenet::WoWRealm::JoinRequestV2::Read() +{ + Realm.Battlegroup = _stream.Read(8); + Realm.Index = _stream.Read(32); + Realm.Region = _stream.Read(8); + ClientSeed = _stream.Read(32); +} + +std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const +{ + std::ostringstream stream; + stream << "Battlenet::WoWRealm::JoinRequestV2 ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index; + return stream.str().c_str(); +} + +void Battlenet::WoWRealm::JoinRequestV2::CallHandler(Session* session) +{ + session->HandleJoinRequestV2(*this); +} + Battlenet::WoWRealm::ListSubscribeResponse::~ListSubscribeResponse() { for (ServerPacket* realmData : RealmData) @@ -143,24 +163,32 @@ std::string Battlenet::WoWRealm::ListUpdate::ToString() const return stream.str().c_str(); } -void Battlenet::WoWRealm::JoinRequestV2::Read() +void Battlenet::WoWRealm::ToonReady::Write() { - Realm.Battlegroup = _stream.Read(8); - Realm.Index = _stream.Read(32); - Realm.Region = _stream.Read(8); - ClientSeed = _stream.Read(32); + _stream.Write(Realm.Region, 8); + _stream.WriteFourCC(Game); + uint32 realmAddress = ((Realm.Battlegroup << 16) & 0xFF0000) | uint16(Realm.Index); + _stream.Write(realmAddress, 32); + _stream.WriteString(Name, 7, -2); + _stream.WriteSkip(7); + _stream.Write(Guid, 64); + _stream.WriteFourCC(Game); + _stream.Write(Realm.Region, 8); + _stream.WriteSkip(21); + _stream.Write(realmAddress, 32); + _stream.WriteSkip(9); + _stream.Write(0, 64); // Unknown + _stream.Write(0, 32); // Unknown } -std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const +std::string Battlenet::WoWRealm::ToonReady::ToString() const { std::ostringstream stream; - stream << "Battlenet::WoWRealm::JoinRequestV2 ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index; - return stream.str().c_str(); -} + stream << "Battlenet::WoWRealm::ToonReady" << " Game: " << Game + << ", Region: " << uint32(Realm.Region) << ", Battlegroup: " << uint32(Realm.Battlegroup) << ", Index: " << Realm.Index + << ", Guid: " << Guid << ", Name: " << Name; -void Battlenet::WoWRealm::JoinRequestV2::CallHandler(Session* session) -{ - session->HandleJoinRequestV2(*this); + return stream.str().c_str(); } void Battlenet::WoWRealm::JoinResponseV2::Write() diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index 2b1390a9067..b411c63100a 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -153,6 +153,33 @@ namespace Battlenet std::string ToString() const override { return "Battlenet::WoWRealm::ListComplete"; } }; + class ToonReady final : public ServerPacket + { + public: + ToonReady() : ServerPacket(PacketHeader(SMSG_TOON_READY, WOWREALM)), Game("WoW"), Guid(0) + { + } + + void Write() override; + std::string ToString() const override; + + std::string Game; + RealmId Realm; + uint64 Guid; + std::string Name; + }; + + class ToonLoggedOut final : public ServerPacket + { + public: + ToonLoggedOut() : ServerPacket(PacketHeader(SMSG_TOON_LOGGED_OUT, WOWREALM)) + { + } + + void Write() override { } + std::string ToString() const override { return "Battlenet::WoWRealm::ToonLoggedOut"; } + }; + class JoinResponseV2 final : public ServerPacket { public: diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index 2bf93e12cb3..cc7e1d492a8 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -16,12 +16,21 @@ * with this program. If not, see . */ -#include #include "Common.h" #include "Database/DatabaseEnv.h" #include "SessionManager.h" #include "Util.h" +#include "Commands.h" #include "RealmList.h" +#include + +Battlenet::RealmId& Battlenet::RealmId::operator=(Battlenet::RealmHandle const& handle) +{ + Region = handle.Region; + Battlegroup = handle.Battlegroup; + Index = handle.Index; + return *this; +} ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const { @@ -58,7 +67,7 @@ ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) cons return endpoint; } -RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) +RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr), _worldListener(nullptr) { } @@ -66,10 +75,11 @@ RealmList::~RealmList() { delete _updateTimer; delete _resolver; + delete _worldListener; } // Load the realm list from the database -void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) +void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval, uint16 worldListenPort) { _updateInterval = updateInterval; _updateTimer = new boost::asio::deadline_timer(ioService); @@ -77,6 +87,14 @@ void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInte // Get the content of the realmlist table in the database UpdateRealms(boost::system::error_code()); + + _worldListener = new WorldListener(worldListenPort); + _worldListener->Start(); +} + +void RealmList::Close() +{ + _worldListener->End(); } template diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index a4d3d77ff56..dc78a00dfdd 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -19,11 +19,12 @@ #ifndef _REALMLIST_H #define _REALMLIST_H +#include "Common.h" +#include "WorldListener.h" #include #include #include #include -#include "Common.h" using namespace boost::asio; @@ -44,6 +45,8 @@ enum RealmFlags namespace Battlenet { + struct RealmHandle; + struct RealmId { RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { } @@ -59,6 +62,8 @@ namespace Battlenet { return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0; } + + RealmId& operator=(RealmHandle const& handle); }; } @@ -98,7 +103,8 @@ public: ~RealmList(); - void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); + void Initialize(boost::asio::io_service& ioService, uint32 updateInterval, uint16 worldListenPort); + void Close(); RealmMap const& GetRealms() const { return _realms; } Realm const* GetRealm(Battlenet::RealmId const& id) const; @@ -114,6 +120,7 @@ private: uint32 _updateInterval; boost::asio::deadline_timer* _updateTimer; boost::asio::ip::tcp::resolver* _resolver; + WorldListener* _worldListener; }; #define sRealmList RealmList::instance() diff --git a/src/server/bnetserver/Realms/WorldListener.cpp b/src/server/bnetserver/Realms/WorldListener.cpp new file mode 100644 index 00000000000..30886a67310 --- /dev/null +++ b/src/server/bnetserver/Realms/WorldListener.cpp @@ -0,0 +1,109 @@ +/* + * 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 "Log.h" +#include "SessionManager.h" +#include "WoWRealmPackets.h" +#include "ZmqContext.h" +#include "WorldListener.h" + +WorldListener::HandlerTable const WorldListener::_handlers; + +WorldListener::HandlerTable::HandlerTable() +{ +#define DEFINE_HANDLER(opc, func) _handlers[opc] = { func, #opc } + + DEFINE_HANDLER(BNET_CHANGE_TOON_ONLINE_STATE, &WorldListener::HandleToonOnlineStatusChange); + +#undef DEFINE_HANDLER +} + +WorldListener::WorldListener(uint16 worldListenPort) : _worldListenPort(worldListenPort) +{ + _worldSocket = sIpcContext->CreateNewSocket(zmqpp::socket_type::pull); +} + +WorldListener::~WorldListener() +{ + delete _worldSocket; +} + +void WorldListener::Run() +{ + while (!ProcessExit()) + { + _poller->poll(); + if (_poller->events(*_worldSocket) & zmqpp::poller::poll_in) + { + int32 op1; + do + { + zmqpp::message msg; + _worldSocket->receive(msg); + Dispatch(msg); + _worldSocket->get(zmqpp::socket_option::events, op1); + } while (op1 & zmqpp::poller::poll_in); + } + } +} + +void WorldListener::HandleOpen() +{ + _worldSocket->bind(std::string("tcp://*:") + std::to_string(_worldListenPort)); + _poller->add(*_worldSocket); + TC_LOG_INFO("server.ipc", "Listening on connections from worldservers..."); +} + +void WorldListener::HandleClose() +{ + _worldSocket->close(); + TC_LOG_INFO("server.ipc", "Shutting down connections from worldservers..."); +} + +void WorldListener::Dispatch(zmqpp::message& msg) const +{ + Battlenet::Header ipcHeader; + msg >> ipcHeader; + + if (ipcHeader.Ipc.Channel != IPC_CHANNEL_BNET) + return; + + if (ipcHeader.Ipc.Command < IPC_BNET_MAX_COMMAND) + (this->*_handlers[ipcHeader.Ipc.Command].Handler)(ipcHeader.Realm, msg); +} + +void WorldListener::HandleToonOnlineStatusChange(Battlenet::RealmHandle const& realm, zmqpp::message& msg) const +{ + Battlenet::ToonHandle toonHandle; + bool online; + msg >> toonHandle; + msg >> online; + + if (Battlenet::Session* session = sSessionMgr.GetSession(toonHandle.AccountId, toonHandle.GameAccountId)) + { + if (online) + { + Battlenet::WoWRealm::ToonReady* toonReady = new Battlenet::WoWRealm::ToonReady(); + toonReady->Realm = realm; + toonReady->Guid = toonHandle.Guid; + toonReady->Name = toonHandle.Name; + session->AsyncWrite(toonReady); + } + else + session->AsyncWrite(new Battlenet::WoWRealm::ToonLoggedOut()); + } +} diff --git a/src/server/bnetserver/Realms/WorldListener.h b/src/server/bnetserver/Realms/WorldListener.h new file mode 100644 index 00000000000..04d5342449c --- /dev/null +++ b/src/server/bnetserver/Realms/WorldListener.h @@ -0,0 +1,63 @@ +/* + * 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 WorldListener_h__ +#define WorldListener_h__ + +#include "ZMQTask.h" +#include "Commands.h" + +class WorldListener : public ZMQTask +{ +public: + explicit WorldListener(uint16 worldListenPort); + ~WorldListener(); + void Run() override; + +protected: + void HandleOpen() override; + void HandleClose() override; + +private: + void Dispatch(zmqpp::message& msg) const; + + typedef void(WorldListener::*PacketHandler)(Battlenet::RealmHandle const& realm, zmqpp::message& msg) const; + class HandlerTable + { + public: + HandlerTable(); + + struct HandlerInfo + { + PacketHandler Handler; + char const* Name; + }; + + HandlerInfo const& operator[](uint8 opcode) const { return _handlers[opcode]; } + + private: + HandlerInfo _handlers[IPC_BNET_MAX_COMMAND]; + }; + + void HandleToonOnlineStatusChange(Battlenet::RealmHandle const& realm, zmqpp::message& msg) const; + + zmqpp::socket* _worldSocket; + uint16 _worldListenPort; + static HandlerTable const _handlers; +}; + +#endif // WorldListener_h__ diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index a2c587841a4..c932115a04b 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -93,9 +93,9 @@ namespace Battlenet bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; } - protected: void AsyncWrite(ServerPacket* packet); + protected: void ReadHandler() override; private: diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index 8dcee55ec6c..9e5836dab8d 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -49,3 +49,22 @@ void Battlenet::SessionManager::RemoveSession(Session* session) _sessions.erase({ session->GetAccountId(), session->GetGameAccountId() }); _sessionsByAccountId[session->GetAccountId()].remove(session); } + +Battlenet::Session* Battlenet::SessionManager::GetSession(uint32 accountId, uint32 gameAccountId) const +{ + auto itr = _sessions.find({ accountId, gameAccountId }); + if (itr != _sessions.end()) + return itr->second; + + return nullptr; +} + +std::list Battlenet::SessionManager::GetSessions(uint32 accountId) const +{ + std::list sessions; + auto itr = _sessionsByAccountId.find(accountId); + if (itr != _sessionsByAccountId.end()) + sessions = itr->second; + + return sessions; +} diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index bbd78c052d2..08ca5ce2b4e 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -60,6 +60,9 @@ namespace Battlenet void RemoveSession(Session* /*session*/); + Session* GetSession(uint32 accountId, uint32 gameAccountId) const; + std::list GetSessions(uint32 accountId) const; + template void LockedForEach(Iterator iterator) { diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 84456c117b3..102ddb9906a 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -46,6 +46,13 @@ LogsDir = "" MaxPingTime = 30 +# +# WorldserverListenPort +# Description: TCP port to listen on for incoming worldserver IPC. +# Default: 1118 + +WorldserverListenPort = 1118 + # # BattlenetPort # Description: TCP port to reach the auth server for battle.net connections. diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index 1c5fcbee52e..3aac255be29 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -47,6 +47,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/shared/DataStores + ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_SOURCE_DIR}/src/server/game/Addons ${CMAKE_SOURCE_DIR}/src/server/game/Conditions ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 79512e57fe3..6550bccc06d 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -107,7 +107,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& else { bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid); - logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realmID); + logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realmHandle.Index); if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName)) bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 0d1b460500e..27b3ea2c381 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -111,6 +111,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib + ${CMAKE_SOURCE_DIR}/dep/zmqpp ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models @@ -129,6 +130,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Accounts ${CMAKE_CURRENT_SOURCE_DIR}/Achievements @@ -205,6 +207,7 @@ include_directories( ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${VALGRIND_INCLUDE_DIR} + ${ZMQ_INCLUDE_DIR} ) add_library(game STATIC diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index ace13989efb..6dfd25495d2 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -160,7 +160,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac if (target) target_sec = target->GetSecurity(); else if (target_account) - target_sec = AccountMgr::GetSecurity(target_account, realmID); + target_sec = AccountMgr::GetSecurity(target_account, realmHandle.Index); else return true; // caller must report error for (target == NULL && target_account == 0) diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 2cae8427161..bef7aada6e9 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -47,6 +47,7 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "BattlenetServerManager.h" class LoginQueryHolder : public SQLQueryHolder { @@ -689,13 +690,13 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, GetAccountId()); - stmt->setUInt32(1, realmID); + stmt->setUInt32(1, realmHandle.Index); trans->Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); stmt->setUInt32(0, createInfo->CharCount); stmt->setUInt32(1, GetAccountId()); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realmHandle.Index); trans->Append(stmt); LoginDatabase.CommitTransaction(trans); @@ -1139,6 +1140,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) sScriptMgr->OnPlayerLogin(pCurrChar, firstLogin); + sBattlenetServer.SendChangeToonOnlineState(GetBattlenetAccountId(), GetAccountId(), _player->GetGUID(), _player->GetName(), true); + delete holder; } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 8d11b9bf41d..3f7cf24206d 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -609,7 +609,7 @@ void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std team = Player::TeamForRace(fields[1].GetUInt8()); friendAccountId = fields[2].GetUInt32(); - if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) + if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmHandle.Index))) { if (friendGuid) { diff --git a/src/server/game/Server/BattlenetServerManager.cpp b/src/server/game/Server/BattlenetServerManager.cpp new file mode 100644 index 00000000000..b267926c6ff --- /dev/null +++ b/src/server/game/Server/BattlenetServerManager.cpp @@ -0,0 +1,66 @@ +/* + * 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 "Config.h" +#include "World.h" +#include "ZmqContext.h" +#include "BattlenetServerManager.h" + +void Battlenet::ServerManager::InitializeConnection() +{ + std::string bnetserverAddress = sConfigMgr->GetStringDefault("BnetServer.Address", "127.0.0.1"); + int32 bnetserverPort = sConfigMgr->GetIntDefault("BnetServer.Port", 1118); + _socket = new ZmqMux("inproc://bnetmgr", "tcp://" + bnetserverAddress + ":" + std::to_string(bnetserverPort)); + _socket->Start(); +} + +void Battlenet::ServerManager::CloseConnection() +{ + _socket->End(); + delete _socket; + _socket = nullptr; +} + +Battlenet::Header Battlenet::ServerManager::CreateHeader(BnetCommands command) +{ + Header header; + header.Ipc.Channel = IPC_CHANNEL_BNET; + header.Ipc.Command = command; + header.Realm = realmHandle; + return header; +} + +void Battlenet::ServerManager::SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online) +{ + // Do nothing for Grunt login + if (!battlenetAccountId) + return; + + Header header = CreateHeader(BNET_CHANGE_TOON_ONLINE_STATE); + ToonHandle toon; + toon.AccountId = battlenetAccountId; + toon.GameAccountId = gameAccountId; + toon.Guid = guid; + toon.Name = name; + + zmqpp::message msg; + msg << header; + msg << toon; + msg << online; + + _socket->Send(&msg); +} diff --git a/src/server/game/Server/BattlenetServerManager.h b/src/server/game/Server/BattlenetServerManager.h new file mode 100644 index 00000000000..fe103a1c981 --- /dev/null +++ b/src/server/game/Server/BattlenetServerManager.h @@ -0,0 +1,55 @@ +/* + * 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 BattlenetMgr_h__ +#define BattlenetMgr_h__ + +#include "ZmqMux.h" +#include "Commands.h" + +namespace zmqpp +{ + class socket; +} + +namespace Battlenet +{ + class ServerManager + { + ServerManager() : _socket(nullptr) { } + + public: + void InitializeConnection(); + void CloseConnection(); + + static ServerManager& Instance() + { + static ServerManager instance; + return instance; + } + + void SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online); + + private: + static Header CreateHeader(BnetCommands command); + ZmqMux* _socket; + }; +} + +#define sBattlenetServer Battlenet::ServerManager::Instance() + +#endif // BattlenetMgr_h__ diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 4c183939460..0fd46f0d20b 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -47,6 +47,7 @@ #include "Transport.h" #include "WardenWin.h" #include "WardenMac.h" +#include "BattlenetServerManager.h" namespace { @@ -582,6 +583,9 @@ void WorldSession::LogoutPlayer(bool save) _player->CleanupsBeforeDelete(); TC_LOG_INFO("entities.player.character", "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d", GetAccountId(), GetRemoteAddress().c_str(), _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel()); + + sBattlenetServer.SendChangeToonOnlineState(GetBattlenetAccountId(), GetAccountId(), _player->GetGUID(), _player->GetName(), false); + if (Map* _map = _player->FindMap()) _map->RemovePlayerFromMap(_player, true); @@ -1143,11 +1147,11 @@ void WorldSession::LoadPermissions() AccountMgr::GetName(id, name); uint8 secLevel = GetSecurity(); - _RBACData = new rbac::RBACData(id, name, realmID, secLevel); + _RBACData = new rbac::RBACData(id, name, realmHandle.Index, secLevel); _RBACData->LoadFromDB(); TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]", - id, name.c_str(), realmID, secLevel); + id, name.c_str(), realmHandle.Index, secLevel); } rbac::RBACData* WorldSession::GetRBACData() @@ -1162,7 +1166,7 @@ bool WorldSession::HasPermission(uint32 permission) bool hasPermission = _RBACData->HasPermission(permission); TC_LOG_DEBUG("rbac", "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]", - _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + _RBACData->GetId(), _RBACData->GetName().c_str(), realmHandle.Index); return hasPermission; } @@ -1170,7 +1174,7 @@ bool WorldSession::HasPermission(uint32 permission) void WorldSession::InvalidateRBACData() { TC_LOG_DEBUG("rbac", "WorldSession::Invalidaterbac::RBACData [AccountId: %u, Name: %s, realmId: %d]", - _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + _RBACData->GetId(), _RBACData->GetName().c_str(), realmHandle.Index); delete _RBACData; _RBACData = NULL; } diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index bff343bdcb1..7933ddfeb4d 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -406,7 +406,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) return; } - if (realmIndex != realmID) + if (realmIndex != realmHandle.Index) { SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); @@ -485,7 +485,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, id); - stmt->setInt32(1, int32(realmID)); + stmt->setInt32(1, int32(realmHandle.Index)); result = LoginDatabase.Query(stmt); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 6adb93d4742..4b114255dbc 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1375,7 +1375,7 @@ void World::SetInitialWorldSettings() uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE); - LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); // One-time query + LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmHandle.Index); // One-time query ///- Remove the bones (they should not exist in DB though) and old corpses after a restart PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_CORPSES); @@ -1797,7 +1797,7 @@ void World::SetInitialWorldSettings() m_startTime = m_gameTime; LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')", - realmID, uint32(m_startTime), _FULLVERSION); // One-time query + realmHandle.Index, uint32(m_startTime), _FULLVERSION); // One-time query m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS); m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS); @@ -2079,7 +2079,7 @@ void World::Update(uint32 diff) stmt->setUInt32(0, tmpDiff); stmt->setUInt16(1, uint16(maxOnlinePlayers)); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realmHandle.Index); stmt->setUInt32(3, uint32(m_startTime)); LoginDatabase.Execute(stmt); @@ -2809,13 +2809,13 @@ void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM); stmt->setUInt32(0, accountId); - stmt->setUInt32(1, realmID); + stmt->setUInt32(1, realmHandle.Index); LoginDatabase.Execute(stmt); stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS); stmt->setUInt8(0, charCount); stmt->setUInt32(1, accountId); - stmt->setUInt32(2, realmID); + stmt->setUInt32(2, realmHandle.Index); LoginDatabase.Execute(stmt); } } @@ -2984,7 +2984,7 @@ void World::ResetCurrencyWeekCap() void World::LoadDBAllowedSecurityLevel() { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL); - stmt->setInt32(0, int32(realmID)); + stmt->setInt32(0, int32(realmHandle.Index)); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 49d154d8db6..2c74e3929fe 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -24,6 +24,7 @@ #define __WORLD_H #include "Common.h" +#include "Commands.h" #include "ObjectGuid.h" #include "Timer.h" #include "SharedDefines.h" @@ -879,7 +880,7 @@ class World std::deque> m_realmCharCallbacks; }; -extern uint32 realmID; +extern Battlenet::RealmHandle realmHandle; #define sWorld World::instance() #endif diff --git a/src/server/ipc/CMakeLists.txt b/src/server/ipc/CMakeLists.txt new file mode 100644 index 00000000000..93a5d630dfe --- /dev/null +++ b/src/server/ipc/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2008-2014 TrinityCore +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +file(GLOB_RECURSE sources_ipc *.cpp *.h) + +set(ipc_SRCS + ${sources_ipc} +) + +include_directories( + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/zmqpp + ${CMAKE_SOURCE_DIR}/src/server/shared/ + ${ZMQ_INCLUDE_DIR} +) + +add_library(ipc STATIC ${ipc_SRCS}) diff --git a/src/server/ipc/Commands.cpp b/src/server/ipc/Commands.cpp new file mode 100644 index 00000000000..8e494fc34b9 --- /dev/null +++ b/src/server/ipc/Commands.cpp @@ -0,0 +1,81 @@ +/* + * 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 "Commands.h" +#include + +zmqpp::message& operator>>(zmqpp::message& msg, IPCHeader& header) +{ + msg >> header.Channel; + msg >> header.Command; + return msg; +} + +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::RealmHandle& realm) +{ + msg >> realm.Region; + msg >> realm.Battlegroup; + msg >> realm.Index; + return msg; +} + +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::Header& header) +{ + msg >> header.Ipc; + msg >> header.Realm; + return msg; +} + +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle) +{ + msg >> toonHandle.AccountId; + msg >> toonHandle.GameAccountId; + msg >> toonHandle.Guid; + msg >> toonHandle.Name; + return msg; +} + +zmqpp::message& operator<<(zmqpp::message& msg, IPCHeader& header) +{ + msg << header.Channel; + msg << header.Command; + return msg; +} + +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle& realm) +{ + msg << realm.Region; + msg << realm.Battlegroup; + msg << realm.Index; + return msg; +} + +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::Header& header) +{ + msg << header.Ipc; + msg << header.Realm; + return msg; +} + +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle) +{ + msg << toonHandle.AccountId; + msg << toonHandle.GameAccountId; + msg << toonHandle.Guid; + msg << toonHandle.Name; + return msg; +} diff --git a/src/server/ipc/Commands.h b/src/server/ipc/Commands.h new file mode 100644 index 00000000000..05309a45022 --- /dev/null +++ b/src/server/ipc/Commands.h @@ -0,0 +1,83 @@ +/* + * 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 _COMMANDS_H +#define _COMMANDS_H + +#include "Define.h" +#include + +enum Channels +{ + IPC_CHANNEL_BNET, + + MAX_IPC_CHANNELS, +}; + +enum BnetCommands +{ + BNET_CHANGE_TOON_ONLINE_STATE, + + IPC_BNET_MAX_COMMAND +}; + +struct IPCHeader +{ + uint8 Channel; + uint8 Command; +}; + +namespace Battlenet +{ + struct RealmHandle + { + uint8 Region; + uint8 Battlegroup; + uint32 Index; + }; + + struct Header + { + IPCHeader Ipc; + RealmHandle Realm; + }; + + struct ToonHandle + { + uint32 AccountId; + uint32 GameAccountId; + uint64 Guid; + std::string Name; + }; +} + +namespace zmqpp +{ + class message; +} + +zmqpp::message& operator>>(zmqpp::message& msg, IPCHeader& header); +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::RealmHandle& realm); +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::Header& header); +zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle); + +zmqpp::message& operator<<(zmqpp::message& msg, IPCHeader& header); +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle& realm); +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::Header& header); +zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle); + +#endif // _COMMANDS_H diff --git a/src/server/ipc/ZMQTask.cpp b/src/server/ipc/ZMQTask.cpp new file mode 100644 index 00000000000..0d25dc2babf --- /dev/null +++ b/src/server/ipc/ZMQTask.cpp @@ -0,0 +1,93 @@ +/* + * 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 "ZMQTask.h" +#include "ZmqContext.h" +#include + +ZMQTask::ZMQTask() +{ + _poller = new zmqpp::poller(); +} + +ZMQTask::~ZMQTask() +{ + delete _poller; + _poller = NULL; + delete _inproc; + delete _thread; +} + +void ZMQTask::Start() +{ + _inproc = sIpcContext->CreateInprocSubscriber(); + _poller->add(*_inproc); + + HandleOpen(); + _thread = new std::thread(&ZMQTask::Run, this); +} + +void ZMQTask::End() +{ + _thread->join(); + _inproc->close(); + HandleClose(); +} + +bool ZMQTask::ProcessExit() +{ + if (_poller->events(*_inproc) == zmqpp::poller::poll_in) + { + int op1; + do + { + zmqpp::message msg; + if (!_inproc->receive(msg, true)) + return false; //No more messages to read from sock. This shouldn't happen. + + // strip 'internalmq.' from message + std::string cmd = msg.get(0).substr(11); + if (cmd == "kill") + return true; + + _inproc->get(zmqpp::socket_option::events, op1); + } while (op1 & zmqpp::poller::poll_in); + } + + return false; +} + +void ZMQTask::Pipeline(zmqpp::socket* from, zmqpp::socket* to) +{ + /* + Push messages from socket to socket. + */ + if (_poller->events(*from) == zmqpp::poller::poll_in) + { + int32 op1, op2; + do + { + zmqpp::message msg; + if (!from->receive(msg, true)) + return; //No more messages to read from socket. This shouldn't happen. + + to->send(msg); + from->get(zmqpp::socket_option::events, op1); + to->get(zmqpp::socket_option::events, op2); + } while(op1 & zmqpp::poller::poll_in && op2 & zmqpp::poller::poll_out); + } +} diff --git a/src/server/ipc/ZMQTask.h b/src/server/ipc/ZMQTask.h new file mode 100644 index 00000000000..24251893aaa --- /dev/null +++ b/src/server/ipc/ZMQTask.h @@ -0,0 +1,52 @@ +/* + * 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 __ZMQTASK_H +#define __ZMQTASK_H + +#include "Define.h" +#include +#include +#include + +/* + This class serves as a base for all long running tasks + It is set up to terminate its running task upon receiving "kill" command +*/ +class ZMQTask +{ +public: + ZMQTask(); + virtual ~ZMQTask(); + + void Start(); + void End(); + virtual void Run() = 0; + +protected: + virtual void HandleOpen() { } + virtual void HandleClose() { } + void Pipeline(zmqpp::socket* from, zmqpp::socket* to); + bool ProcessExit(); + + zmqpp::poller* _poller; + + zmqpp::socket* _inproc; + std::thread* _thread; +}; + +#endif // __ZMQTASK_H diff --git a/src/server/ipc/ZmqContext.cpp b/src/server/ipc/ZmqContext.cpp new file mode 100644 index 00000000000..305e6b1d843 --- /dev/null +++ b/src/server/ipc/ZmqContext.cpp @@ -0,0 +1,52 @@ +/* + * 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 "ZmqContext.h" + +ZmqContext::ZmqContext() : _inproc(nullptr) +{ +} + +ZmqContext::~ZmqContext() +{ + delete _inproc; +} + +zmqpp::socket* ZmqContext::CreateNewSocket(zmqpp::socket_type type) +{ + std::unique_lock lock(_mutex); + return new zmqpp::socket(_context, type); +} + +void ZmqContext::Initialize() +{ + _inproc = new zmqpp::socket(_context, zmqpp::socket_type::pub); + _inproc->bind("inproc://workers"); +} + +zmqpp::socket* ZmqContext::CreateInprocSubscriber() +{ + zmqpp::socket* sub = CreateNewSocket(zmqpp::socket_type::sub); + sub->connect("inproc://workers"); + sub->subscribe("internalmq."); + return sub; +} + +void ZmqContext::Close() +{ + _inproc->send("internalmq.kill"); +} diff --git a/src/server/ipc/ZmqContext.h b/src/server/ipc/ZmqContext.h new file mode 100644 index 00000000000..a6ad12b1b70 --- /dev/null +++ b/src/server/ipc/ZmqContext.h @@ -0,0 +1,55 @@ +/* + * 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 __ZMQCONTEX_H +#define __ZMQCONTEX_H + +#include +#include + +/* + * We need to serialize access to zmq context otherwise stuff blows up. + */ +class ZmqContext +{ +public: + ~ZmqContext(); + + static ZmqContext* Instance() + { + static ZmqContext instance; + return &instance; + } + + zmqpp::socket* CreateNewSocket(zmqpp::socket_type); + void Initialize(); + zmqpp::socket* CreateInprocSubscriber(); + void Close(); + +private: + ZmqContext(); + ZmqContext(ZmqContext const&) = delete; + ZmqContext& operator=(ZmqContext const&) = delete; + + zmqpp::context _context; + std::mutex _mutex; + zmqpp::socket* _inproc; +}; + +#define sIpcContext ZmqContext::Instance() + +#endif diff --git a/src/server/ipc/ZmqListener.cpp b/src/server/ipc/ZmqListener.cpp new file mode 100644 index 00000000000..98333305e58 --- /dev/null +++ b/src/server/ipc/ZmqListener.cpp @@ -0,0 +1,69 @@ +/* + * 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 "ZmqListener.h" +#include "ZmqContext.h" + +ZmqListener::ZmqListener(std::string const& from, std::string const& to) +{ + _from = sIpcContext->CreateNewSocket(zmqpp::socket_type::sub); + _to = sIpcContext->CreateNewSocket(zmqpp::socket_type::push); + _from->connect(from); + _to->bind(to); +} + +ZmqListener::~ZmqListener() +{ + delete _from; + delete _to; +} + +void ZmqListener::HandleOpen() +{ +} + +void ZmqListener::HandleClose() +{ + _from->close(); + _to->close(); +} + +void ZmqListener::Run() +{ + while (!ProcessExit()) + { + _poller->poll(); + + while (_poller->events(*_from) & zmqpp::poller::poll_in && + _poller->events(*_to) & zmqpp::poller::poll_out) + { + zmqpp::message msg; + _from->receive(msg); + _to->send(msg); + } + } +} + +void ZmqListener::Subscribe(std::string const& keyword) +{ + _from->subscribe(keyword); +} + +void ZmqListener::Unsubscribe(std::string const& keyword) +{ + _from->unsubscribe(keyword); +} diff --git a/src/server/ipc/ZmqListener.h b/src/server/ipc/ZmqListener.h new file mode 100644 index 00000000000..8b79ba67f6d --- /dev/null +++ b/src/server/ipc/ZmqListener.h @@ -0,0 +1,51 @@ +/* + * 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 __ZMQLISTENER_H +#define __ZMQLISTENER_H + +#include "ZMQTask.h" +#include + +class ZmqListener : public ZMQTask +{ +/* + * Read broadcasts from remote PUB socket, and forward them to + * another socket. + * + * from - client SUB socket + * to - listen PUSH socket + * + */ +public: + ZmqListener(std::string const& from, std::string const& to); + ~ZmqListener(); + void Run() override; + + void Subscribe(std::string const& keyword); + void Unsubscribe(std::string const& keyword); + +protected: + void HandleOpen() override; + void HandleClose() override; + +private: + zmqpp::socket* _from; + zmqpp::socket* _to; +}; + +#endif diff --git a/src/server/ipc/ZmqMux.cpp b/src/server/ipc/ZmqMux.cpp new file mode 100644 index 00000000000..4b5a4f48b05 --- /dev/null +++ b/src/server/ipc/ZmqMux.cpp @@ -0,0 +1,67 @@ +/* + * 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 "ZmqMux.h" +#include "ZmqContext.h" + +ZmqMux::ZmqMux(std::string from_uri, std::string to_uri): + _fromAddress(from_uri) +{ + printf("Opening muxer thread from %s to %s\n", from_uri.c_str(), to_uri.c_str()); + _from = sIpcContext->CreateNewSocket(zmqpp::socket_type::pull); + _to = sIpcContext->CreateNewSocket(zmqpp::socket_type::push); + + _from->bind(from_uri); + _to->connect(to_uri); +} + +ZmqMux::~ZmqMux() +{ + delete _from; + delete _to; +} + +void ZmqMux::HandleOpen() +{ + _poller->add(*_from); + _poller->add(*_to, zmqpp::poller::poll_out); +} + +bool ZmqMux::Send(zmqpp::message* m, bool dont_block) +{ + if (_socket.get() == nullptr) + { + _socket.reset(sIpcContext->CreateNewSocket(zmqpp::socket_type::push)); + _socket->connect(_fromAddress); + } + + return _socket->send(*m, dont_block); +} + +void ZmqMux::Run() +{ + for (;;) + { + if (!_poller->poll()) + break; + + if (ProcessExit()) + break; + + Pipeline(_from, _to); + } +} diff --git a/src/server/ipc/ZmqMux.h b/src/server/ipc/ZmqMux.h new file mode 100644 index 00000000000..4b81f11daaf --- /dev/null +++ b/src/server/ipc/ZmqMux.h @@ -0,0 +1,47 @@ +/* + * 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 __ZMQMUX_H +#define __ZMQMUX_H + +#include "ZMQTask.h" +#include +#include + +/* + * Multiplexes zmq messages from many threads, + * and then passes them to another socket. + */ +class ZmqMux : public ZMQTask +{ +public: + ZmqMux(std::string from, std::string to); + ~ZmqMux(); + bool Send(zmqpp::message*, bool dont_block = false); + void Run() override; + +protected: + void HandleOpen() override; + +private: + boost::thread_specific_ptr _socket; + zmqpp::socket* _from; + zmqpp::socket* _to; + std::string const _fromAddress; +}; + +#endif diff --git a/src/server/ipc/ZmqWorker.cpp b/src/server/ipc/ZmqWorker.cpp new file mode 100644 index 00000000000..f205ea831b5 --- /dev/null +++ b/src/server/ipc/ZmqWorker.cpp @@ -0,0 +1,70 @@ +/* + * 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 "ZmqWorker.h" +#include "ZmqContext.h" + +ZmqWorker::ZmqWorker(std::string task_uri, std::string res_uri) : + _taskUri(task_uri), _resultsUri(res_uri) +{ +} + +ZmqWorker::~ZmqWorker() +{ + delete _taskQueue; + delete _results; + delete _inproc; +} + +void ZmqWorker::HandleOpen() +{ + _taskQueue = sIpcContext->CreateNewSocket(zmqpp::socket_type::pull); + _results = sIpcContext->CreateNewSocket(zmqpp::socket_type::push); + + _taskQueue->connect(_taskUri); + _results->connect(_resultsUri); + + _poller->add(*_taskQueue); +} + +void ZmqWorker::HandleClose() +{ + _taskQueue->close(); + _results->close(); +} + +void ZmqWorker::Run() +{ + while (!ProcessExit()) + { + _poller->poll(); + if (_poller->events(*_taskQueue) & zmqpp::poller::poll_in) + PerformWork(); + } +} + +void ZmqWorker::PerformWork() +{ + int32 op1; + do + { + zmqpp::message msg; + _taskQueue->receive(msg); + Dispatch(msg); + _taskQueue->get(zmqpp::socket_option::events, op1); + } while (op1 & zmqpp::poller::poll_in); +} diff --git a/src/server/ipc/ZmqWorker.h b/src/server/ipc/ZmqWorker.h new file mode 100644 index 00000000000..b3e221e9129 --- /dev/null +++ b/src/server/ipc/ZmqWorker.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 __ZMQWORKER_H +#define __ZMQWORKER_H + +#include "ZMQTask.h" +#include + +class ZmqWorker : public ZMQTask +{ +public: + ZmqWorker(std::string task_uri, std::string res_uri); + ~ZmqWorker(); + void Run() override; + +protected: + void HandleOpen() override; + void HandleClose() override; + zmqpp::socket* _results; + +private: + void PerformWork(); + virtual void Dispatch(zmqpp::message const&) = 0; + zmqpp::socket* _taskQueue; + std::string _taskUri; + std::string _resultsUri; +}; + +#endif diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index e92c883eeff..eab6a36d02e 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -64,6 +64,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index 27ec4835ce6..4c5b68516ca 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -163,7 +163,7 @@ public: ///- Get the accounts with GM Level >0 PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_GM_ACCOUNTS); stmt->setUInt8(0, uint8(SEC_MODERATOR)); - stmt->setInt32(1, int32(realmID)); + stmt->setInt32(1, int32(realmHandle.Index)); PreparedQueryResult result = LoginDatabase.Query(stmt); if (result) diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 386be81c198..6fa3c6512b7 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1542,7 +1542,7 @@ public: // Query the prepared statement for login data stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO); - stmt->setInt32(0, int32(realmID)); + stmt->setInt32(0, int32(realmHandle.Index)); stmt->setUInt32(1, accId); PreparedQueryResult result = LoginDatabase.Query(stmt); diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp index 95ef5ab6984..ab960026d69 100644 --- a/src/server/scripts/Commands/cs_rbac.cpp +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -160,7 +160,7 @@ public: if (!rdata) { - data->rbac = new rbac::RBACData(accountId, accountName, realmID, AccountMgr::GetSecurity(accountId, realmID)); + data->rbac = new rbac::RBACData(accountId, accountName, realmHandle.Index, AccountMgr::GetSecurity(accountId, realmHandle.Index)); data->rbac->LoadFromDB(); data->needDelete = true; } diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index 674658f41ff..f2aa046676f 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -98,7 +98,7 @@ public: ObjectGuid targetGuid = sObjectMgr->GetPlayerGUIDByName(target); uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid); // Target must exist and have administrative rights - if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmID)) + if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmHandle.Index)) { handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); return true; @@ -122,7 +122,7 @@ public: // Assign ticket SQLTransaction trans = SQLTransaction(NULL); - ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmID))); + ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmHandle.Index))); ticket->SaveToDB(trans); sTicketMgr->UpdateLastChange(); @@ -378,7 +378,7 @@ public: { ObjectGuid guid = ticket->GetAssignedToGUID(); uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(guid); - security = AccountMgr::GetSecurity(accountId, realmID); + security = AccountMgr::GetSecurity(accountId, realmHandle.Index); } // Check security diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 0cdf5f13f79..65972e680ef 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -47,6 +47,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/dep/gsoap ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT + ${CMAKE_SOURCE_DIR}/dep/zmqpp ${CMAKE_SOURCE_DIR}/src/server/collision ${CMAKE_SOURCE_DIR}/src/server/collision/Management ${CMAKE_SOURCE_DIR}/src/server/collision/Models @@ -64,6 +65,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities + ${CMAKE_SOURCE_DIR}/src/server/ipc ${CMAKE_SOURCE_DIR}/src/server/game ${CMAKE_SOURCE_DIR}/src/server/game/Accounts ${CMAKE_SOURCE_DIR}/src/server/game/Achievements @@ -141,6 +143,7 @@ include_directories( ${MYSQL_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${VALGRIND_INCLUDE_DIR} + ${ZMQ_INCLUDE_DIR} ) add_executable(worldserver @@ -164,18 +167,21 @@ set_target_properties(worldserver PROPERTIES LINK_FLAGS "${worldserver_LINK_FLAG target_link_libraries(worldserver game + ipc shared scripts collision g3dlib gsoap Detour + zmqpp ${JEMALLOC_LIBRARY} ${READLINE_LIBRARY} ${TERMCAP_LIBRARY} ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARIES} + ${ZMQ_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ) diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 6c93343b8de..c5127b8f3e2 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -20,13 +20,9 @@ /// @{ /// \file -#include -#include -#include -#include -#include - #include "Common.h" +#include "Commands.h" +#include "ZmqContext.h" #include "DatabaseEnv.h" #include "AsyncAcceptor.h" #include "RASession.h" @@ -47,6 +43,12 @@ #include "SystemConfig.h" #include "WorldSocket.h" #include "WorldSocketMgr.h" +#include "BattlenetServerManager.h" +#include +#include +#include +#include +#include using namespace boost::program_options; @@ -79,7 +81,7 @@ uint32 _maxCoreStuckTimeInMs(0); WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the world database CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database -uint32 realmID; ///< Id of the realm +Battlenet::RealmHandle realmHandle; ///< Id of the realm void SignalHandler(const boost::system::error_code& error, int signalNumber); void FreezeDetectorHandler(const boost::system::error_code& error); @@ -188,7 +190,7 @@ extern int main(int argc, char** argv) } // Set server offline (not connectable) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmHandle.Index); // Initialize the World sWorld->SetInitialWorldSettings(); @@ -223,7 +225,7 @@ extern int main(int argc, char** argv) sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort); // Set server online (allow connecting now) - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmHandle.Index); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) @@ -234,6 +236,10 @@ extern int main(int argc, char** argv) TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", coreStuckTime); } + sIpcContext->Initialize(); + + sBattlenetServer.InitializeConnection(); + TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); sScriptMgr->OnStartup(); @@ -245,6 +251,10 @@ extern int main(int argc, char** argv) sScriptMgr->OnShutdown(); + sIpcContext->Close(); + + sBattlenetServer.CloseConnection(); + sWorld->KickAll(); // save and kick all players sWorld->UpdateSessions(1); // real players unload required UpdateSessions call @@ -260,7 +270,7 @@ extern int main(int argc, char** argv) sOutdoorPvPMgr->Die(); // set server offline - LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); + LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmHandle.Index); // Clean up threads if any if (soapThread != nullptr) @@ -523,13 +533,24 @@ bool StartDB() } ///- Get the realm Id from the configuration file - realmID = sConfigMgr->GetIntDefault("RealmID", 0); - if (!realmID) + realmHandle.Index = sConfigMgr->GetIntDefault("RealmID", 0); + if (!realmHandle.Index) { 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); + + QueryResult realmIdQuery = LoginDatabase.PQuery("SELECT `Region`,`Battlegroup` FROM `realmlist` WHERE `id`=%u", realmHandle.Index); + if (!realmIdQuery) + { + TC_LOG_ERROR("server.worldserver", "Realm id %u not defined in realmlist table", realmHandle.Index); + return false; + } + + realmHandle.Region = (*realmIdQuery)[0].GetUInt8(); + realmHandle.Battlegroup = (*realmIdQuery)[1].GetUInt8(); + + TC_LOG_INFO("server.worldserver", "Realm running as realm ID %u region %u battlegroup %u", realmHandle.Index, uint32(realmHandle.Region), uint32(realmHandle.Battlegroup)); ///- Clean the database before starting ClearOnlineAccounts(); @@ -556,7 +577,7 @@ void StopDB() 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); + LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", realmHandle.Index); // Reset online status for all characters CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0"); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 6c3972de421..57d97756d70 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3324,3 +3324,24 @@ PacketSpoof.BanDuration = 86400 # ################################################################################################### + +################################################################################################### +# IPC SETTINGS +# +# BnetServer.Address +# Description: Determines IP address of battle.net server to connect to. +# Default: 127.0.0.1 +# + +BnetServer.Address = 127.0.0.1 + +# +# BnetServer.Port +# Description: Determines port to use when connecting to battle.net server. +# Default: 1118 +# + +BnetServer.Port = 1118 + +# +################################################################################################### -- cgit v1.2.3 From 863eac9c1a94f202aa5d5008d0b595626ba18951 Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 18 Oct 2014 00:01:00 +0200 Subject: Fixed nopch build --- src/server/bnetserver/Packets/CachePackets.cpp | 1 + src/server/bnetserver/Packets/CachePackets.h | 1 + 2 files changed, 2 insertions(+) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/CachePackets.cpp b/src/server/bnetserver/Packets/CachePackets.cpp index cd5aa05fed6..4679448cbc8 100644 --- a/src/server/bnetserver/Packets/CachePackets.cpp +++ b/src/server/bnetserver/Packets/CachePackets.cpp @@ -15,6 +15,7 @@ * with this program. If not, see . */ +#include "Session.h" #include "CachePackets.h" void Battlenet::Cache::GetStreamItemsRequest::Read() diff --git a/src/server/bnetserver/Packets/CachePackets.h b/src/server/bnetserver/Packets/CachePackets.h index 4d9987a0f0e..a65ab2651c8 100644 --- a/src/server/bnetserver/Packets/CachePackets.h +++ b/src/server/bnetserver/Packets/CachePackets.h @@ -18,6 +18,7 @@ #ifndef CachePackets_h__ #define CachePackets_h__ +#include "ModuleManager.h" #include "PacketsBase.h" namespace Battlenet -- cgit v1.2.3 From 69a17346d477be337c288145ec9da8a019ed040e Mon Sep 17 00:00:00 2001 From: Shauren Date: Sat, 18 Oct 2014 00:26:41 +0200 Subject: More build fixes, everyone loves pch --- src/server/bnetserver/Packets/CachePackets.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/server/bnetserver') diff --git a/src/server/bnetserver/Packets/CachePackets.cpp b/src/server/bnetserver/Packets/CachePackets.cpp index 4679448cbc8..b4fa6c6499d 100644 --- a/src/server/bnetserver/Packets/CachePackets.cpp +++ b/src/server/bnetserver/Packets/CachePackets.cpp @@ -16,6 +16,7 @@ */ #include "Session.h" +#include "Util.h" #include "CachePackets.h" void Battlenet::Cache::GetStreamItemsRequest::Read() -- cgit v1.2.3