diff options
-rw-r--r-- | src/server/authserver/Realms/RealmList.cpp | 10 | ||||
-rw-r--r-- | src/server/authserver/Realms/RealmList.h | 4 | ||||
-rw-r--r-- | src/server/bnetserver/Main.cpp | 9 | ||||
-rw-r--r-- | src/server/bnetserver/Packets/FriendsPackets.cpp | 22 | ||||
-rw-r--r-- | src/server/bnetserver/Packets/FriendsPackets.h | 11 | ||||
-rw-r--r-- | src/server/bnetserver/Packets/PacketFactory.h | 5 | ||||
-rw-r--r-- | src/server/bnetserver/Packets/WoWRealmPackets.cpp | 20 | ||||
-rw-r--r-- | src/server/bnetserver/Packets/WoWRealmPackets.h | 21 | ||||
-rw-r--r-- | src/server/bnetserver/Realms/RealmList.cpp | 133 | ||||
-rw-r--r-- | src/server/bnetserver/Realms/RealmList.h | 74 | ||||
-rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 110 | ||||
-rw-r--r-- | src/server/bnetserver/Server/Session.h | 15 | ||||
-rw-r--r-- | src/server/bnetserver/Server/SessionManager.cpp | 12 | ||||
-rw-r--r-- | src/server/bnetserver/Server/SessionManager.h | 20 | ||||
-rw-r--r-- | src/server/bnetserver/bnetserver.conf.dist | 4 |
15 files changed, 283 insertions, 187 deletions
diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 662a015dc65..15302c74ac6 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -77,7 +77,7 @@ void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInte } void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup) + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; @@ -90,15 +90,11 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address cons realm.allowedSecurityLevel = allowedSecurityLevel; realm.populationLevel = population; - // Append port to IP address. - realm.ExternalAddress = address; realm.LocalAddress = localAddr; realm.LocalSubnetMask = localSubmask; realm.port = port; realm.gamebuild = build; - realm.Region = region; - realm.Battlegroup = battlegroup; } void RealmList::UpdateIfNeed() @@ -174,11 +170,9 @@ void RealmList::UpdateRealms(bool init) uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); uint32 build = fields[11].GetUInt32(); - uint8 region = fields[12].GetUInt8(); - uint8 battlegroup = fields[13].GetUInt8(); UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, - (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); if (init) TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index f7a98cda686..9d5771144a9 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -54,8 +54,6 @@ struct Realm AccountTypes allowedSecurityLevel; float populationLevel; uint32 gamebuild; - uint8 Region; - uint8 Battlegroup; ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; }; @@ -89,7 +87,7 @@ private: void UpdateRealms(bool init = false); void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup); + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index e208f3cd1d9..5e0d728d724 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -99,14 +99,7 @@ int main(int argc, char** argv) return 1; // Get the list of realms for the server - sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); - - if (sRealmList->size() == 0) - { - TC_LOG_ERROR("server.bnetserver", "No valid realms specified."); - StopDB(); - return 1; - } + sRealmList->Initialize(_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10)); // Start the listening port (acceptor) for auth connections int32 bnport = sConfigMgr->GetIntDefault("BattlenetPort", 1119); diff --git a/src/server/bnetserver/Packets/FriendsPackets.cpp b/src/server/bnetserver/Packets/FriendsPackets.cpp index 784d6980777..cd920e91c9c 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.cpp +++ b/src/server/bnetserver/Packets/FriendsPackets.cpp @@ -18,23 +18,22 @@ #include "Session.h" #include "FriendsPackets.h" -void Battlenet::Friends::SocialnetworkCheckConnected::Read() +void Battlenet::Friends::SocialNetworkCheckConnected::Read() { SocialNetworkId = _stream.Read<uint32>(32); } -std::string Battlenet::Friends::SocialnetworkCheckConnected::ToString() const +std::string Battlenet::Friends::SocialNetworkCheckConnected::ToString() const { - return "Battlenet::Friends::SocialnetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); + return "Battlenet::Friends::SocialNetworkCheckConnected SocialNetworkId " + std::to_string(SocialNetworkId); } -void Battlenet::Friends::SocialnetworkCheckConnected::CallHandler(Session* session) const +void Battlenet::Friends::SocialNetworkCheckConnected::CallHandler(Session* session) const { - SocialNetworkCheckConnectedResult* result = new SocialNetworkCheckConnectedResult(SocialNetworkId); - session->AsyncWrite(result); + session->HandleSocialNetworkCheckConnected(*this); } -void Battlenet::Friends::SocialnetworkConnect::Read() +void Battlenet::Friends::SocialNetworkConnect::Read() { int32 unk1 = _stream.Read<int32>(32); uint32 size1 = _stream.Read<uint32>(9); @@ -43,12 +42,12 @@ void Battlenet::Friends::SocialnetworkConnect::Read() auto data2 = _stream.ReadBytes(size2); } -std::string Battlenet::Friends::SocialnetworkConnect::ToString() const +std::string Battlenet::Friends::SocialNetworkConnect::ToString() const { - return "Battlenet::Friends::SocialnetworkConnect"; + return "Battlenet::Friends::SocialNetworkConnect"; } -void Battlenet::Friends::SocialnetworkConnect::CallHandler(Session* session) const +void Battlenet::Friends::SocialNetworkConnect::CallHandler(Session* session) const { session->LogUnhandledPacket(*this); } @@ -70,8 +69,7 @@ std::string Battlenet::Friends::SocialNetworkCheckConnectedResult::ToString() co void Battlenet::Friends::SocialNetworkCheckConnectedResult::Write() { _stream.Write(0, 23); // Ignored - volatile uint16 res = 0; - _stream.Write(res, 16); // Unknown + _stream.Write(0, 16); // Unknown _stream.Write(SocialNetworkId, 32); } diff --git a/src/server/bnetserver/Packets/FriendsPackets.h b/src/server/bnetserver/Packets/FriendsPackets.h index a0ef6f4a63f..ec20f202098 100644 --- a/src/server/bnetserver/Packets/FriendsPackets.h +++ b/src/server/bnetserver/Packets/FriendsPackets.h @@ -54,10 +54,10 @@ namespace Battlenet SMSG_FRIENDS_LIST_NOTIFY_3 = 0x18 // Not implemented }; - class SocialnetworkConnect final : public ClientPacket + class SocialNetworkConnect final : public ClientPacket { public: - SocialnetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + SocialNetworkConnect(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS) && "Invalid packet header for SocialnetworkConnect"); } @@ -78,10 +78,10 @@ namespace Battlenet std::string ToString() const override; }; - class SocialnetworkCheckConnected final : public ClientPacket + class SocialNetworkCheckConnected final : public ClientPacket { public: - SocialnetworkCheckConnected(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + SocialNetworkCheckConnected(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) { ASSERT(header == PacketHeader(CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS) && "Invalid packet header for SocialNetworkCheckConnected"); } @@ -96,7 +96,8 @@ namespace Battlenet class SocialNetworkCheckConnectedResult final : public ServerPacket { public: - SocialNetworkCheckConnectedResult(uint32 socialNetworkId) : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), SocialNetworkId(socialNetworkId) + SocialNetworkCheckConnectedResult() : ServerPacket(PacketHeader(SMSG_SOCIAL_NETWORK_CHECK_CONNECTED_RESULT, FRIENDS)), + SocialNetworkId(0) { } diff --git a/src/server/bnetserver/Packets/PacketFactory.h b/src/server/bnetserver/Packets/PacketFactory.h index 4ae6338cfd7..418e56abea4 100644 --- a/src/server/bnetserver/Packets/PacketFactory.h +++ b/src/server/bnetserver/Packets/PacketFactory.h @@ -57,10 +57,11 @@ namespace Battlenet _creators[PacketHeader(Connection::CMSG_LOGOUT_REQUEST, CONNECTION)] = &New<Connection::LogoutRequest>; _creators[PacketHeader(WoWRealm::CMSG_LIST_SUBSCRIBE_REQUEST, WOWREALM)] = &New<WoWRealm::ListSubscribeRequest>; + _creators[PacketHeader(WoWRealm::CMSG_LIST_UNSUBSCRIBE, WOWREALM)] = &New<WoWRealm::ListUnsubscribe>; _creators[PacketHeader(WoWRealm::CMSG_JOIN_REQUEST_V2, WOWREALM)] = &New<WoWRealm::JoinRequestV2>; - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New<Friends::SocialnetworkCheckConnected>; - _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New<Friends::SocialnetworkConnect>; + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CHECK_CONNECTED, FRIENDS)] = &New<Friends::SocialNetworkCheckConnected>; + _creators[PacketHeader(Friends::CMSG_SOCIAL_NETWORK_CONNECT, FRIENDS)] = &New<Friends::SocialNetworkConnect>; _creators[PacketHeader(Friends::CMSG_GET_FRIENDS_OF_FRIEND, FRIENDS)] = &New<Friends::GetFriendsOfFriend>; _creators[PacketHeader(Friends::CMSG_REALID_FRIEND_INVITE, FRIENDS)] = &New<Friends::RealIdFriendInvite>; diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.cpp b/src/server/bnetserver/Packets/WoWRealmPackets.cpp index 6845fc914b1..95176963c18 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.cpp +++ b/src/server/bnetserver/Packets/WoWRealmPackets.cpp @@ -30,6 +30,16 @@ void Battlenet::WoWRealm::ListSubscribeRequest::CallHandler(Session* session) co session->HandleListSubscribeRequest(*this); } +std::string Battlenet::WoWRealm::ListUnsubscribe::ToString() const +{ + return "Battlenet::WoWRealm::ListUnsubscribe"; +} + +void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session) const +{ + session->HandleListUnsubscribe(*this); +} + Battlenet::WoWRealm::ListSubscribeResponse::~ListSubscribeResponse() { for (ServerPacket* realmData : RealmData) @@ -95,7 +105,7 @@ void Battlenet::WoWRealm::ListUpdate::Write() if (!Version.empty()) { _stream.WriteString(Version, 5); - _stream.Write(Build, 32); + _stream.Write(Id.Build, 32); boost::asio::ip::address_v4::bytes_type ip = Address.address().to_v4().to_bytes(); uint16 port = Address.port(); @@ -110,16 +120,16 @@ void Battlenet::WoWRealm::ListUpdate::Write() _stream.WriteString(Name, 10); } - _stream.Write(Battlegroup, 8); - _stream.Write(Index, 32); - _stream.Write(Region, 8); + _stream.Write(Id.Battlegroup, 8); + _stream.Write(Id.Index, 32); + _stream.Write(Id.Region, 8); } std::string Battlenet::WoWRealm::ListUpdate::ToString() const { std::ostringstream stream; stream << "Battlenet::WoWRealm::ListUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name - << " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index; + << " Flags " << uint32(Flags) << " Region " << uint32(Id.Region) << " Battlegroup " << uint32(Id.Battlegroup) << " Index " << Id.Index; if (!Version.empty()) stream << " Version " << Version; diff --git a/src/server/bnetserver/Packets/WoWRealmPackets.h b/src/server/bnetserver/Packets/WoWRealmPackets.h index 4ce5ea68835..a27601f7478 100644 --- a/src/server/bnetserver/Packets/WoWRealmPackets.h +++ b/src/server/bnetserver/Packets/WoWRealmPackets.h @@ -53,6 +53,19 @@ namespace Battlenet void CallHandler(Session* session) const override; }; + class ListUnsubscribe final : public ClientPacket + { + public: + ListUnsubscribe(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream) + { + ASSERT(header == PacketHeader(CMSG_LIST_UNSUBSCRIBE, WOWREALM) && "Invalid packet header for ListUnsubscribe"); + } + + void Read() override { } + std::string ToString() const override; + void CallHandler(Session* session) const override; + }; + class JoinRequestV2 final : public ClientPacket { public: @@ -110,8 +123,7 @@ namespace Battlenet }; ListUpdate() : ServerPacket(PacketHeader(SMSG_LIST_UPDATE, WOWREALM)), UpdateState(UPDATE), - Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), - Flags(0), Region(0), Battlegroup(0), Index(0), Build(0) + Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""), Flags(0) { } @@ -127,10 +139,7 @@ namespace Battlenet std::string Version; tcp::endpoint Address; uint8 Flags; - uint8 Region; - uint8 Battlegroup; - uint32 Index; - uint32 Build; + RealmId Id; }; class ListComplete final : public ServerPacket diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index 60d40f98edf..6e2c1e99e56 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -18,9 +18,10 @@ #include <boost/asio/ip/tcp.hpp> #include "Common.h" -#include "RealmList.h" #include "Database/DatabaseEnv.h" +#include "SessionManager.h" #include "Util.h" +#include "RealmList.h" ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const { @@ -51,73 +52,71 @@ ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) cons realmIp = ExternalAddress; } - ip::tcp::endpoint endpoint(realmIp, port); + ip::tcp::endpoint endpoint(realmIp, Port); // Return external IP return endpoint; } -RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr) +RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) { } RealmList::~RealmList() { + delete _updateTimer; delete _resolver; } // Load the realm list from the database void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval) { + _updateInterval = updateInterval; + _updateTimer = new boost::asio::deadline_timer(ioService); _resolver = new boost::asio::ip::tcp::resolver(ioService); - m_UpdateInterval = updateInterval; // Get the content of the realmlist table in the database - UpdateRealms(true); + UpdateRealms(boost::system::error_code()); } -void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup) +template<typename FieldType> +inline void UpdateField(FieldType& out, FieldType const& in, bool& changed) { - // Create new if not exist or update existed - Realm& realm = m_realms[name]; - - realm.m_ID = id; - realm.name = name; - realm.icon = icon; - realm.flag = flag; - realm.timezone = timezone; - realm.allowedSecurityLevel = allowedSecurityLevel; - realm.populationLevel = population; - - // Append port to IP address. - - realm.ExternalAddress = address; - realm.LocalAddress = localAddr; - realm.LocalSubnetMask = localSubmask; - realm.port = port; - realm.gamebuild = build; - realm.Region = region; - realm.Battlegroup = battlegroup; + if (out != in) + { + out = in; + changed = true; + } } -void RealmList::UpdateIfNeed() +void RealmList::UpdateRealm(Battlenet::RealmId const& id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, + float population) { - // maybe disabled or updated recently - if (!m_UpdateInterval || m_NextUpdateTime > time(NULL)) - return; - - m_NextUpdateTime = time(NULL) + m_UpdateInterval; - - // Clears Realm list - m_realms.clear(); - - // Get the content of the realmlist table in the database - UpdateRealms(); + // Create new if not exist or update existed + Realm& realm = _realms[id]; + + realm.Keep = true; + realm.Updated = false; + + realm.Id = id; + UpdateField(realm.Name, name, realm.Updated); + UpdateField(realm.Type, icon, realm.Updated); + UpdateField(realm.Flags, flag, realm.Updated); + UpdateField(realm.Timezone, timezone, realm.Updated); + UpdateField(realm.AllowedSecurityLevel, allowedSecurityLevel, realm.Updated); + UpdateField(realm.PopulationLevel, population, realm.Updated); + UpdateField(realm.ExternalAddress, address, realm.Updated); + UpdateField(realm.LocalAddress, localAddr, realm.Updated); + UpdateField(realm.LocalSubnetMask, localSubmask, realm.Updated); + UpdateField(realm.Port, port, realm.Updated); } -void RealmList::UpdateRealms(bool init) +void RealmList::UpdateRealms(boost::system::error_code const& error) { + if (error) + return; + TC_LOG_INFO("server.authserver", "Updating Realm List..."); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST); @@ -133,7 +132,6 @@ void RealmList::UpdateRealms(bool init) boost::asio::ip::tcp::resolver::iterator end; Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); std::string name = fields[1].GetString(); boost::asio::ip::tcp::resolver::query externalAddressQuery(ip::tcp::v4(), fields[2].GetString(), ""); @@ -142,7 +140,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[2].GetString().c_str()); - return; + continue; } ip::address externalAddress = (*endPoint).endpoint().address(); @@ -152,7 +150,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[3].GetString().c_str()); - return; + continue; } ip::address localAddress = (*endPoint).endpoint().address(); @@ -162,7 +160,7 @@ void RealmList::UpdateRealms(bool init) if (endPoint == end || ec) { TC_LOG_ERROR("server.authserver", "Could not resolve address %s", fields[4].GetString().c_str()); - return; + continue; } ip::address localSubmask = (*endPoint).endpoint().address(); @@ -173,15 +171,17 @@ void RealmList::UpdateRealms(bool init) uint8 timezone = fields[8].GetUInt8(); uint8 allowedSecurityLevel = fields[9].GetUInt8(); float pop = fields[10].GetFloat(); + uint32 realmId = fields[0].GetUInt32(); uint32 build = fields[11].GetUInt32(); uint8 region = fields[12].GetUInt8(); uint8 battlegroup = fields[13].GetUInt8(); - UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, - (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup); + Battlenet::RealmId id{ region, battlegroup, realmId, build }; - if (init) - TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port); + UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, + (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); + + //TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[id].ExternalAddress.to_string().c_str(), port); } catch (std::exception& ex) { @@ -191,16 +191,41 @@ void RealmList::UpdateRealms(bool init) } while (result->NextRow()); } + + std::vector<Realm const*> updatedRealms; + std::vector<Battlenet::RealmId> deletedRealms; + + for (RealmMap::value_type const& pair : _realms) + { + if (pair.second.Updated) + updatedRealms.push_back(&pair.second); + if (!pair.second.Keep) + deletedRealms.push_back(pair.first); + } + + for (Battlenet::RealmId const& deleted : deletedRealms) + _realms.erase(deleted); + + if (!updatedRealms.empty() || !deletedRealms.empty()) + { + sSessionMgr.LockedForEach([&updatedRealms, &deletedRealms](Battlenet::Session* session) + { + if (session->IsSubscribedToRealmListUpdates()) + session->UpdateRealms(updatedRealms, deletedRealms); + }); + } + + if (_updateInterval) + { + _updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval)); + _updateTimer->async_wait(std::bind(&RealmList::UpdateRealms, this, std::placeholders::_1)); + } } Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const { - auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair) - { - return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index; - }); - - if (itr != m_realms.end()) + auto itr = _realms.find(id); + if (itr != _realms.end()) return &itr->second; return NULL; diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index 502fef80ee7..c7108101056 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -39,43 +39,55 @@ enum RealmFlags REALM_FLAG_FULL = 0x80 }; -// Storage object for a realm -struct Realm -{ - ip::address ExternalAddress; - ip::address LocalAddress; - ip::address LocalSubnetMask; - uint16 port; - std::string name; - uint8 icon; - RealmFlags flag; - uint8 timezone; - uint32 m_ID; - AccountTypes allowedSecurityLevel; - float populationLevel; - uint32 gamebuild; - uint8 Region; - uint8 Battlegroup; - - ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; -}; +#pragma pack(push, 1) namespace Battlenet { struct RealmId { + RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { } + RealmId(uint8 region, uint8 battlegroup, uint32 index, uint32 build) + : Region(region), Battlegroup(battlegroup), Index(index), Build(build) { } + uint8 Region; uint8 Battlegroup; uint32 Index; uint32 Build; + + bool operator<(RealmId const& r) const + { + return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0; + } }; } +#pragma pack(pop) + +// Storage object for a realm +struct Realm +{ + Battlenet::RealmId Id; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 Port; + std::string Name; + uint8 Type; + RealmFlags Flags; + uint8 Timezone; + AccountTypes AllowedSecurityLevel; + float PopulationLevel; + bool Updated; + bool Keep; + + ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; +}; + /// Storage object for the list of realms on the server class RealmList { public: - typedef std::map<std::string, Realm> RealmMap; + typedef std::map<Battlenet::RealmId, Realm> RealmMap; static RealmList* instance() { @@ -87,25 +99,19 @@ public: void Initialize(boost::asio::io_service& ioService, uint32 updateInterval); - void UpdateIfNeed(); - - void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; } - - RealmMap::const_iterator begin() const { return m_realms.begin(); } - RealmMap::const_iterator end() const { return m_realms.end(); } - uint32 size() const { return m_realms.size(); } + RealmMap const& GetRealms() const { return _realms; } Realm const* GetRealm(Battlenet::RealmId const& id) const; private: RealmList(); - void UpdateRealms(bool init = false); - void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr, - ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build, uint8 region, uint8 battlegroup); + void UpdateRealms(boost::system::error_code const& error); + void UpdateRealm(Battlenet::RealmId const& id, const std::string& name, ip::address const& address, ip::address const& localAddr, + ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population); - RealmMap m_realms; - uint32 m_UpdateInterval; - time_t m_NextUpdateTime; + RealmMap _realms; + uint32 _updateInterval; + boost::asio::deadline_timer* _updateTimer; boost::asio::ip::tcp::resolver* _resolver; }; diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 1d8e0136af3..301a6b9bae1 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -38,7 +38,7 @@ Battlenet::Session::ModuleHandler const Battlenet::Session::ModuleHandlers[MODUL Battlenet::Session::Session(tcp::socket&& socket) : Socket(std::move(socket)), _accountId(0), _accountName(), _locale(), _os(), _build(0), _gameAccountId(0), _gameAccountName(), _accountSecurityLevel(SEC_PLAYER), I(), s(), v(), b(), B(), K(), - _reconnectProof(), _crypt(), _authed(false) + _reconnectProof(), _crypt(), _authed(false), _subscribedToRealmListUpdates(false) { static uint8 const N_Bytes[] = { @@ -398,8 +398,6 @@ void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /* void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& /*listSubscribeRequest*/) { - sRealmList->UpdateIfNeed(); - WoWRealm::ListSubscribeResponse* listSubscribeResponse = new WoWRealm::ListSubscribeResponse(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS); @@ -411,58 +409,29 @@ void Battlenet::Session::HandleListSubscribeRequest(WoWRealm::ListSubscribeReque { Field* fields = countResult->Fetch(); uint32 build = fields[4].GetUInt32(); - listSubscribeResponse->CharacterCounts.push_back({ { fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0) }, fields[0].GetUInt8() }); + listSubscribeResponse->CharacterCounts.push_back({ RealmId(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0)), fields[0].GetUInt8() }); } while (countResult->NextRow()); } - for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i) - { - Realm const& realm = i->second; - - uint32 flag = realm.flag & ~REALM_FLAG_SPECIFYBUILD; - RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild); - if (realm.gamebuild != _build) - { - flag |= REALM_FLAG_INVALID; - if (buildInfo) - flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for - } - - WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); - listUpdate->Timezone = realm.timezone; - listUpdate->Population = realm.populationLevel; - listUpdate->Lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - listUpdate->Type = realm.icon; - listUpdate->Name = realm.name; - - if (flag & REALM_FLAG_SPECIFYBUILD) - { - std::ostringstream version; - version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; - - listUpdate->Version = version.str(); - listUpdate->Address = realm.GetAddressForClient(GetRemoteIpAddress()); - listUpdate->Build = buildInfo->Build; - } - - listUpdate->Flags = flag; - listUpdate->Region = realm.Region; - listUpdate->Battlegroup = realm.Battlegroup; - listUpdate->Index = realm.m_ID; - - listSubscribeResponse->RealmData.push_back(listUpdate); - } + for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms()) + listSubscribeResponse->RealmData.push_back(BuildListUpdate(&i.second)); listSubscribeResponse->RealmData.push_back(new WoWRealm::ListComplete()); AsyncWrite(listSubscribeResponse); + _subscribedToRealmListUpdates = true; +} + +void Battlenet::Session::HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& /*listUnsubscribe*/) +{ + _subscribedToRealmListUpdates = false; } void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest) { WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2(); Realm const* realm = sRealmList->GetRealm(joinRequest.Realm); - if (!realm || realm->flag & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) + if (!realm || realm->Flags & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE)) { joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE; AsyncWrite(joinResponse); @@ -491,13 +460,20 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join LoginDatabase.DirectPExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = %u, failed_logins = 0, os = '%s' WHERE id = %u", ByteArrayToHexStr(sessionKey, 40, true).c_str(), GetRemoteIpAddress().to_string().c_str(), GetLocaleByName(_locale), _os.c_str(), _gameAccountId); - joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->ExternalAddress, realm->Port); if (realm->ExternalAddress != realm->LocalAddress) - joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->port); + joinResponse->IPv4.emplace_back(realm->LocalAddress, realm->Port); AsyncWrite(joinResponse); } +void Battlenet::Session::HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected) +{ + Friends::SocialNetworkCheckConnectedResult* socialNetworkCheckConnectedResult = new Friends::SocialNetworkCheckConnectedResult(); + socialNetworkCheckConnectedResult->SocialNetworkId = socialNetworkCheckConnected.SocialNetworkId; + AsyncWrite(socialNetworkCheckConnectedResult); +} + void Battlenet::Session::ReadHandler() { BitStream stream(std::move(GetReadBuffer())); @@ -998,3 +974,49 @@ bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket ReplaceResponse(response, logonResponse); return false; } + +void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms) +{ + for (Realm const* realm : realms) + AsyncWrite(BuildListUpdate(realm)); + + for (RealmId& deleted : deletedRealms) + { + WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); + listUpdate->UpdateState = WoWRealm::ListUpdate::DELETED; + listUpdate->Id = deleted; + AsyncWrite(listUpdate); + } +} + +Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const* realm) const +{ + uint32 flag = realm->Flags & ~REALM_FLAG_SPECIFYBUILD; + RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm->Id.Build); + if (realm->Id.Build != _build) + { + flag |= REALM_FLAG_INVALID; + if (buildInfo) + flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for + } + + WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate(); + listUpdate->Timezone = realm->Timezone; + listUpdate->Population = realm->PopulationLevel; + listUpdate->Lock = (realm->AllowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; + listUpdate->Type = realm->Type; + listUpdate->Name = realm->Name; + + if (flag & REALM_FLAG_SPECIFYBUILD) + { + std::ostringstream version; + version << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << '.' << buildInfo->Build; + + listUpdate->Version = version.str(); + listUpdate->Address = realm->GetAddressForClient(GetRemoteIpAddress()); + } + + listUpdate->Flags = flag; + listUpdate->Id = realm->Id; + return listUpdate; +} diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index 41caadbab3f..7def3c70460 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -25,6 +25,7 @@ #include <memory> #include <boost/asio/ip/tcp.hpp> +struct Realm; using boost::asio::ip::tcp; namespace Battlenet @@ -73,12 +74,23 @@ namespace Battlenet // WoWRealm void HandleListSubscribeRequest(WoWRealm::ListSubscribeRequest const& listSubscribeRequest); + void HandleListUnsubscribe(WoWRealm::ListUnsubscribe const& listUnsubscribe); void HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& joinRequest); + // Friends + void HandleSocialNetworkCheckConnected(Friends::SocialNetworkCheckConnected const& socialNetworkCheckConnected); + void Start() override; + void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms); + void AsyncWrite(ServerPacket* packet); + uint32 GetAccountId() const { return _accountId; } + uint32 GetGameAccountId() const { return _gameAccountId; } + + bool IsSubscribedToRealmListUpdates() const { return _subscribedToRealmListUpdates; } + protected: void ReadHandler() override; @@ -94,6 +106,8 @@ namespace Battlenet bool HandleResumeModule(BitStream* dataStream, ServerPacket** response); bool UnhandledModule(BitStream* dataStream, ServerPacket** response); + WoWRealm::ListUpdate* BuildListUpdate(Realm const* realm) const; + uint32 _accountId; std::string _accountName; std::string _locale; @@ -121,6 +135,7 @@ namespace Battlenet PacketCrypt _crypt; bool _authed; + bool _subscribedToRealmListUpdates; }; } diff --git a/src/server/bnetserver/Server/SessionManager.cpp b/src/server/bnetserver/Server/SessionManager.cpp index d8b6bfca8d1..caa17364038 100644 --- a/src/server/bnetserver/Server/SessionManager.cpp +++ b/src/server/bnetserver/Server/SessionManager.cpp @@ -35,3 +35,15 @@ void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock) { sSessionMgr.OnSocketOpen(std::forward<tcp::socket>(sock)); } + +void Battlenet::SessionManager::AddSession(Session* session) +{ + std::unique_lock<boost::shared_mutex> lock(_sessionMutex); + _sessions[{ session->GetAccountId(), session->GetGameAccountId() }] = session; +} + +void Battlenet::SessionManager::RemoveSession(Session* session) +{ + std::unique_lock<boost::shared_mutex> lock(_sessionMutex); + _sessions.erase({ session->GetAccountId(), session->GetGameAccountId() }); +} diff --git a/src/server/bnetserver/Server/SessionManager.h b/src/server/bnetserver/Server/SessionManager.h index 10e7196e4d8..4f8e0d9fa97 100644 --- a/src/server/bnetserver/Server/SessionManager.h +++ b/src/server/bnetserver/Server/SessionManager.h @@ -20,6 +20,8 @@ #include "Session.h" #include "SocketMgr.h" +#include <boost/thread/locks.hpp> +#include <boost/thread/shared_mutex.hpp> namespace Battlenet { @@ -28,7 +30,7 @@ namespace Battlenet struct SessionInfo { uint32 AccountId; - uint32 GameAccountIndex; + uint32 GameAccountId; bool operator<(SessionInfo const& right) const { @@ -41,6 +43,7 @@ namespace Battlenet class SessionManager : SocketMgr<Session> { typedef SocketMgr<Session> BaseSocketMgr; + typedef std::map<SessionInfo, Session*> SessionMap; public: static SessionManager& Instance() @@ -52,9 +55,17 @@ namespace Battlenet bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) override; // noop for now, will be needed later to broadcast realmlist updates for example - void AddSession(Session* /*session*/) { } + void AddSession(Session* /*session*/); - void RemoveSession(Session* /*session*/) { } + void RemoveSession(Session* /*session*/); + + template<typename Iterator> + void LockedForEach(Iterator iterator) + { + boost::shared_lock<boost::shared_mutex> lock(_sessionMutex); + for (SessionMap::value_type const& pair : _sessions) + iterator(pair.second); + } protected: NetworkThread<Session>* CreateThreads() const override; @@ -62,7 +73,8 @@ namespace Battlenet private: static void OnSocketAccept(tcp::socket&& sock); - std::map<SessionInfo, Session> _sessions; + SessionMap _sessions; + boost::shared_mutex _sessionMutex; }; } diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 2ca57cea20c..ac02a06c918 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -91,10 +91,10 @@ ProcessPriority = 0 # # RealmsStateUpdateDelay # Description: Time (in seconds) between realm list updates. -# Default: 20 - (Enabled) +# Default: 10 # 0 - (Disabled) -RealmsStateUpdateDelay = 20 +RealmsStateUpdateDelay = 10 # # WrongPass.MaxCount |