diff options
author | Shauren <shauren.trinity@gmail.com> | 2014-11-09 00:37:33 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2014-11-09 00:37:33 +0100 |
commit | bacc90b6baa34e6a194c93e5a7860d4041f08af7 (patch) | |
tree | de99e93636f809f1179cb7336af307b70cae13ec /src/server | |
parent | 6c1ca104edd07adf99e7946fa9b46ce4a849bd5d (diff) |
Core/NetworkIO: Added second connection to WorldSession, handle AuthContinuedSession and enabled ConnectTo and ResumeComms
Diffstat (limited to 'src/server')
30 files changed, 706 insertions, 247 deletions
diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index 5b854018d47..5d1edef5b81 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -55,6 +55,7 @@ include_directories( ${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/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index cc7e1d492a8..a876aa93a07 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -24,49 +24,6 @@ #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) { } diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index dc78a00dfdd..718e26d2564 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -20,6 +20,7 @@ #define _REALMLIST_H #include "Common.h" +#include "Realm.h" #include "WorldListener.h" #include <boost/asio/ip/address.hpp> #include <boost/asio/ip/tcp.hpp> @@ -28,67 +29,6 @@ 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 { diff --git a/src/server/bnetserver/Realms/WorldListener.cpp b/src/server/bnetserver/Realms/WorldListener.cpp index 30886a67310..9c9f1029e87 100644 --- a/src/server/bnetserver/Realms/WorldListener.cpp +++ b/src/server/bnetserver/Realms/WorldListener.cpp @@ -98,7 +98,9 @@ void WorldListener::HandleToonOnlineStatusChange(Battlenet::RealmHandle const& r if (online) { Battlenet::WoWRealm::ToonReady* toonReady = new Battlenet::WoWRealm::ToonReady(); - toonReady->Realm = realm; + toonReady->Realm.Battlegroup = realm.Battlegroup; + toonReady->Realm.Index = realm.Index; + toonReady->Realm.Region = realm.Region; toonReady->Guid = toonHandle.Guid; toonReady->Name = toonHandle.Name; session->AsyncWrite(toonReady); diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index bcf1a33a626..d18fce9b829 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -128,6 +128,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Packets + ${CMAKE_SOURCE_DIR}/src/server/shared/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp index df7f6fdcc77..74f6b62e398 100644 --- a/src/server/game/Entities/Object/Updates/UpdateData.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp @@ -45,11 +45,11 @@ void UpdateData::AddUpdateBlock(const ByteBuffer &block) bool UpdateData::BuildPacket(WorldPacket* packet) { ASSERT(packet->empty()); // shouldn't happen - packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); + packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos(), CONNECTION_TYPE_INSTANCE); *packet << uint32(m_blockCount); *packet << uint16(m_map); - + if (packet->WriteBit(!m_outOfRangeGUIDs.empty())) { *packet << uint16(0); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 6845ebb383b..b27a398e989 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -51,6 +51,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "BattlenetServerManager.h" +#include "AuthenticationPackets.h" class LoginQueryHolder : public SQLQueryHolder { @@ -761,7 +762,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& TC_LOG_DEBUG("network", "WORLD: Recvd Player Logon Message"); - m_playerLoading = true; + m_playerLoading = playerLogin.Guid; TC_LOG_DEBUG("network", "Character %s logging in", playerLogin.Guid.ToString().c_str()); @@ -772,11 +773,32 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& return; } - LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), playerLogin.Guid); + boost::system::error_code ignored_error; + boost::asio::ip::tcp::endpoint instanceAddress = realm.GetAddressForClient(boost::asio::ip::address::from_string(GetRemoteAddress(), ignored_error)); + instanceAddress.port(sWorld->getIntConfig(CONFIG_PORT_INSTANCE)); + + WorldPackets::Auth::ConnectTo connectTo; + connectTo.Key = MAKE_PAIR64(GetAccountId(), CONNECTION_TYPE_INSTANCE); + connectTo.Serial = 1; + connectTo.Payload.Where = instanceAddress; + connectTo.Con = CONNECTION_TYPE_INSTANCE; + + SendPacket(connectTo.Write()); +} + +void WorldSession::HandleContinuePlayerLogin() +{ + if (!PlayerLoading() || GetPlayer()) + { + KickPlayer(); + return; + } + + LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), m_playerLoading); if (!holder->Initialize()) { delete holder; // delete all unprocessed queries - m_playerLoading = false; + m_playerLoading.Clear(); return; } @@ -809,7 +831,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick delete pCurrChar; // delete it manually delete holder; // delete all unprocessed queries - m_playerLoading = false; + m_playerLoading.Clear(); return; } @@ -1049,7 +1071,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED)) pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); - m_playerLoading = false; + m_playerLoading.Clear(); // Handle Login-Achievements (should be handled after loading) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); diff --git a/src/server/game/Server/Packet.cpp b/src/server/game/Server/Packet.cpp index 10b472bee67..61d626b8228 100644 --- a/src/server/game/Server/Packet.cpp +++ b/src/server/game/Server/Packet.cpp @@ -17,6 +17,164 @@ #include "Packet.h" +inline bool IsInstanceOnlyOpcode(uint32 opcode) +{ + // TODO: Use names when known + switch (opcode) + { + case 0x000F: // Client + case 0x0111: // Client + case 0x03E4: // Client + case 0x0549: // Client + case 0x054C: // Client + case 0x055A: // Client + case 0x056C: // Client + case 0x057A: // Client + case 0x057B: // Client + case 0x05CC: // Client + case 0x05EA: // Client + case 0x05EC: // Client + case 0x05F9: // Client + case 0x05FB: // Client + case 0x074C: // Client + case 0x075B: // Client + case 0x076C: // Client + case 0x077B: // Client + case 0x077C: // Client + case 0x07CC: // Client + case 0x07DB: // Client + case 0x07EC: // Client + case 0x07FB: // Client + case 0x07FC: // Client + case 0x0827: // Client + case 0x0935: // Client + case 0x0F0C: // ClientSpell + case 0x0F10: // ClientSpell + case 0x0F1B: // ClientSpell + case 0x0F1C: // ClientSpell + case 0x0F20: // ClientSpell + case 0x0F2C: // ClientSpell + case 0x0F2F: // ClientSpell + case 0x0F3B: // ClientSpell + case 0x0F8B: // ClientSpell + case 0x0F8C: // ClientSpell + case 0x0F90: // ClientSpell + case 0x0F9F: // ClientSpell + case 0x0FA0: // ClientSpell + case 0x1382: // Client + case 0x14C9: // Client + case 0x154A: // Client + case 0x155A: // Client + case 0x155C: // Client + case 0x1567: // ClientQuest + case 0x156A: // Client + case 0x156B: // Client + case 0x157A: // Client + case 0x157B: // Client + case 0x15DC: // Client + case 0x15EB: // Client + case 0x15FB: // Client + case 0x170C: // ClientSpell + case 0x171C: // ClientSpell + case 0x171F: // ClientSpell + case 0x172C: // ClientSpell + case 0x172F: // ClientSpell + case 0x173C: // ClientSpell + case 0x173F: // ClientSpell + case 0x1740: // ClientSpell + case 0x1790: // ClientSpell + case 0x179B: // ClientSpell + case 0x179F: // ClientSpell + case 0x1D3E: // Client + case 0x1D82: // ClientQuest + case 0x1D83: // ClientQuest + case 0x1D85: // ClientQuest + case 0x1D87: // ClientQuest + case 0x1D93: // ClientQuest + case 0x1D96: // ClientQuest + case 0x1D97: // ClientQuest + case 0x1DA1: // ClientQuest + case 0x1DA2: // ClientQuest + case 0x1DA3: // ClientQuest + case 0x1DA4: // ClientQuest + case 0x1DA5: // ClientQuest + case 0x1DA7: // ClientQuest + case 0x1DB0: // Client + case 0x1DC2: // ClientQuest + case 0x1DC6: // ClientQuest + case 0x1DC7: // ClientQuest + case 0x1DD2: // ClientQuest + case 0x1DD3: // ClientQuest + case 0x1DD6: // ClientQuest + case 0x1DD7: // ClientQuest + case 0x1DD8: // ClientQuest + case 0x1DE4: // ClientQuest + case 0x1DE5: // ClientQuest + case 0x1DE7: // ClientQuest + case 0x1F02: // ClientQuest + case 0x1F06: // ClientQuest + case 0x1F07: // ClientQuest + case 0x1F0C: // ClientSpell + case 0x1F12: // ClientQuest + case 0x1F13: // ClientQuest + case 0x1F16: // ClientQuest + case 0x1F17: // ClientQuest + case 0x1F18: // ClientQuest + case 0x1F1C: // ClientSpell + case 0x1F1F: // ClientSpell + case 0x1F24: // ClientQuest + case 0x1F25: // ClientQuest + case 0x1F27: // ClientQuest + case 0x1F2C: // ClientSpell + case 0x1F2F: // ClientSpell + case 0x1F3C: // ClientSpell + case 0x1F3F: // ClientSpell + case 0x1F40: // ClientSpell + case 0x1F44: // ClientQuest + case 0x1F48: // ClientQuest + case 0x1F51: // ClientQuest + case 0x1F55: // ClientQuest + case 0x1F57: // ClientQuest + case 0x1F61: // ClientQuest + case 0x1F63: // ClientQuest + case 0x1F64: // ClientQuest + case 0x1F65: // ClientQuest + case 0x1F67: // ClientQuest + case 0x1F85: // ClientQuest + case 0x1F86: // ClientQuest + case 0x1F87: // ClientQuest + case 0x1F90: // ClientSpell + case 0x1F92: // ClientQuest + case 0x1F94: // ClientQuest + case 0x1F96: // ClientQuest + case 0x1F97: // ClientQuest + case 0x1F9B: // ClientSpell + case 0x1F9F: // ClientSpell + case 0x1FA1: // ClientQuest + case 0x1FA2: // ClientQuest + case 0x1FA3: // ClientQuest + case 0x1FA4: // ClientQuest + case 0x1FA5: // ClientQuest + case 0x1FA7: // ClientQuest + case 0x1FC2: // ClientQuest + case 0x1FC6: // ClientQuest + case 0x1FC7: // ClientQuest + case 0x1FD2: // ClientQuest + case 0x1FD3: // ClientQuest + case 0x1FD6: // ClientQuest + case 0x1FD7: // ClientQuest + case 0x1FD8: // ClientQuest + case 0x1FE4: // ClientQuest + case 0x1FE5: // ClientQuest + case 0x1FE7: // ClientQuest + return true; + default: + return false; + } +} + WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize)) { + if (IsInstanceOnlyOpcode(opcode)) + _connectionIndex = CONNECTION_TYPE_INSTANCE; } diff --git a/src/server/game/Server/Packet.h b/src/server/game/Server/Packet.h index 66061166ede..1a2ba87f90a 100644 --- a/src/server/game/Server/Packet.h +++ b/src/server/game/Server/Packet.h @@ -25,7 +25,11 @@ namespace WorldPackets class Packet { public: - Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket)) { } + Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket)) + { + _connectionIndex = _worldPacket.GetConnection(); + } + virtual ~Packet() = default; Packet(Packet const& right) = delete; @@ -35,9 +39,11 @@ namespace WorldPackets virtual void Read() = 0; size_t GetSize() const { return _worldPacket.size(); } + ConnectionType GetConnection() const { return _connectionIndex; } protected: WorldPacket _worldPacket; + ConnectionType _connectionIndex; }; class ServerPacket : public Packet diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index a57f5f60244..95f2379e82f 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -585,3 +585,10 @@ WorldPacket const* WorldPackets::Auth::ConnectTo::Write() _worldPacket << uint8(Con); return &_worldPacket; } + +void WorldPackets::Auth::AuthContinuedSession::Read() +{ + _worldPacket >> DosResponse; + _worldPacket >> Key; + _worldPacket.read(Digest, SHA_DIGEST_LENGTH); +} diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index 1d194b0b2a9..70aa38cac8e 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -168,6 +168,29 @@ namespace WorldPackets BigNumber dmq1; BigNumber iqmp; }; + + class AuthContinuedSession final : public ClientPacket + { + public: + AuthContinuedSession(WorldPacket&& packet) : ClientPacket(std::move(packet)) + { + memset(Digest, 0, SHA_DIGEST_LENGTH); + } + + void Read() override; + + uint64 DosResponse = 0; + uint64 Key = 0; + uint8 Digest[SHA_DIGEST_LENGTH]; + }; + + class ResumeComms final : public ServerPacket + { + public: + ResumeComms() : ServerPacket(SMSG_RESUME_COMMS, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index b22dc575c0c..003a1ce1fad 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -137,6 +137,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_PLACE_BID, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionPlaceBid ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_REMOVE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionRemoveItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_SELL_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTH_CONTINUED_SESSION, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTH_SESSION, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOBANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOEQUIP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); @@ -501,7 +502,6 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_READ_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReadItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REALM_SPLIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRealmSplitOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_RECLAIM_CORPSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReclaimCorpseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REDIRECTION_AUTH_PROOF, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REFORGE_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleReforgeItemOpcode ); DEFINE_HANDLER(CMSG_REORDER_CHARACTERS, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Character::ReorderCharacters, &WorldSession::HandleReorderCharacters); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPAIR_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode ); @@ -576,7 +576,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SUBMIT_COMPLAIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUGGESTION_SUBMIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUMMON_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_INV_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SYNC_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -877,7 +877,6 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCEACTIONSHOW, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SEND_QUEUED_PACKETS, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SET_VEHICLE_REC_ID, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORGE_MASTER_SET, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FRIEND_STATUS, STATUS_UNHANDLED); @@ -1202,7 +1201,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_SPLIT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REAL_GROUP_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RECEIVED_MAIL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_EXPIRED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_UNHANDLED); @@ -1215,6 +1214,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_FAILED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED); @@ -1312,7 +1312,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index d8ac4b68d9e..c20dc4b81c9 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -26,6 +26,12 @@ #include "Common.h" #include <iomanip> +enum ConnectionType +{ + CONNECTION_TYPE_REALM = 0, + CONNECTION_TYPE_INSTANCE = 1 +}; + enum OpcodeMisc : uint32 { MAX_OPCODE = 0x1FFF, @@ -70,6 +76,7 @@ enum OpcodeClient : uint32 CMSG_AUCTION_PLACE_BID = 0xBADD, CMSG_AUCTION_REMOVE_ITEM = 0xBADD, CMSG_AUCTION_SELL_ITEM = 0xBADD, + CMSG_AUTH_CONTINUED_SESSION = 0x0485, CMSG_AUTH_SESSION = 0x0487, CMSG_AUTOBANK_ITEM = 0xBADD, CMSG_AUTOEQUIP_GROUND_ITEM = 0xBADD, @@ -466,7 +473,6 @@ enum OpcodeClient : uint32 CMSG_READ_ITEM = 0xBADD, CMSG_REALM_SPLIT = 0xBADD, CMSG_RECLAIM_CORPSE = 0xBADD, - CMSG_REDIRECTION_AUTH_PROOF = 0x0485, CMSG_REFORGE_ITEM = 0xBADD, CMSG_REORDER_CHARACTERS = 0x0DAA, CMSG_REPAIR_ITEM = 0xBADD, @@ -552,7 +558,7 @@ enum OpcodeClient : uint32 CMSG_SUBMIT_COMPLAIN = 0xBADD, CMSG_SUGGESTION_SUBMIT = 0xBADD, CMSG_SUMMON_RESPONSE = 0xBADD, - CMSG_SUSPEND_TOKEN = 0x0142, + CMSG_SUSPEND_TOKEN_RESPONSE = 0x0142, CMSG_SWAP_INV_ITEM = 0xBADD, CMSG_SWAP_ITEM = 0xBADD, CMSG_SYNC_DANCE = 0xBADD, @@ -887,7 +893,6 @@ enum OpcodeServer : uint32 SMSG_FORCED_DEATH_UPDATE = 0xBADD, SMSG_FORCE_ANIM = 0xBADD, SMSG_FORCE_DISPLAY_UPDATE = 0xBADD, - SMSG_FORCE_SEND_QUEUED_PACKETS = 0xBADD, SMSG_FORCE_SET_VEHICLE_REC_ID = 0xBADD, SMSG_FORGE_MASTER_SET = 0xBADD, SMSG_FRIEND_STATUS = 0xBADD, @@ -1248,6 +1253,7 @@ enum OpcodeServer : uint32 SMSG_RESET_FAILED_NOTIFY = 0xBADD, SMSG_RESISTLOG = 0xBADD, SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0xBADD, + SMSG_RESUME_COMMS = 0x07C9, SMSG_RESURRECT_FAILED = 0xBADD, SMSG_RESURRECT_REQUEST = 0xBADD, SMSG_RESYNC_RUNES = 0xBADD, @@ -1347,7 +1353,7 @@ enum OpcodeServer : uint32 SMSG_SUPERCEDED_SPELL = 0xBADD, SMSG_SUPPRESS_NPC_GREETINGS = 0xBADD, SMSG_SUSPEND_COMMS = 0x076A, - SMSG_SUSPEND_TOKEN_RESPONSE = 0x12A2, + SMSG_SUSPEND_TOKEN = 0x12A2, SMSG_TALENTS_ERROR = 0xBADD, SMSG_TALENTS_INFO = 0x012D, SMSG_TALENTS_INVOLUNTARILY_RESET = 0xBADD, diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h index e7d6d4fb5b1..65b2f6fcae1 100644 --- a/src/server/game/Server/WorldPacket.h +++ b/src/server/game/Server/WorldPacket.h @@ -27,17 +27,18 @@ class WorldPacket : public ByteBuffer { public: // just container for later use - WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE) + WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE), _connection(CONNECTION_TYPE_REALM) { } - explicit WorldPacket(uint32 opcode, size_t res = 200) : ByteBuffer(res), m_opcode(opcode) { } + WorldPacket(uint32 opcode, size_t res = 200, ConnectionType connection = CONNECTION_TYPE_REALM) : ByteBuffer(res), + m_opcode(opcode), _connection(connection) { } - WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode) + WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), _connection(packet._connection) { } - WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode) + WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode), _connection(right._connection) { } @@ -46,26 +47,31 @@ class WorldPacket : public ByteBuffer if (this != &right) { m_opcode = right.m_opcode; + _connection = right._connection; ByteBuffer::operator =(right); } return *this; } - WorldPacket(uint32 opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { } + WorldPacket(uint32 opcode, MessageBuffer&& buffer, ConnectionType connection) : ByteBuffer(std::move(buffer)), m_opcode(opcode), _connection(connection) { } - void Initialize(uint32 opcode, size_t newres = 200) + void Initialize(uint32 opcode, size_t newres = 200, ConnectionType connection = CONNECTION_TYPE_REALM) { clear(); _storage.reserve(newres); m_opcode = opcode; + _connection = connection; } uint32 GetOpcode() const { return m_opcode; } void SetOpcode(uint32 opcode) { m_opcode = opcode; } + ConnectionType GetConnection() const { return _connection; } + protected: uint32 m_opcode; + ConnectionType _connection; }; #endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 0164ad9a575..f427b91787a 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -106,7 +106,6 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr AntiDOS(this), m_GUIDLow(UI64LIT(0)), _player(NULL), - m_Socket(sock), _security(sec), _accountId(id), _battlenetAccountId(battlenetAccountId), @@ -114,7 +113,6 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr _warden(NULL), _logoutTime(0), m_inQueue(false), - m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false), @@ -140,17 +138,9 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query } - InitializeQueryCallbackParameters(); + m_Socket[0] = sock; - _compressionStream = new z_stream(); - _compressionStream->zalloc = (alloc_func)NULL; - _compressionStream->zfree = (free_func)NULL; - _compressionStream->opaque = (voidpf)NULL; - _compressionStream->avail_in = 0; - _compressionStream->next_in = NULL; - int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); - if (z_res != Z_OK) - TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); + InitializeQueryCallbackParameters(); } /// WorldSession destructor @@ -161,10 +151,13 @@ WorldSession::~WorldSession() LogoutPlayer (true); /// - If have unclosed socket, close it - if (m_Socket) + for (uint8 i = 0; i < 2; ++i) { - m_Socket->CloseSocket(); - m_Socket = nullptr; + if (m_Socket[i]) + { + m_Socket[i]->CloseSocket(); + m_Socket[i].reset(); + } } delete _warden; @@ -176,12 +169,6 @@ WorldSession::~WorldSession() delete packet; LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); // One-time query - - int32 z_res = deflateEnd(_compressionStream); - if (z_res != Z_OK && z_res != Z_DATA_ERROR) // Z_DATA_ERROR signals that internal state was BUSY - TC_LOG_ERROR("network", "Can't close packet compression stream (zlib: deflateEnd) Error code: %i (%s)", z_res, zError(z_res)); - - delete _compressionStream; } std::string const & WorldSession::GetPlayerName() const @@ -205,7 +192,7 @@ std::string WorldSession::GetPlayerInfo() const /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/) { - if (!m_Socket) + if (!m_Socket[packet->GetConnection()]) return; if (packet->GetOpcode() == NULL_OPCODE) @@ -265,38 +252,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ sScriptMgr->OnPacketSend(this, *packet); - m_Socket->SendPacket(*packet); -} - -uint32 WorldSession::CompressPacket(uint8* buffer, WorldPacket const& packet) -{ - uint32 opcode = packet.GetOpcode(); - uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode)); - - _compressionStream->next_out = buffer; - _compressionStream->avail_out = bufferSize; - _compressionStream->next_in = (Bytef*)&opcode; - _compressionStream->avail_in = sizeof(uint32); - - int32 z_res = deflate(_compressionStream, Z_BLOCK); - if (z_res != Z_OK) - { - TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); - return 0; - } - - _compressionStream->next_in = (Bytef*)packet.contents(); - _compressionStream->avail_in = packet.size(); - - z_res = deflate(_compressionStream, Z_SYNC_FLUSH); - if (z_res != Z_OK) - { - TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); - return 0; - } - - - return bufferSize - _compressionStream->avail_out; + m_Socket[packet->GetConnection()]->SendPacket(*packet); } /// Add an incoming packet to the queue @@ -332,7 +288,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) - m_Socket->CloseSocket(); + m_Socket[0]->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed @@ -349,7 +305,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) uint32 processedPackets = 0; time_t currentTime = time(NULL); - while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) + while (m_Socket[0] && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) KickPlayer(); @@ -458,7 +414,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } - if (m_Socket && m_Socket->IsOpen() && _warden) + if (m_Socket[0] && m_Socket[0]->IsOpen() && _warden) _warden->Update(); ProcessQueryCallbacks(); @@ -469,23 +425,24 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) { time_t currTime = time(NULL); ///- If necessary, log the player out - if (ShouldLogOut(currTime) && !m_playerLoading) + if (ShouldLogOut(currTime) && m_playerLoading.IsEmpty()) LogoutPlayer(true); - if (m_Socket && GetPlayer() && _warden) + if (m_Socket[0] && GetPlayer() && _warden) _warden->Update(); ///- Cleanup socket pointer if need - if (m_Socket && !m_Socket->IsOpen()) + if ((m_Socket[0] && !m_Socket[0]->IsOpen()) || (m_Socket[1] && !m_Socket[1]->IsOpen())) { expireTime -= expireTime > diff ? diff : expireTime; if (expireTime < diff || forceExit || !GetPlayer()) { - m_Socket = nullptr; + m_Socket[0].reset(); + m_Socket[1].reset(); } } - if (!m_Socket) + if (!m_Socket[0]) return false; //Will remove this session from the world session map } @@ -587,7 +544,7 @@ void WorldSession::LogoutPlayer(bool save) // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) - if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) + if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket[0]) _player->RemoveFromGroup(); //! Send update to group and reset stored max enchanting level @@ -640,10 +597,13 @@ void WorldSession::LogoutPlayer(bool save) /// Kick a player out of the World void WorldSession::KickPlayer() { - if (m_Socket) + for (uint8 i = 0; i < 2; ++i) { - m_Socket->CloseSocket(); - forceExit = true; + if (m_Socket[i]) + { + m_Socket[i]->CloseSocket(); + forceExit = true; + } } } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index c77ad210ebc..83a746c8f44 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -54,7 +54,6 @@ struct DeclinedName; struct ItemTemplate; struct MovementInfo; struct TradeStatusInfo; -struct z_stream_s; namespace lfg { @@ -228,7 +227,7 @@ class WorldSession WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); - bool PlayerLoading() const { return m_playerLoading; } + bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); } bool PlayerLogout() const { return m_playerLogout; } bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; } bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; } @@ -238,7 +237,7 @@ class WorldSession bool IsAddonRegistered(const std::string& prefix) const; void SendPacket(WorldPacket const* packet, bool forced = false); - uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); + void AddInstanceConnection(std::shared_ptr<WorldSocket> sock) { m_Socket[1] = sock; } void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3); void SendNotification(uint32 string_id, ...); @@ -424,8 +423,6 @@ class WorldSession uint32 GetRecruiterId() const { return recruiterId; } bool IsARecruiter() const { return isRecruiter; } - z_stream_s* GetCompressionStream() { return _compressionStream; } - public: // opcodes handlers void Handle_NULL(WorldPacket& recvPacket); // not used @@ -441,6 +438,7 @@ class WorldSession void HandleCharCreateOpcode(WorldPackets::Character::CharacterCreate& charCreate); void HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo); void HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& playerLogin); + void HandleContinuePlayerLogin(); void HandleLoadScreenOpcode(WorldPacket& recvPacket); void HandlePlayerLogin(LoginQueryHolder * holder); void HandleCharRenameOpcode(WorldPacket& recvData); @@ -1091,7 +1089,7 @@ class WorldSession ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set) Player* _player; - std::shared_ptr<WorldSocket> m_Socket; + std::shared_ptr<WorldSocket> m_Socket[2]; std::string m_Address; // Current Remote Address // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session! @@ -1107,7 +1105,7 @@ class WorldSession time_t _logoutTime; bool m_inQueue; // session wait in auth.queue - bool m_playerLoading; // code processed in LoginPlayer + ObjectGuid m_playerLoading; // code processed in LoginPlayer bool m_playerLogout; // code processed in LogoutPlayer bool m_playerRecentlyLogout; bool m_playerSave; @@ -1124,7 +1122,6 @@ class WorldSession uint32 recruiterId; bool isRecruiter; LockedQueue<WorldPacket*> _recvQueue; - z_stream_s* _compressionStream; rbac::RBACData* _RBACData; uint32 expireTime; bool forceExit; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 23bd9a65f88..9cdb05ac79b 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -25,6 +25,7 @@ #include "SHA1.h" #include "PacketLog.h" #include "BattlenetAccountMgr.h" +#include "World.h" #include <zlib.h> #include <memory> @@ -53,12 +54,22 @@ uint32 const SizeOfClientHeader[2][2] = uint32 const SizeOfServerHeader[2] = { sizeof(uint16) + sizeof(uint32), sizeof(uint32) }; -WorldSocket::WorldSocket(tcp::socket&& socket) - : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false) +WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), + _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), + _initialized(false), _type(CONNECTION_TYPE_REALM) { _headerBuffer.Resize(SizeOfClientHeader[0][0]); } +WorldSocket::~WorldSocket() +{ + if (_compressionStream) + { + deflateEnd(_compressionStream); + delete _compressionStream; + } +} + void WorldSocket::Start() { AsyncRead(); @@ -75,15 +86,13 @@ void WorldSocket::Start() void WorldSocket::HandleSendAuthSession() { - BigNumber seed1; - BigNumber seed2; - seed1.SetRand(16 * 8); - seed2.SetRand(16 * 8); + _encryptSeed.SetRand(16 * 8); + _decryptSeed.SetRand(16 * 8); WorldPackets::Auth::AuthChallenge challenge; challenge.Challenge = _authSeed; - memcpy(&challenge.DosChallenge[0], seed1.AsByteArray(16).get(), 16); - memcpy(&challenge.DosChallenge[4], seed2.AsByteArray(16).get(), 16); + memcpy(&challenge.DosChallenge[0], _encryptSeed.AsByteArray(16).get(), 16); + memcpy(&challenge.DosChallenge[4], _decryptSeed.AsByteArray(16).get(), 16); challenge.DosZeroBits = 1; SendPacket(*challenge.Write()); @@ -204,7 +213,7 @@ bool WorldSocket::ReadDataHandler() std::string opcodeName = GetOpcodeNameForLogging(opcode); - WorldPacket packet(opcode, std::move(_packetBuffer)); + WorldPacket packet(opcode, std::move(_packetBuffer), GetConnectionType()); if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort()); @@ -217,15 +226,32 @@ bool WorldSocket::ReadDataHandler() HandlePing(packet); break; case CMSG_AUTH_SESSION: + { if (_worldSession) { TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); break; } - HandleAuthSession(packet); + WorldPackets::Auth::AuthSession authSession(std::move(packet)); + authSession.Read(); + HandleAuthSession(authSession); + break; + } + case CMSG_AUTH_CONTINUED_SESSION: + { + if (_worldSession) + { + TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_CONTINUED_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); + break; + } + + WorldPackets::Auth::AuthContinuedSession authSession(std::move(packet)); + authSession.Read(); + HandleAuthContinuedSession(authSession); break; - /* + } + /* case CMSG_KEEP_ALIVE: TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); sScriptMgr->OnPacketReceive(_worldSession, packet); @@ -286,6 +312,20 @@ bool WorldSocket::ReadDataHandler() return false; } + _compressionStream = new z_stream(); + _compressionStream->zalloc = (alloc_func)NULL; + _compressionStream->zfree = (free_func)NULL; + _compressionStream->opaque = (voidpf)NULL; + _compressionStream->avail_in = 0; + _compressionStream->next_in = NULL; + int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (z_res != Z_OK) + { + TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); + CloseSocket(); + return false; + } + _initialized = true; _headerBuffer.Resize(SizeOfClientHeader[1][0]); _packetBuffer.Reset(); @@ -295,6 +335,35 @@ bool WorldSocket::ReadDataHandler() return true; } +void WorldSocket::SendPacket(WorldPacket const& packet) +{ + if (!IsOpen()) + return; + + if (sPacketLog->CanLogPacket()) + sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort()); + + TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str()); + + uint32 packetSize = packet.size(); + uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; + if (packetSize > 0x400) + packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); + + std::unique_lock<std::mutex> guard(_writeLock); + +#ifndef TC_SOCKET_USE_IOCP + if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize) + WritePacketToBuffer(packet, _writeBuffer); + else +#endif + { + MessageBuffer buffer(sizeOfHeader + packetSize); + WritePacketToBuffer(packet, buffer); + QueuePacket(std::move(buffer), guard); + } +} + void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer) { ServerPktHeader header; @@ -306,7 +375,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* headerPos = buffer.GetWritePointer(); buffer.WriteCompleted(sizeOfHeader); - if (packetSize > 0x400 && _worldSession) + if (packetSize > 0x400) { CompressedWorldPacket cmp; cmp.UncompressedSize = packetSize + 4; @@ -316,7 +385,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* compressionInfo = buffer.GetWritePointer(); buffer.WriteCompleted(sizeof(CompressedWorldPacket)); - uint32 compressedSize = _worldSession->CompressPacket(buffer.GetWritePointer(), packet); + uint32 compressedSize = CompressPacket(buffer.GetWritePointer(), packet); cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize); @@ -344,40 +413,39 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& memcpy(headerPos, &header, sizeOfHeader); } -void WorldSocket::SendPacket(WorldPacket const& packet) +uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet) { - if (!IsOpen()) - return; - - if (sPacketLog->CanLogPacket()) - sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort()); + uint32 opcode = packet.GetOpcode(); + uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode)); - TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str()); + _compressionStream->next_out = buffer; + _compressionStream->avail_out = bufferSize; + _compressionStream->next_in = (Bytef*)&opcode; + _compressionStream->avail_in = sizeof(uint32); - uint32 packetSize = packet.size(); - uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; - if (packetSize > 0x400 && _worldSession) - packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); + int32 z_res = deflate(_compressionStream, Z_BLOCK); + if (z_res != Z_OK) + { + TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); + return 0; + } - std::unique_lock<std::mutex> guard(_writeLock); + _compressionStream->next_in = (Bytef*)packet.contents(); + _compressionStream->avail_in = packet.size(); -#ifndef TC_SOCKET_USE_IOCP - if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize) - WritePacketToBuffer(packet, _writeBuffer); - else -#endif + z_res = deflate(_compressionStream, Z_SYNC_FLUSH); + if (z_res != Z_OK) { - MessageBuffer buffer(sizeOfHeader + packetSize); - WritePacketToBuffer(packet, buffer); - QueuePacket(std::move(buffer), guard); + TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); + return 0; } + + + return bufferSize - _compressionStream->avail_out; } -void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) +void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession) { - WorldPackets::Auth::AuthSession authSession(std::move(recvPacket)); - authSession.Read(); - uint8 security; uint32 id; LocaleConstant locale; @@ -598,6 +666,56 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) sWorld->AddSession(_worldSession); } +void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession) +{ + uint32 accountId = PAIR64_LOPART(authSession.Key); + _type = ConnectionType(PAIR64_HIPART(authSession.Key)); + QueryResult result = LoginDatabase.PQuery("SELECT username, sessionkey FROM account WHERE id = %u", accountId); + if (!result) + { + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + DelayedCloseSocket(); + return; + } + + Field* fields = result->Fetch(); + std::string login = fields[0].GetString(); + BigNumber k; + k.SetHexStr(fields[1].GetCString()); + + _authCrypt.Init(&k, _encryptSeed.AsByteArray().get(), _decryptSeed.AsByteArray().get()); + _headerBuffer.Resize(SizeOfClientHeader[1][1]); + + SHA1Hash sha; + sha.UpdateData(login); + sha.UpdateBigNumbers(&k, NULL); + sha.UpdateData((uint8*)&_authSeed, 4); + sha.Finalize(); + + if (memcmp(sha.GetDigest(), authSession.Digest, sha.GetLength())) + { + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + _worldSession = sWorld->FindSession(accountId); + if (!_worldSession) + { + SendAuthResponseError(AUTH_SESSION_EXPIRED); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: No active session found for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + WorldPackets::Auth::ResumeComms resumeComms; + SendPacket(*resumeComms.Write()); + + _worldSession->AddInstanceConnection(shared_from_this()); + _worldSession->HandleContinuePlayerLogin(); +} + void WorldSocket::SendAuthResponseError(uint8 code) { WorldPackets::Auth::AuthResponse response; diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index e0dad0a43a1..16769c68c33 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -31,10 +31,16 @@ #include <boost/asio/buffer.hpp> using boost::asio::ip::tcp; +struct z_stream_s; namespace WorldPackets { class ServerPacket; + namespace Auth + { + class AuthSession; + class AuthContinuedSession; + } } #pragma pack(push, 1) @@ -67,6 +73,7 @@ class WorldSocket : public Socket<WorldSocket> public: WorldSocket(tcp::socket&& socket); + ~WorldSocket(); WorldSocket(WorldSocket const& right) = delete; WorldSocket& operator=(WorldSocket const& right) = delete; @@ -74,7 +81,8 @@ public: void Start() override; void SendPacket(WorldPacket const& packet); - void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer); + + ConnectionType GetConnectionType() const { return _type; } protected: void ReadHandler() override; @@ -82,16 +90,24 @@ protected: bool ReadDataHandler(); private: + void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer); + uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); + void HandleSendAuthSession(); - void HandleAuthSession(WorldPacket& recvPacket); + void HandleAuthSession(WorldPackets::Auth::AuthSession& authSession); + void HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession); void SendAuthResponseError(uint8 code); void HandlePing(WorldPacket& recvPacket); void ExtractOpcodeAndSize(ClientPktHeader const* header, uint32& opcode, uint32& size) const; + ConnectionType _type; + uint32 _authSeed; WorldPacketCrypt _authCrypt; + BigNumber _encryptSeed; + BigNumber _decryptSeed; std::chrono::steady_clock::time_point _LastPingTime; uint32 _OverSpeedPings; @@ -101,6 +117,8 @@ private: MessageBuffer _headerBuffer; MessageBuffer _packetBuffer; + z_stream_s* _compressionStream; + bool _initialized; }; diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 21f62fa265c..5fcd308f376 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -46,6 +46,11 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m { } +WorldSocketMgr::~WorldSocketMgr() +{ + delete _instanceAcceptor; +} + bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) { _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); @@ -64,8 +69,10 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string } BaseSocketMgr::StartNetwork(service, bindIp, port); + _instanceAcceptor = new AsyncAcceptor(service, bindIp, uint16(sWorld->getIntConfig(CONFIG_PORT_INSTANCE))); _acceptor->AsyncAcceptManaged(&OnSocketAccept); + _instanceAcceptor->AsyncAcceptManaged(&OnSocketAccept); sScriptMgr->OnNetworkStart(); return true; diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index 92a28d0c135..389818b2f9b 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -35,6 +35,8 @@ class WorldSocketMgr : public SocketMgr<WorldSocket> typedef SocketMgr<WorldSocket> BaseSocketMgr; public: + ~WorldSocketMgr(); + static WorldSocketMgr& Instance() { static WorldSocketMgr instance; @@ -55,6 +57,7 @@ protected: NetworkThread<WorldSocket>* CreateThreads() const override; private: + AsyncAcceptor* _instanceAcceptor; int32 _socketSendBufferSize; int32 m_SockOutUBuff; bool _tcpNoDelay; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 4900b655766..f2248ebf3e2 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -650,9 +650,16 @@ void World::LoadConfigSettings(bool reload) uint32 val = sConfigMgr->GetIntDefault("WorldServerPort", 8085); if (val != m_int_configs[CONFIG_PORT_WORLD]) TC_LOG_ERROR("server.loading", "WorldServerPort option can't be changed at worldserver.conf reload, using current value (%u).", m_int_configs[CONFIG_PORT_WORLD]); + + val = sConfigMgr->GetIntDefault("InstanceServerPort", 8086); + if (val != m_int_configs[CONFIG_PORT_INSTANCE]) + TC_LOG_ERROR("server.loading", "InstanceServerPort option can't be changed at worldserver.conf reload, using current value (%u).", m_int_configs[CONFIG_PORT_INSTANCE]); } else + { m_int_configs[CONFIG_PORT_WORLD] = sConfigMgr->GetIntDefault("WorldServerPort", 8085); + m_int_configs[CONFIG_PORT_INSTANCE] = sConfigMgr->GetIntDefault("InstanceServerPort", 8086); + } m_int_configs[CONFIG_SOCKET_TIMEOUTTIME] = sConfigMgr->GetIntDefault("SocketTimeOutTime", 900000); m_int_configs[CONFIG_SESSION_ADD_DELAY] = sConfigMgr->GetIntDefault("SessionAddDelay", 10000); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 3c3e40cc76b..48f6271b558 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -30,6 +30,7 @@ #include "SharedDefines.h" #include "QueryResult.h" #include "Callback.h" +#include "Realm/Realm.h" #include <atomic> #include <map> @@ -204,6 +205,7 @@ enum WorldIntConfigs CONFIG_INTERVAL_CHANGEWEATHER, CONFIG_INTERVAL_DISCONNECT_TOLERANCE, CONFIG_PORT_WORLD, + CONFIG_PORT_INSTANCE, CONFIG_SOCKET_TIMEOUTTIME, CONFIG_SESSION_ADD_DELAY, CONFIG_GAME_TYPE, @@ -887,6 +889,7 @@ class World }; extern Battlenet::RealmHandle realmHandle; +extern Realm realm; uint32 GetVirtualRealmAddress(); #define sWorld World::instance() diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index 7a02e415d69..1ad85acb601 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -20,6 +20,7 @@ file(GLOB_RECURSE sources_Dynamic Dynamic/*.cpp Dynamic/*.h) file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h) file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h) file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h) +file(GLOB_RECURSE sources_Realm Realm/*.cpp Realm/*.h) file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h) file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h) @@ -50,6 +51,7 @@ set(shared_STAT_SRCS ${sources_Logging} ${sources_Networking} ${sources_Packets} + ${sources_Realm} ${sources_Threading} ${sources_Utilities} ${sources_localdir} @@ -72,6 +74,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Logging ${CMAKE_CURRENT_SOURCE_DIR}/Networking ${CMAKE_CURRENT_SOURCE_DIR}/Packets + ${CMAKE_CURRENT_SOURCE_DIR}/Realm ${CMAKE_CURRENT_SOURCE_DIR}/Threading ${CMAKE_CURRENT_SOURCE_DIR}/Utilities ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index 69198c18df0..b84de24741c 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -29,12 +29,17 @@ WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) void WorldPacketCrypt::Init(BigNumber* K) { uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x08, 0xF1, 0x95, 0x9F, 0x47, 0xE5, 0xD2, 0xDB, 0xA1, 0x3D, 0x77, 0x8F, 0x3F, 0x3E, 0xE7, 0x00 }; - HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); - uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); - uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0x40, 0xAA, 0xD3, 0x92, 0x26, 0x71, 0x43, 0x47, 0x3A, 0x31, 0x08, 0xA6, 0xE7, 0xDC, 0x98, 0x2A }; - HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); - uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); + Init(K, ServerEncryptionKey, ServerDecryptionKey); +} + +void WorldPacketCrypt::Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey) +{ + HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)serverKey); + uint8 *encryptHash = serverEncryptHmac.ComputeHash(k); + + HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)clientKey); + uint8 *decryptHash = clientDecryptHmac.ComputeHash(k); _clientDecrypt.Init(decryptHash); _serverEncrypt.Init(encryptHash); diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h index 7ccca11f09d..58c4003418e 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h @@ -29,6 +29,7 @@ class WorldPacketCrypt : public PacketCrypt WorldPacketCrypt(); void Init(BigNumber* K) override; + void Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey); }; #endif // _WORLDPACKETCRYPT_H diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h index dbe2b8ec902..92c16d96882 100644 --- a/src/server/shared/Networking/SocketMgr.h +++ b/src/server/shared/Networking/SocketMgr.h @@ -33,6 +33,7 @@ class SocketMgr public: virtual ~SocketMgr() { + delete _acceptor; delete[] _threads; } diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp new file mode 100644 index 00000000000..79b10843773 --- /dev/null +++ b/src/server/shared/Realm/Realm.cpp @@ -0,0 +1,53 @@ +/* + * 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 "Realm.h" + +ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const +{ + ip::address realmIp; + + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (LocalAddress.is_loopback() || ExternalAddress.is_loopback()) + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that 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; +} diff --git a/src/server/shared/Realm/Realm.h b/src/server/shared/Realm/Realm.h new file mode 100644 index 00000000000..9476f137947 --- /dev/null +++ b/src/server/shared/Realm/Realm.h @@ -0,0 +1,86 @@ +/* + * 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 Realm_h__ +#define Realm_h__ + +#include "Common.h" +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.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; + } + }; +} + +#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; +}; + +#endif // Realm_h__ diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index c5127b8f3e2..d4f5c086f4b 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -30,7 +30,6 @@ #include "OpenSSLCrypto.h" #include "ProcessPriority.h" #include "BigNumber.h" -#include "RealmList.h" #include "World.h" #include "MapManager.h" #include "InstanceSaveMgr.h" @@ -44,6 +43,7 @@ #include "WorldSocket.h" #include "WorldSocketMgr.h" #include "BattlenetServerManager.h" +#include "Realm/Realm.h" #include <openssl/opensslv.h> #include <openssl/crypto.h> #include <boost/asio/io_service.hpp> @@ -82,6 +82,7 @@ WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database Battlenet::RealmHandle realmHandle; ///< Id of the realm +Realm realm; void SignalHandler(const boost::system::error_code& error, int signalNumber); void FreezeDetectorHandler(const boost::system::error_code& error); @@ -92,6 +93,7 @@ void WorldUpdateLoop(); void ClearOnlineAccounts(); void ShutdownCLIThread(std::thread* cliThread); void ShutdownThreadPool(std::vector<std::thread>& threadPool); +bool LoadRealmInfo(); variables_map GetConsoleArguments(int argc, char** argv, std::string& cfg_file, std::string& cfg_service); /// Launch the Trinity server @@ -192,6 +194,8 @@ extern int main(int argc, char** argv) // Set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmHandle.Index); + LoadRealmInfo(); + // Initialize the World sWorld->SetInitialWorldSettings(); @@ -226,6 +230,8 @@ extern int main(int argc, char** argv) // Set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmHandle.Index); + realm.PopulationLevel = 0.0f; + realm.Flags = RealmFlags(realm.Flags & ~uint32(REALM_FLAG_INVALID)); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) @@ -452,6 +458,61 @@ AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService) return acceptor; } +bool LoadRealmInfo() +{ + boost::asio::ip::tcp::resolver resolver(_ioService); + boost::asio::ip::tcp::resolver::iterator end; + + QueryResult result = LoginDatabase.PQuery("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE id = %u", realmHandle.Index); + if (!result) + return false; + + Field* fields = result->Fetch(); + realm.Name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(ip::tcp::v4(), fields[2].GetString(), ""); + + boost::system::error_code ec; + boost::asio::ip::tcp::resolver::iterator endPoint = resolver.resolve(externalAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return false; + } + + realm.ExternalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(ip::tcp::v4(), fields[3].GetString(), ""); + endPoint = resolver.resolve(localAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return false; + } + + realm.LocalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(ip::tcp::v4(), fields[4].GetString(), ""); + endPoint = resolver.resolve(localSubmaskQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return false; + } + + realm.LocalSubnetMask = (*endPoint).endpoint().address(); + + realm.Port = fields[5].GetUInt16(); + realm.Type = fields[6].GetUInt8(); + realm.Flags = RealmFlags(fields[7].GetUInt8()); + realm.Timezone = fields[8].GetUInt8(); + realm.AllowedSecurityLevel = AccountTypes(fields[9].GetUInt8()); + realm.PopulationLevel = fields[10].GetFloat(); + realm.Id.Index = fields[0].GetUInt32(); + realm.Id.Build = fields[11].GetUInt32(); + realm.Id.Region = fields[12].GetUInt8(); + realm.Id.Battlegroup = fields[13].GetUInt8(); +} + /// Initialize connection to the databases bool StartDB() { diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 4d40365451e..3d59b6216f8 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -141,6 +141,13 @@ MaxPingTime = 30 WorldServerPort = 8085 # +# InstanceServerPort +# Description: TCP port to for second world connection. +# Default: 8086 + +InstanceServerPort = 8086 + +# # BindIP # Description: Bind world server to IP/hostname. # Default: "0.0.0.0" - (Bind to all IPs on the system) |