aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/bnetserver/CMakeLists.txt1
-rw-r--r--src/server/bnetserver/Realms/RealmList.cpp43
-rw-r--r--src/server/bnetserver/Realms/RealmList.h62
-rw-r--r--src/server/bnetserver/Realms/WorldListener.cpp4
-rw-r--r--src/server/game/CMakeLists.txt1
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateData.cpp4
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp32
-rw-r--r--src/server/game/Server/Packet.cpp158
-rw-r--r--src/server/game/Server/Packet.h8
-rw-r--r--src/server/game/Server/Packets/AuthenticationPackets.cpp7
-rw-r--r--src/server/game/Server/Packets/AuthenticationPackets.h23
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp10
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h14
-rw-r--r--src/server/game/Server/WorldPacket.h18
-rw-r--r--src/server/game/Server/WorldSession.cpp92
-rw-r--r--src/server/game/Server/WorldSession.h13
-rw-r--r--src/server/game/Server/WorldSocket.cpp192
-rw-r--r--src/server/game/Server/WorldSocket.h22
-rw-r--r--src/server/game/Server/WorldSocketMgr.cpp7
-rw-r--r--src/server/game/Server/WorldSocketMgr.h3
-rw-r--r--src/server/game/World/World.cpp7
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/shared/CMakeLists.txt3
-rw-r--r--src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp15
-rw-r--r--src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h1
-rw-r--r--src/server/shared/Networking/SocketMgr.h1
-rw-r--r--src/server/shared/Realm/Realm.cpp53
-rw-r--r--src/server/shared/Realm/Realm.h86
-rw-r--r--src/server/worldserver/Main.cpp63
-rw-r--r--src/server/worldserver/worldserver.conf.dist7
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)