aboutsummaryrefslogtreecommitdiff
path: root/src/server/bnetserver
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2014-10-18 17:03:30 +0200
committerShauren <shauren.trinity@gmail.com>2014-10-18 17:03:30 +0200
commit8936723291985d1759a4903901c7a29cc54fdcbf (patch)
tree2ca2331742863ef6318697075aad5ff3f8e76715 /src/server/bnetserver
parent3ee9961ecce2a745134eeefa45b29109a276e49f (diff)
parent4a0be2bffc21e30624122ec5f36d6c8479f83385 (diff)
Merge branch '4.3.4' of https://github.com/TrinityCore/TrinityCore into 6.x
Conflicts: dep/PackageList.txt src/server/bnetserver/Packets/WoWRealmPackets.cpp src/server/bnetserver/Server/Session.cpp
Diffstat (limited to 'src/server/bnetserver')
-rw-r--r--src/server/bnetserver/Authentication/AuthCodes.cpp55
-rw-r--r--src/server/bnetserver/Authentication/AuthCodes.h128
-rw-r--r--src/server/bnetserver/Authentication/BattlenetPacketCrypt.cpp42
-rw-r--r--src/server/bnetserver/Authentication/BattlenetPacketCrypt.h36
-rw-r--r--src/server/bnetserver/CMakeLists.txt121
-rw-r--r--src/server/bnetserver/Main.cpp244
-rw-r--r--src/server/bnetserver/Packets/AchievementPackets.h42
-rw-r--r--src/server/bnetserver/Packets/AuthenticationPackets.cpp325
-rw-r--r--src/server/bnetserver/Packets/AuthenticationPackets.h203
-rw-r--r--src/server/bnetserver/Packets/BitStream.cpp30
-rw-r--r--src/server/bnetserver/Packets/BitStream.h239
-rw-r--r--src/server/bnetserver/Packets/CachePackets.cpp82
-rw-r--r--src/server/bnetserver/Packets/CachePackets.h79
-rw-r--r--src/server/bnetserver/Packets/ChatPackets.h63
-rw-r--r--src/server/bnetserver/Packets/ConnectionPackets.cpp109
-rw-r--r--src/server/bnetserver/Packets/ConnectionPackets.h153
-rw-r--r--src/server/bnetserver/Packets/FriendsPackets.cpp138
-rw-r--r--src/server/bnetserver/Packets/FriendsPackets.h138
-rw-r--r--src/server/bnetserver/Packets/PacketManager.cpp243
-rw-r--r--src/server/bnetserver/Packets/PacketManager.h105
-rw-r--r--src/server/bnetserver/Packets/Packets.h32
-rw-r--r--src/server/bnetserver/Packets/PacketsBase.cpp44
-rw-r--r--src/server/bnetserver/Packets/PacketsBase.h120
-rw-r--r--src/server/bnetserver/Packets/PresencePackets.cpp38
-rw-r--r--src/server/bnetserver/Packets/PresencePackets.h63
-rw-r--r--src/server/bnetserver/Packets/ProfilePackets.h44
-rw-r--r--src/server/bnetserver/Packets/SupportPackets.h34
-rw-r--r--src/server/bnetserver/Packets/WoWRealmPackets.cpp247
-rw-r--r--src/server/bnetserver/Packets/WoWRealmPackets.h209
-rw-r--r--src/server/bnetserver/PrecompiledHeaders/bnetPCH.cpp1
-rw-r--r--src/server/bnetserver/PrecompiledHeaders/bnetPCH.h10
-rw-r--r--src/server/bnetserver/Realms/RealmList.cpp252
-rw-r--r--src/server/bnetserver/Realms/RealmList.h127
-rw-r--r--src/server/bnetserver/Realms/WorldListener.cpp109
-rw-r--r--src/server/bnetserver/Realms/WorldListener.h63
-rw-r--r--src/server/bnetserver/Server/ComponentManager.cpp55
-rw-r--r--src/server/bnetserver/Server/ComponentManager.h61
-rw-r--r--src/server/bnetserver/Server/ModuleManager.cpp58
-rw-r--r--src/server/bnetserver/Server/ModuleManager.h94
-rw-r--r--src/server/bnetserver/Server/Session.cpp1075
-rw-r--r--src/server/bnetserver/Server/Session.h148
-rw-r--r--src/server/bnetserver/Server/SessionManager.cpp70
-rw-r--r--src/server/bnetserver/Server/SessionManager.h88
-rw-r--r--src/server/bnetserver/bnetserver.conf.dist260
-rw-r--r--src/server/bnetserver/bnetserver.icobin0 -> 136606 bytes
-rw-r--r--src/server/bnetserver/bnetserver.rc94
-rw-r--r--src/server/bnetserver/resource.h15
47 files changed, 5986 insertions, 0 deletions
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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AuthCodes.h"
+#include <cstddef>
+
+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 <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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..5b854018d47
--- /dev/null
+++ b/src/server/bnetserver/CMakeLists.txt
@@ -0,0 +1,121 @@
+# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# 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.
+
+########### bnetserver ###############
+
+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}/dep/zmqpp
+ ${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_SOURCE_DIR}/src/server/ipc
+ ${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}
+ ${ZMQ_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
+ ipc
+ shared
+ zmqpp
+ ${MYSQL_LIBRARY}
+ ${OPENSSL_LIBRARIES}
+ ${ZMQ_LIBRARY}
+ ${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..ce90019c011
--- /dev/null
+++ b/src/server/bnetserver/Main.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* @file 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 "ZmqContext.h"
+#include <cstdlib>
+#include <iostream>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/program_options.hpp>
+#include <openssl/opensslv.h>
+#include <openssl/crypto.h>
+
+using boost::asio::ip::tcp;
+using namespace boost::program_options;
+
+#ifndef _TRINITY_BNET_CONFIG
+# define _TRINITY_BNET_CONFIG "bnetserver.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", "<Ctrl-C> 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);
+
+ // bnetserver 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;
+ }
+ }
+
+ 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), worldListenPort);
+
+ // 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();
+
+ sIpcContext->Close();
+
+ sRealmList->Close();
+
+ // 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.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.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.bnetserver", "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1.");
+ synch_threads = 1;
+ }
+
+ if (!LoginDatabase.Open(dbstring, uint8(worker_threads), uint8(synch_threads)))
+ {
+ TC_LOG_ERROR("server.bnetserver", "Cannot connect to database");
+ return false;
+ }
+
+ TC_LOG_INFO("server.bnetserver", "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.bnetserver", "Ping MySQL to keep connection alive");
+ LoginDatabase.KeepAlive();
+
+ _dbPingTimer.expires_from_now(boost::posix_time::minutes(_dbPingInterval));
+ _dbPingTimer.async_wait(KeepDatabaseAliveHandler);
+ }
+}
+
+variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile)
+{
+ options_description all("Allowed options");
+ all.add_options()
+ ("help,h", "print usage message")
+ ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_BNET_CONFIG), "use <arg> as configuration file")
+ ;
+ variables_map variablesMap;
+ try
+ {
+ store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
+ notify(variablesMap);
+ }
+ catch (std::exception& e) {
+ std::cerr << e.what() << "\n";
+ }
+
+ if (variablesMap.count("help")) {
+ std::cout << all << "\n";
+ }
+
+ return variablesMap;
+}
diff --git a/src/server/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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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..f6743a7c2f0
--- /dev/null
+++ b/src/server/bnetserver/Packets/AuthenticationPackets.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AuthenticationPackets.h"
+#include "Session.h"
+#include "Util.h"
+
+void Battlenet::Authentication::ResumeRequest::Read()
+{
+ Program = _stream.ReadFourCC();
+ Platform = _stream.ReadFourCC();
+ Locale = _stream.ReadFourCC();
+
+ Components.resize(_stream.Read<uint32>(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<uint32>(32);
+ }
+
+ Login = _stream.ReadString(9, 3);
+ Region = _stream.Read<uint8>(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)
+{
+ 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<uint32>(3));
+ for (size_t i = 0; i < Modules.size(); ++i)
+ {
+ BitStream*& dataStream = Modules[i];
+ dataStream = new BitStream(_stream.Read<uint32>(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)
+{
+ session->HandleProofResponse(*this);
+}
+
+void Battlenet::Authentication::LogonRequest3::Read()
+{
+ Program = _stream.ReadFourCC();
+ Platform = _stream.ReadFourCC();
+ Locale = _stream.ReadFourCC();
+
+ Components.resize(_stream.Read<uint32>(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<uint32>(32);
+ }
+
+ if (_stream.Read<uint32>(1))
+ Login = _stream.ReadString(9, 3);
+
+ Compatibility = _stream.Read<uint64>(64);
+}
+
+std::string Battlenet::Authentication::LogonRequest3::ToString() const
+{
+ std::ostringstream stream;
+ stream << "Battlenet::Authentication::LogonRequest3 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 << " Login: " << Login;
+
+ stream << " Compatibility: " << Compatibility;
+
+ return stream.str();
+}
+
+void Battlenet::Authentication::LogonRequest3::CallHandler(Session* session)
+{
+ session->HandleLogonRequest(*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<int32>::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);
+ _stream.Write(false, 1); // RaF
+ }
+ 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<int32>::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<int32>::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<int32>::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..bcaa0e72011
--- /dev/null
+++ b/src/server/bnetserver/Packets/AuthenticationPackets.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AuthenticationPackets_h__
+#define AuthenticationPackets_h__
+
+#include "PacketsBase.h"
+#include "ComponentManager.h"
+#include "ModuleManager.h"
+
+namespace Battlenet
+{
+ namespace Authentication
+ {
+ enum Opcode
+ {
+ CMSG_LOGON_REQUEST = 0x0, // Deprecated
+ CMSG_RESUME_REQUEST = 0x1,
+ CMSG_PROOF_RESPONSE = 0x2,
+ CMSG_GENERATE_SINGLE_SIGN_ON_TOKEN_REQUEST_2 = 0x8, // Not implemented
+ CMSG_LOGON_REQUEST_3 = 0x9,
+ CMSG_SINGLE_SIGN_ON_REQUEST_3 = 0xA, // Not implemented
+
+ SMSG_LOGON_RESPONSE = 0x0,
+ SMSG_RESUME_RESPONSE = 0x1,
+ SMSG_PROOF_REQUEST = 0x2,
+ SMSG_PATCH = 0x3, // Not implemented
+ SMSG_AUTHORIZED_LICENSES = 0x4, // Not implemented
+ SMSG_GENERATE_SINGLE_SIGN_ON_TOKEN_REQUEST_2 = 0x8 // Not implemented
+ };
+
+ 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) override;
+
+ std::string Program;
+ std::string Platform;
+ std::string Locale;
+ std::vector<Component> 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) override;
+
+ std::vector<BitStream*> Modules;
+ };
+
+ class LogonRequest3 final : public ClientPacket
+ {
+ public:
+ LogonRequest3(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
+ {
+ ASSERT(header == PacketHeader(CMSG_LOGON_REQUEST_3, AUTHENTICATION) && "Invalid packet header for LogonRequest3");
+ }
+
+ void Read() override;
+ std::string ToString() const override;
+ void CallHandler(Session* session) override;
+
+ std::string Program;
+ std::string Platform;
+ std::string Locale;
+ std::vector<Component> Components;
+ std::string Login;
+ uint64 Compatibility;
+ };
+
+ 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<ModuleInfo*> 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<ModuleInfo*> Modules;
+ void SetAuthResult(AuthResult result);
+ ResponseFailure Result;
+
+ 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<ModuleInfo*> Modules;
+ };
+ }
+}
+
+#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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "BitStream.h"
+
+template<>
+bool Battlenet::BitStream::Read<bool>(uint32 /*bitCount*/)
+{
+ return Read<uint8>(1) != 0;
+}
+
+template<>
+void Battlenet::BitStream::Write<bool>(bool value, uint32 /*bitCount*/)
+{
+ Write<uint8>(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..54c61ab3bbf
--- /dev/null
+++ b/src/server/bnetserver/Packets/BitStream.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef BitStream_h__
+#define BitStream_h__
+
+#include "Common.h"
+#include "ByteConverter.h"
+#include "MessageBuffer.h"
+#include <exception>
+#include <vector>
+#include <type_traits>
+#include <memory>
+
+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<uint32>(bitCount) + baseLength;
+ AlignToNextByte();
+ std::string str(reinterpret_cast<char*>(&_buffer[_readPos >> 3]), len);
+ _readPos += len * 8;
+ return str;
+ }
+
+ std::unique_ptr<uint8[]> ReadBytes(uint32 count)
+ {
+ AlignToNextByte();
+ if (_readPos + count * 8 > _writePos)
+ throw BitStreamPositionException(true, count * 8, _readPos, _writePos);
+
+ std::unique_ptr<uint8[]> buf(new uint8[count]);
+ memcpy(buf.get(), &_buffer[_readPos >> 3], count);
+ _readPos += count * 8;
+ return buf;
+ }
+
+ float ReadFloat()
+ {
+ uint32 val = Read<uint32>(32);
+ return *reinterpret_cast<float*>(&val);
+ }
+
+ std::string ReadFourCC()
+ {
+ uint32 fcc = Read<uint32>(32);
+ EndianConvertReverse(fcc);
+ size_t len = 4;
+ while (!(fcc & 0xFF))
+ {
+ fcc >>= 8;
+ --len;
+ }
+
+ return std::string(reinterpret_cast<char*>(&fcc), len);
+ }
+
+ template<typename T>
+ T Read(uint32 bitCount)
+ {
+ static_assert(std::is_integral<T>::value || std::is_enum<T>::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<T>(ret);
+ }
+
+ void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0)
+ {
+ Write(str.length() + baseLength, bitCount);
+ WriteBytes(str.c_str(), str.length());
+ }
+
+ template<typename T>
+ 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<uint32*>(&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<typename T>
+ void Write(T value, uint32 bitCount)
+ {
+ static_assert(std::is_integral<T>::value || std::is_enum<T>::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;
+ }
+ }
+
+ 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; }
+
+ // 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;
+ std::vector<uint8> _buffer;
+ };
+
+ template<>
+ bool BitStream::Read<bool>(uint32 bitCount);
+
+ template<>
+ void BitStream::Write<bool>(bool value, uint32 bitCount);
+}
+
+#endif // BitStream_h__
diff --git a/src/server/bnetserver/Packets/CachePackets.cpp b/src/server/bnetserver/Packets/CachePackets.cpp
new file mode 100644
index 00000000000..deacfd34065
--- /dev/null
+++ b/src/server/bnetserver/Packets/CachePackets.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Session.h"
+#include "Util.h"
+#include "CachePackets.h"
+
+void Battlenet::Cache::GetStreamItemsRequest::Read()
+{
+ _stream.WriteSkip(31);
+ Index = _stream.Read<uint32>(32);
+ ReferenceTime = _stream.Read<int32>(32) - std::numeric_limits<int32>::min();
+ _stream.Read<bool>(1); // StreamDirection
+ _stream.Read<uint8>(6); // Module count, always 0
+ Locale = _stream.ReadFourCC();
+ if (_stream.Read<bool>(1))
+ {
+ ItemName = _stream.ReadFourCC();
+ Channel = _stream.ReadFourCC();
+ }
+ else
+ _stream.Read<uint16>(16);
+}
+
+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(1, 16);
+ _stream.Write(Index, 32);
+ _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.WriteSkip(27);
+ _stream.WriteBytes(info->Data, 4);
+ }
+}
+
+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
new file mode 100644
index 00000000000..a65ab2651c8
--- /dev/null
+++ b/src/server/bnetserver/Packets/CachePackets.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CachePackets_h__
+#define CachePackets_h__
+
+#include "ModuleManager.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
+ 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
+ };
+
+ 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<ModuleInfo*> Modules;
+ };
+ }
+}
+
+#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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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..3b7a9949552
--- /dev/null
+++ b/src/server/bnetserver/Packets/ConnectionPackets.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Session.h"
+#include "ConnectionPackets.h"
+
+std::string Battlenet::Connection::Ping::ToString() const
+{
+ return "Battlenet::Connection::Ping";
+}
+
+void Battlenet::Connection::Ping::CallHandler(Session* session)
+{
+ session->HandlePing(*this);
+}
+
+std::string Battlenet::Connection::EnableEncryption::ToString() const
+{
+ return "Battlenet::Connection::EnableEncryption";
+}
+
+void Battlenet::Connection::EnableEncryption::CallHandler(Session* session)
+{
+ session->HandleEnableEncryption(*this);
+}
+
+std::string Battlenet::Connection::LogoutRequest::ToString() const
+{
+ return "Battlenet::Connection::LogoutRequest";
+}
+
+void Battlenet::Connection::LogoutRequest::CallHandler(Session* session)
+{
+ session->HandleLogoutRequest(*this);
+}
+
+void Battlenet::Connection::DisconnectRequest::Read()
+{
+ Timeout = _stream.Read<uint16>(16);
+ Tick = _stream.Read<uint32>(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()
+{
+ Packets.resize(_stream.Read<uint8>(6));
+ for (size_t i = 0; i < Packets.size(); ++i)
+ {
+ PacketInfo& info = Packets[i];
+ info.CommandName = _stream.ReadFourCC();
+ info.Timestamp = _stream.Read<uint32>(32);
+ info.Size = _stream.Read<uint32>(16);
+ info.Channel = _stream.ReadFourCC();
+ info.LayerId = _stream.Read<uint32>(16);
+ }
+
+ Reason = _stream.Read<ClosingReason>(4);
+ _stream.ReadBytes(_stream.Read<uint8>(8)); // BadData
+
+ if (_stream.Read<bool>(1)) // HasHeader
+ {
+ Header.Opcode = _stream.Read<uint32>(6);
+ if (_stream.Read<bool>(1))
+ Header.Channel = _stream.Read<int32>(4);
+ }
+
+ Now = _stream.Read<time_t>(32);
+}
+
+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
new file mode 100644
index 00000000000..8572cd5d854
--- /dev/null
+++ b/src/server/bnetserver/Packets/ConnectionPackets.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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 handled
+ CMSG_CONNECTION_CLOSING = 0x9,
+
+ 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) 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) 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) 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<PacketInfo> Packets;
+ time_t Now;
+ };
+
+ 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..2659ec6204f
--- /dev/null
+++ b/src/server/bnetserver/Packets/FriendsPackets.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Session.h"
+#include "FriendsPackets.h"
+
+void Battlenet::Friends::GetFriendsOfFriend::Read()
+{
+ uint8 unk = _stream.Read<uint8>(2);
+ uint32 unk1 = _stream.Read<uint32>(32);
+}
+
+std::string Battlenet::Friends::GetFriendsOfFriend::ToString() const
+{
+ return "Battlenet::Friends::GetFriendsOfFriend";
+}
+
+void Battlenet::Friends::SocialNetworkCheckConnected::Read()
+{
+ SocialNetworkId = _stream.Read<uint32>(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::RealIdFriendInvite::Read()
+{
+ _stream.Read<uint32>(32);
+ uint8 type = _stream.Read<uint8>(3);
+
+ switch (type)
+ {
+ case 0:
+ {
+ _stream.Read<uint32>(32); // Presence Id?
+ break;
+ }
+ case 1: // GameAccount?
+ {
+ _stream.Read<uint8>(8);
+ _stream.Read<uint32>(32);
+ _stream.Read<uint32>(32);
+ uint8 size = _stream.Read<uint8>(7); // Only if *(a1 + 16) <= 0x64
+ _stream.ReadBytes(size);
+ break;
+ }
+ case 2:
+ Email = _stream.ReadString(9, 3);
+ break;
+ case 3:
+ {
+ _stream.Read<uint32>(32);
+ break;
+ }
+ case 4:
+ {
+ _stream.Read<uint64>(64);
+ _stream.Read<uint32>(32);
+ break;
+ }
+ }
+
+ _stream.Read<uint8>(1);
+
+ if (_stream.Read<uint8>(1))
+ Message = _stream.ReadString(9);
+
+ _stream.Read<uint32>(32);
+}
+
+std::string Battlenet::Friends::RealIdFriendInvite::ToString() const
+{
+ return "Battlenet::Friends::RealIdFriendInvite Mail: " + Email + " Message: " + Message;
+}
+
+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);
+ }
+}
+
+std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() const
+{
+ return "Battlenet::Friends::SocialNetworkCheckConnectedResult";
+}
+
+void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write()
+{
+ _stream.WriteSkip(23);
+ _stream.Write(Result, 16);
+ _stream.Write(SocialNetworkId, 32);
+}
diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h
new file mode 100644
index 00000000000..ea4d6d2ea92
--- /dev/null
+++ b/src/server/bnetserver/Packets/FriendsPackets.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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, // 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
+
+ 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, // 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 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;
+ };
+
+ 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) override;
+
+ uint32 SocialNetworkId;
+ };
+
+ 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
+ {
+ public:
+ FriendInviteResult() : ServerPacket(PacketHeader(SMSG_FRIEND_INVITE_RESULT, FRIENDS))
+ {
+ }
+
+ void Write() override;
+ std::string ToString() 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 SocialNetworkCheckConnectedResult final : public ServerPacket
+ {
+ public:
+ 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;
+ };
+ }
+}
+
+#endif // FriendsPackets_h__
diff --git a/src/server/bnetserver/Packets/PacketManager.cpp b/src/server/bnetserver/Packets/PacketManager.cpp
new file mode 100644
index 00000000000..cbfd0c8b2b6
--- /dev/null
+++ b/src/server/bnetserver/Packets/PacketManager.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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<packetClass>(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_NAME(PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION), "Authentication::LogonRequest3");
+ REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_RESUME_REQUEST, AUTHENTICATION), Authentication::ResumeRequest);
+ REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_PROOF_RESPONSE, AUTHENTICATION), Authentication::ProofResponse);
+ REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_LOGON_REQUEST_3, AUTHENTICATION), Authentication::LogonRequest3);
+
+ 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(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);
+}
+
+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(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(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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PacketManager_h__
+#define PacketManager_h__
+
+#include "Packets.h"
+#include <map>
+#include <type_traits>
+
+template<typename T>
+struct has_call_handler
+{
+ template<typename U, void(U::*)(Battlenet::Session*)> struct test_has_call_handler { };
+ template<typename U> static char Test(test_has_call_handler<U, &U::CallHandler>*);
+ template<typename U> static int Test(...);
+ static const bool value = sizeof(Test<T>(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<class PacketType>
+ static ClientPacket* New(PacketHeader const& header, BitStream& stream)
+ {
+ return new PacketType(header, stream);
+ }
+
+ void RegisterPacketName(std::map<PacketHeader, PacketInfo>& packetTable, PacketHeader const& header, char const* name)
+ {
+ PacketInfo& info = packetTable[header];
+ info.Constructor = nullptr;
+ info.Name = name;
+ info.HasHandler = false;
+ }
+
+ template<class PacketType>
+ void RegisterClientPacket(PacketHeader const& header, char const* name)
+ {
+ PacketInfo& info = _clientPacketTable[header];
+ info.Constructor = &New<PacketType>;
+ info.Name = name;
+ info.HasHandler = has_call_handler<PacketType>::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<PacketHeader, PacketInfo> _clientPacketTable;
+ std::map<PacketHeader, PacketInfo> _serverPacketTable;
+ };
+}
+
+#define sPacketManager Battlenet::PacketManager::Instance()
+
+#endif // PacketManager_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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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..fd3bebcf471
--- /dev/null
+++ b/src/server/bnetserver/Packets/PacketsBase.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Packets.h"
+#include "Session.h"
+#include <sstream>
+
+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;
+}
+
+void Battlenet::ClientPacket::CallHandler(Session* session)
+{
+ session->LogUnhandledPacket(GetHeader());
+}
diff --git a/src/server/bnetserver/Packets/PacketsBase.h b/src/server/bnetserver/Packets/PacketsBase.h
new file mode 100644
index 00000000000..0f86621d6a6
--- /dev/null
+++ b/src/server/bnetserver/Packets/PacketsBase.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PacketsBase_h__
+#define PacketsBase_h__
+
+#include "AuthCodes.h"
+#include "BitStream.h"
+#include "Define.h"
+#include "Errors.h"
+#include <string>
+#include <boost/asio/ip/tcp.hpp>
+
+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 client packets."); }
+ virtual void CallHandler(Session* session);
+ };
+
+ 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..b72bf8daca8
--- /dev/null
+++ b/src/server/bnetserver/Packets/PresencePackets.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Session.h"
+#include "PresencePackets.h"
+
+void Battlenet::Presence::UpdateRequest::Read()
+{
+
+}
+
+std::string Battlenet::Presence::UpdateRequest::ToString() const
+{
+ return "Battlenet::Presence::UpdateRequest";
+}
+
+void Battlenet::Presence::StatisticSubscribe::Read()
+{
+}
+
+std::string Battlenet::Presence::StatisticSubscribe::ToString() const
+{
+ return "Battlenet::Presence::StatisticSubscribe";
+}
diff --git a/src/server/bnetserver/Packets/PresencePackets.h b/src/server/bnetserver/Packets/PresencePackets.h
new file mode 100644
index 00000000000..45b8f3e0e82
--- /dev/null
+++ b/src/server/bnetserver/Packets/PresencePackets.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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;
+ };
+
+ 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;
+ };
+ }
+}
+
+#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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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..714c43b8eb4
--- /dev/null
+++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "WoWRealmPackets.h"
+#include "Session.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/asio/ip/address.hpp>
+
+std::string Battlenet::WoWRealm::ListSubscribeRequest::ToString() const
+{
+ return "Battlenet::WoWRealm::ListSubscribeRequest";
+}
+
+void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session)
+{
+ session->HandleListSubscribeRequest(*this);
+}
+
+std::string Battlenet::WoWRealm::ListUnsubscribe::ToString() const
+{
+ return "Battlenet::WoWRealm::ListUnsubscribe";
+}
+
+void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session)
+{
+ session->HandleListUnsubscribe(*this);
+}
+
+void Battlenet::WoWRealm::JoinRequestV2::Read()
+{
+ Realm.Battlegroup = _stream.Read<uint8>(8);
+ Realm.Index = _stream.Read<uint32>(32);
+ Realm.Region = _stream.Read<uint8>(8);
+ ClientSeed = _stream.Read<uint32>(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)
+ 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.Region, 8);
+ _stream.Write(0, 12);
+ _stream.Write(entry.Realm.Battlegroup, 8);
+ _stream.Write(entry.Realm.Index, 32);
+ _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(Timezone, 32);
+ _stream.WriteFloat(Population);
+ _stream.Write(Lock, 8);
+ _stream.Write(0, 19);
+ _stream.Write(Type + -std::numeric_limits<int32>::min(), 32);
+ _stream.WriteString(Name, 10);
+ _stream.Write(!Version.empty(), 1);
+ if (!Version.empty())
+ {
+ _stream.WriteString(Version, 5);
+ _stream.Write(Id.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.Write(Flags, 8);
+ }
+
+ _stream.Write(Id.Region, 8);
+ _stream.Write(0, 12);
+ _stream.Write(Id.Battlegroup, 8);
+ _stream.Write(Id.Index, 32);
+}
+
+std::string Battlenet::WoWRealm::ListUpdate::ToString() const
+{
+ std::ostringstream stream;
+ 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;
+ }
+ else
+ stream << " Delete realm [Region: " << uint32(Id.Region) << " Battlegroup : " << uint32(Id.Battlegroup) << " Index : " << Id.Index << "]";
+
+ return stream.str().c_str();
+}
+
+void Battlenet::WoWRealm::ToonReady::Write()
+{
+ _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(21);
+ _stream.Write(0, 64); // Unknown
+ _stream.Write(0, 32); // Unknown
+ _stream.Write(Guid, 64);
+ _stream.Write(realmAddress, 32);
+ _stream.Write(Realm.Region, 8);
+ _stream.WriteFourCC(Game);
+}
+
+std::string Battlenet::WoWRealm::ToonReady::ToString() const
+{
+ std::ostringstream stream;
+ stream << "Battlenet::WoWRealm::ToonReady" << " Game: " << Game
+ << ", Region: " << uint32(Realm.Region) << ", Battlegroup: " << uint32(Realm.Battlegroup) << ", Index: " << Realm.Index
+ << ", Guid: " << Guid << ", Name: " << Name;
+
+ return stream.str().c_str();
+}
+
+void Battlenet::WoWRealm::JoinResponseV2::Write()
+{
+ _stream.Write(0, 27);
+ _stream.Write(Response, 1);
+ if (Response == SUCCESS)
+ {
+ _stream.Write(ServerSeed, 32);
+ _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);
+ }
+
+ _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);
+ }
+ }
+ 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<std::string>(addr);
+
+ for (tcp::endpoint const& addr : IPv6)
+ stream << std::endl << "Battlenet::WoWRealm::JoinResponseV2::Address " << boost::lexical_cast<std::string>(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..b411c63100a
--- /dev/null
+++ b/src/server/bnetserver/Packets/WoWRealmPackets.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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,
+ 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) 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) 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) 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<CharacterCountEntry> CharacterCounts;
+ std::vector<ServerPacket*> 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)
+ {
+ }
+
+ 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;
+ RealmId Id;
+ };
+
+ 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 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:
+ enum Result
+ {
+ SUCCESS = 0,
+ FAILURE = 1
+ };
+
+ JoinResponseV2() : ServerPacket(PacketHeader(SMSG_JOIN_RESPONSE_V2, WOWREALM)),
+ Response(SUCCESS), ResponseCode(26), ServerSeed(0)
+ {
+ }
+
+ void Write() override;
+ std::string ToString() const override;
+
+ Result Response;
+ uint8 ResponseCode;
+ uint32 ServerSeed;
+ std::vector<tcp::endpoint> IPv4;
+ std::vector<tcp::endpoint> 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..cc7e1d492a8
--- /dev/null
+++ b/src/server/bnetserver/Realms/RealmList.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "SessionManager.h"
+#include "Util.h"
+#include "Commands.h"
+#include "RealmList.h"
+#include <boost/asio/ip/tcp.hpp>
+
+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
+{
+ 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 bnetserver 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() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr), _worldListener(nullptr)
+{
+}
+
+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, uint16 worldListenPort)
+{
+ _updateInterval = updateInterval;
+ _updateTimer = new boost::asio::deadline_timer(ioService);
+ _resolver = new boost::asio::ip::tcp::resolver(ioService);
+
+ // 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<typename FieldType>
+inline void UpdateField(FieldType& out, FieldType const& in, bool& changed)
+{
+ if (out != in)
+ {
+ out = in;
+ changed = true;
+ }
+}
+
+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)
+{
+ // Create new if not exist or update existed
+ Realm& realm = _realms[id];
+
+ realm.Keep = true;
+
+ 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(boost::system::error_code const& error)
+{
+ if (error)
+ return;
+
+ TC_LOG_DEBUG("realmlist", "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();
+ 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("realmlist", "Could not resolve address %s", fields[2].GetString().c_str());
+ continue;
+ }
+
+ 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("realmlist", "Could not resolve address %s", fields[3].GetString().c_str());
+ continue;
+ }
+
+ 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("realmlist", "Could not resolve address %s", fields[4].GetString().c_str());
+ continue;
+ }
+
+ 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 realmId = fields[0].GetUInt32();
+ uint32 build = fields[11].GetUInt32();
+ uint8 region = fields[12].GetUInt8();
+ uint8 battlegroup = fields[13].GetUInt8();
+
+ Battlenet::RealmId id{ region, battlegroup, realmId, build };
+
+ UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone,
+ (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
+
+ 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("realmlist", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what());
+ ASSERT(false);
+ }
+ }
+ while (result->NextRow());
+ }
+
+ std::vector<Realm const*> updatedRealms;
+ std::vector<Battlenet::RealmId> deletedRealms;
+
+ for (RealmMap::value_type& pair : _realms)
+ {
+ if (pair.second.Updated)
+ updatedRealms.push_back(&pair.second);
+ else if (!pair.second.Keep)
+ deletedRealms.push_back(pair.first);
+
+ pair.second.Updated = false;
+ pair.second.Keep = false;
+ }
+
+ 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 = _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
new file mode 100644
index 00000000000..dc78a00dfdd
--- /dev/null
+++ b/src/server/bnetserver/Realms/RealmList.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _REALMLIST_H
+#define _REALMLIST_H
+
+#include "Common.h"
+#include "WorldListener.h"
+#include <boost/asio/ip/address.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/deadline_timer.hpp>
+
+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
+};
+
+#pragma pack(push, 1)
+
+namespace Battlenet
+{
+ struct RealmHandle;
+
+ 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;
+ }
+
+ RealmId& operator=(RealmHandle const& handle);
+ };
+}
+
+#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<Battlenet::RealmId, Realm> RealmMap;
+
+ static RealmList* instance()
+ {
+ static RealmList instance;
+ return &instance;
+ }
+
+ ~RealmList();
+
+ 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;
+
+private:
+ RealmList();
+
+ 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 _realms;
+ uint32 _updateInterval;
+ boost::asio::deadline_timer* _updateTimer;
+ boost::asio::ip::tcp::resolver* _resolver;
+ WorldListener* _worldListener;
+};
+
+#define sRealmList RealmList::instance()
+#endif
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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef 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/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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ComponentManager_h__
+#define ComponentManager_h__
+
+#include "Define.h"
+#include <cstring>
+#include <string>
+#include <set>
+
+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<Component*> _components;
+ std::set<std::string> _programs;
+ std::set<std::string> _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..05cee2ff42e
--- /dev/null
+++ b/src/server/bnetserver/Server/ModuleManager.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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 };
+ if (!_modules.count(key))
+ return nullptr;
+
+ 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 <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ModuleManager_h__
+#define ModuleManager_h__
+
+#include "Define.h"
+#include <cstring>
+#include <string>
+#include <map>
+
+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<ModuleKey, ModuleInfo*> _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..edd00e5db2d
--- /dev/null
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -0,0 +1,1075 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "AuthCodes.h"
+#include "BitStream.h"
+#include "PacketManager.h"
+#include "SessionManager.h"
+#include "Database/DatabaseEnv.h"
+#include "HmacHash.h"
+#include "Log.h"
+#include "RealmList.h"
+#include "SHA256.h"
+#include <map>
+
+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), _subscribedToRealmListUpdates(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);
+}
+
+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(PacketHeader const& header)
+{
+ TC_LOG_DEBUG("session.packets", "%s Received unhandled packet %s", GetClientInfo().c_str(), sPacketManager.GetClientPacketName(header));
+}
+
+void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& logonRequest)
+{
+ // 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(LOGIN_BANNED);
+ AsyncWrite(logonResponse);
+ TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort());
+ return;
+ }
+
+ if (logonRequest.Program != "WoW")
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
+ AsyncWrite(logonResponse);
+ return;
+ }
+
+ if (!sComponentMgr->HasPlatform(logonRequest.Platform))
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_INVALID_OS);
+ AsyncWrite(logonResponse);
+ return;
+ }
+
+ if (!sComponentMgr->HasPlatform(logonRequest.Locale))
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE);
+ AsyncWrite(logonResponse);
+ return;
+ }
+
+ for (Component const& component : logonRequest.Components)
+ {
+ if (!sComponentMgr->HasComponent(&component))
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ if (!sComponentMgr->HasProgram(component.Program))
+ logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
+ else if (!sComponentMgr->HasPlatform(component.Platform))
+ logonResponse->SetAuthResult(AUTH_INVALID_OS);
+ else
+ {
+ if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build))
+ logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION);
+ else
+ logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON);
+ }
+
+ AsyncWrite(logonResponse);
+ return;
+ }
+
+ if (component.Platform == "base")
+ _build = component.Build;
+ }
+
+ _accountName = logonRequest.Login;
+ _locale = logonRequest.Locale;
+ _os = logonRequest.Platform;
+
+ Utf8ToUpperOnlyLatin(_accountName);
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO);
+ stmt->setString(0, _accountName);
+
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+ if (!result)
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
+ AsyncWrite(logonResponse);
+ 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("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)
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED);
+ AsyncWrite(logonResponse);
+ return;
+ }
+ }
+ else
+ {
+ 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("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());
+ 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("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();
+ logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED);
+ AsyncWrite(logonResponse);
+ 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(LOGIN_BANNED);
+ AsyncWrite(logonResponse);
+ TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str());
+ return;
+ }
+ else
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(LOGIN_SUSPENDED);
+ AsyncWrite(logonResponse);
+ TC_LOG_DEBUG("session", "'%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* proofRequest = new Authentication::ProofRequest();
+ proofRequest->Modules.push_back(password);
+ // if has authenticator, send Token module
+ proofRequest->Modules.push_back(thumbprint);
+ AsyncWrite(proofRequest);
+}
+
+void Battlenet::Session::HandleResumeRequest(Authentication::ResumeRequest const& resumeRequest)
+{
+ _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, resumeRequest.GameAccountName);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+ if (!result)
+ {
+ Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
+ resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
+ AsyncWrite(resumeResponse);
+ return;
+ }
+
+ Field* fields = result->Fetch();
+
+ _accountId = fields[0].GetUInt32();
+ K.SetHexStr(fields[1].GetString().c_str());
+ _gameAccountId = fields[2].GetUInt32();
+ _gameAccountName = resumeRequest.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* proofRequest = new Authentication::ProofRequest();
+ proofRequest->Modules.push_back(thumbprint);
+ proofRequest->Modules.push_back(resume);
+ AsyncWrite(proofRequest);
+}
+
+void Battlenet::Session::HandleProofResponse(Authentication::ProofResponse const& proofResponse)
+{
+ if (_modulesWaitingForData.size() < proofResponse.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 < proofResponse.Modules.size(); ++i)
+ {
+ if (!(this->*(ModuleHandlers[_modulesWaitingForData.front()]))(proofResponse.Modules[i], &response))
+ break;
+
+ _modulesWaitingForData.pop();
+ }
+
+ if (!response)
+ {
+ response = new Authentication::LogonResponse();
+ static_cast<Authentication::LogonResponse*>(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::HandleConnectionClosing(Connection::ConnectionClosing const& /*connectionClosing*/)
+{
+}
+
+void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/)
+{
+ WoWRealm::ListSubscribeResponse* listSubscribeResponse = 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();
+ 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::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->Flags & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE))
+ {
+ joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE;
+ AsyncWrite(joinResponse);
+ return;
+ }
+
+ joinResponse->ServerSeed = uint32(rand32());
+
+ uint8 sessionKey[40];
+ HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get());
+ hmac.UpdateData((uint8*)"WoW\0", 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*)&joinResponse->ServerSeed, 4);
+ hmac2.UpdateData((uint8*)&joinRequest.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);
+
+ joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port);
+ if (realm->ExternalAddress != realm->LocalAddress)
+ 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::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))
+ 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()));
+ _crypt.DecryptRecv(stream.GetBuffer(), stream.GetSize());
+
+ while (!stream.IsRead())
+ {
+ try
+ {
+ PacketHeader header;
+ header.Opcode = stream.Read<uint32>(6);
+ if (stream.Read<bool>(1))
+ header.Channel = stream.Read<int32>(4);
+
+ if (header.Channel != AUTHENTICATION && !_authed)
+ {
+ TC_LOG_DEBUG("session.packets", "%s Received not allowed %s. Client has not authed yet.", GetClientInfo().c_str(), header.ToString().c_str());
+ CloseSocket();
+ return;
+ }
+
+ if (ClientPacket* packet = sPacketManager.CreateClientPacket(header, stream))
+ {
+ 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());
+ break;
+ }
+
+ stream.AlignToNextByte();
+ }
+ catch (BitStreamPositionException const& e)
+ {
+ TC_LOG_ERROR("session.packets", "%s Exception thrown during packet processing %s", GetClientInfo().c_str(), e.what());
+ CloseSocket();
+ return;
+ }
+ }
+
+ GetReadBuffer().Resize(size_t(BufferSizes::Read));
+ AsyncRead();
+}
+
+void Battlenet::Session::Start()
+{
+ TC_LOG_TRACE("session", "Accepted connection from %s", GetRemoteIpAddress().to_string().c_str());
+ AsyncRead();
+}
+
+void Battlenet::Session::AsyncWrite(ServerPacket* packet)
+{
+ if (!IsOpen())
+ {
+ delete packet;
+ return;
+ }
+
+ TC_LOG_DEBUG("session.packets", "%s Sending %s", GetClientInfo().c_str(), PacketToStringHelper(packet).c_str());
+
+ packet->Write();
+
+ MessageBuffer buffer;
+ buffer.Write(packet->GetData(), packet->GetSize());
+ delete packet;
+
+ std::unique_lock<std::mutex> 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
+ ReplaceResponse(response, logonResponse);
+ return false;
+ }
+
+ if (dataStream->Read<uint8>(8) != 2) // State
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
+ ReplaceResponse(response, logonResponse);
+ 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
+ ReplaceResponse(response, logonResponse);
+ 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
+ ReplaceResponse(response, logonResponse);
+ 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* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
+ ReplaceResponse(response, logonResponse);
+ 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* proofRequest = new Authentication::ProofRequest();
+ proofRequest->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);
+ proofRequest->Modules.push_back(selectGameAccount);
+ _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT);
+ }
+ else
+ {
+ if (fields[4].GetBool())
+ {
+ delete proofRequest;
+
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ if (fields[2].GetUInt32() == fields[3].GetUInt32())
+ {
+ logonResponse->SetAuthResult(LOGIN_BANNED);
+ 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("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
+ }
+
+ ReplaceResponse(response, logonResponse);
+ return false;
+ }
+
+ _gameAccountId = fields[0].GetUInt32();
+ _gameAccountName = fields[1].GetString();
+
+ proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
+ _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
+ }
+
+ ReplaceResponse(response, proofRequest);
+ return true;
+}
+
+bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response)
+{
+ if (dataStream->Read<uint8>(8) != 1)
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
+ ReplaceResponse(response, logonResponse);
+ return false;
+ }
+
+ dataStream->Read<uint8>(8);
+ std::string account = dataStream->ReadString(8);
+ if (account.empty())
+ {
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
+ ReplaceResponse(response, logonResponse);
+ 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* logonResponse = new Authentication::LogonResponse();
+ if (fields[2].GetUInt32() == fields[3].GetUInt32())
+ {
+ logonResponse->SetAuthResult(LOGIN_BANNED);
+ 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("session", "'%s:%d' [Battlenet::SelectGameAccount] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountName.c_str());
+ }
+
+ ReplaceResponse(response, logonResponse);
+ return false;
+ }
+
+ _gameAccountId = fields[0].GetUInt32();
+ _gameAccountName = fields[1].GetString();
+
+ Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest();
+ proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint"));
+ ReplaceResponse(response, proofRequest);
+
+ _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT);
+ return true;
+}
+
+bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response)
+{
+ Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
+ if (dataStream->Read<uint8>(8) == 1)
+ {
+ 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))
+ logonResponse->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
+ logonResponse->SetAuthResult(AUTH_BAD_VERSION_HASH);
+
+ ReplaceResponse(response, logonResponse);
+ return true;
+}
+
+bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket** response)
+{
+ if (dataStream->Read<uint8>(8) != 1)
+ {
+ Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
+ resumeResponse->SetAuthResult(AUTH_CORRUPTED_MODULE);
+ ReplaceResponse(response, resumeResponse);
+ return false;
+ }
+
+ static uint8 const ResumeClient = 0;
+ static uint8 const ResumeServer = 1;
+
+ std::unique_ptr<uint8[]> clientChallenge = dataStream->ReadBytes(16);
+ std::unique_ptr<uint8[]> clientProof = dataStream->ReadBytes(32);
+ std::unique_ptr<uint8[]> serverChallenge = _reconnectProof.AsByteArray(16);
+ std::unique_ptr<uint8[]> 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("session", "[Battlenet::Resume] Invalid proof!");
+ Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
+ resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
+ ReplaceResponse(response, resumeResponse);
+ 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* resumeResponse = new Authentication::ResumeResponse();
+ resumeResponse->Modules.push_back(resume);
+ ReplaceResponse(response, resumeResponse);
+ _authed = true;
+ sSessionMgr.AddSession(this);
+ return true;
+}
+
+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);
+ return false;
+}
+
+void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& 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;
+}
+
+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
new file mode 100644
index 00000000000..ded5170ae32
--- /dev/null
+++ b/src/server/bnetserver/Server/Session.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef Session_h__
+#define Session_h__
+
+#include "Packets.h"
+#include "BattlenetPacketCrypt.h"
+#include "Socket.h"
+#include "BigNumber.h"
+#include <memory>
+#include <boost/asio/ip/tcp.hpp>
+
+struct Realm;
+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<Session>
+ {
+ typedef Socket<Session> BattlenetSocket;
+
+ public:
+ explicit Session(tcp::socket&& socket);
+ ~Session();
+
+ void LogUnhandledPacket(PacketHeader const& header);
+
+ // Authentication
+ void HandleLogonRequest(Authentication::LogonRequest3 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);
+ void HandleConnectionClosing(Connection::ConnectionClosing const& connectionClosing);
+
+ // 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);
+
+ // Cache
+ void HandleGetStreamItemsRequest(Cache::GetStreamItemsRequest const& getStreamItemsRequest);
+
+ void Start() override;
+
+ void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms);
+
+ uint32 GetAccountId() const { return _accountId; }
+ uint32 GetGameAccountId() const { return _gameAccountId; }
+
+ bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; }
+
+ 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);
+
+ WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const;
+ std::string GetClientInfo() const;
+
+ 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<ModuleType> _modulesWaitingForData;
+
+ PacketCrypt _crypt;
+ bool _authed;
+ bool _subscribedToRealmListUpdates;
+ };
+
+}
+
+#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..9e5836dab8d
--- /dev/null
+++ b/src/server/bnetserver/Server/SessionManager.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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::Session>* Battlenet::SessionManager::CreateThreads() const
+{
+ return new NetworkThread<Session>[GetNetworkThreadCount()];
+}
+
+void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock)
+{
+ sSessionMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
+}
+
+void Battlenet::SessionManager::AddSession(Session* session)
+{
+ std::unique_lock<boost::shared_mutex> lock(_sessionMutex);
+ _sessions[{ session->GetAccountId(), session->GetGameAccountId() }] = session;
+ _sessionsByAccountId[session->GetAccountId()].push_back(session);
+}
+
+void Battlenet::SessionManager::RemoveSession(Session* session)
+{
+ std::unique_lock<boost::shared_mutex> lock(_sessionMutex);
+ _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::Session*> Battlenet::SessionManager::GetSessions(uint32 accountId) const
+{
+ std::list<Session*> 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
new file mode 100644
index 00000000000..08ca5ce2b4e
--- /dev/null
+++ b/src/server/bnetserver/Server/SessionManager.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SessionManager_h__
+#define SessionManager_h__
+
+#include "Session.h"
+#include "SocketMgr.h"
+#include <boost/thread/locks.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+namespace Battlenet
+{
+#pragma pack(push, 1)
+
+ struct SessionInfo
+ {
+ uint32 AccountId;
+ uint32 GameAccountId;
+
+ bool operator<(SessionInfo const& right) const
+ {
+ return memcmp(this, &right, sizeof(SessionInfo)) < 0;
+ }
+ };
+
+#pragma pack(pop)
+
+ class SessionManager : SocketMgr<Session>
+ {
+ typedef SocketMgr<Session> BaseSocketMgr;
+ typedef std::map<SessionInfo, Session*> SessionMap;
+ typedef std::map<uint32, std::list<Session*>> SessionByAccountMap;
+
+ 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*/);
+
+ Session* GetSession(uint32 accountId, uint32 gameAccountId) const;
+ std::list<Session*> GetSessions(uint32 accountId) const;
+
+ template<typename Iterator>
+ void LockedForEach(Iterator iterator)
+ {
+ boost::shared_lock<boost::shared_mutex> lock(_sessionMutex);
+ for (SessionMap::value_type const& pair : _sessions)
+ iterator(pair.second);
+ }
+
+ protected:
+ NetworkThread<Session>* CreateThreads() const override;
+
+ private:
+ static void OnSocketAccept(tcp::socket&& sock);
+
+ SessionMap _sessions;
+ SessionByAccountMap _sessionsByAccountId;
+ boost::shared_mutex _sessionMutex;
+ };
+}
+
+#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..102ddb9906a
--- /dev/null
+++ b/src/server/bnetserver/bnetserver.conf.dist
@@ -0,0 +1,260 @@
+###############################################
+# 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
+
+#
+# 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.
+# 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: 10
+# 0 - (Disabled)
+
+RealmsStateUpdateDelay = 10
+
+#
+# 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.Bnet=2,2,0,Bnet.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 Bnet
+Logger.realmlist=3,Console Bnet
+Logger.session=3,Console Bnet
+Logger.session.packets=3,Console Bnet
+
+#
+###################################################################################################
diff --git a/src/server/bnetserver/bnetserver.ico b/src/server/bnetserver/bnetserver.ico
new file mode 100644
index 00000000000..da318f48a8c
--- /dev/null
+++ b/src/server/bnetserver/bnetserver.ico
Binary files 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 <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "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