diff options
| author | Shauren <shauren.trinity@gmail.com> | 2016-03-28 17:12:57 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-03-28 17:12:57 +0200 |
| commit | dde620c402daf4ea8d132fb72a77eabc22f7a6d0 (patch) | |
| tree | 7c12161d7a22915736b0c9a106de896eeb283399 /src/server/shared/Realm | |
| parent | 619669c6209441fc2fb5b483d553badee8c30ad5 (diff) | |
Core: Updated to 6.2.4
* Rewrite bnetserver for new authentication protocol
Diffstat (limited to 'src/server/shared/Realm')
| -rw-r--r-- | src/server/shared/Realm/Realm.cpp | 10 | ||||
| -rw-r--r-- | src/server/shared/Realm/Realm.h | 5 | ||||
| -rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 228 | ||||
| -rw-r--r-- | src/server/shared/Realm/RealmList.h | 41 |
4 files changed, 270 insertions, 14 deletions
diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp index fca9e86046c..2af537b45e5 100644 --- a/src/server/shared/Realm/Realm.cpp +++ b/src/server/shared/Realm/Realm.cpp @@ -61,3 +61,13 @@ uint32 const Realm::ConfigIdByType[MAX_CLIENT_REALM_TYPE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; + +std::string Battlenet::RealmHandle::GetAddressString() const +{ + return Trinity::StringFormat("%u-%u-%u", Region, Site, Realm); +} + +std::string Battlenet::RealmHandle::GetSubRegionAddress() const +{ + return Trinity::StringFormat("%u-%u-0", Region, Site); +} diff --git a/src/server/shared/Realm/Realm.h b/src/server/shared/Realm/Realm.h index 9dc672403f7..c9042cb3da7 100644 --- a/src/server/shared/Realm/Realm.h +++ b/src/server/shared/Realm/Realm.h @@ -46,6 +46,7 @@ namespace Battlenet RealmHandle() : Region(0), Site(0), Realm(0) { } RealmHandle(uint8 region, uint8 battlegroup, uint32 index) : Region(region), Site(battlegroup), Realm(index) { } + RealmHandle(uint32 realmAddress) : Region((realmAddress >> 24) & 0xFF), Site((realmAddress >> 16) & 0xFF), Realm(realmAddress & 0xFFFF) { } uint8 Region; uint8 Site; @@ -56,7 +57,9 @@ namespace Battlenet return Realm < r.Realm; } - uint32 GetAddress() const { return ((Site << 16) & 0xFF0000) | uint16(Realm); } + uint32 GetAddress() const { return (Region << 24) | (Site << 16) | uint16(Realm); } + std::string GetAddressString() const; + std::string GetSubRegionAddress() const; }; } diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index 57b9ecb0166..260b120dd8c 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -16,11 +16,16 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Common.h" +#include "RealmList.h" +#include "BattlenetRpcErrorCodes.h" #include "Database/DatabaseEnv.h" +#include "ProtobufJSON.h" +#include "SHA256.h" +#include "BigNumber.h" #include "Util.h" -#include "RealmList.h" -#include <boost/asio/ip/tcp.hpp> +#include "game_utilities_service.pb.h" +#include "RealmList.pb.h" +#include <zlib.h> RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) { @@ -53,16 +58,6 @@ void RealmList::Close() _updateTimer->cancel(); } -template<typename FieldType> -inline void UpdateField(FieldType& out, FieldType const& in, bool& changed) -{ - if (out != in) - { - out = in; - changed = true; - } -} - void RealmList::UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, 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) @@ -163,6 +158,8 @@ void RealmList::UpdateRealms(boost::system::error_code const& error) UpdateRealm(id, build, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); + _subRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString()); + if (!existingRealms.count(id)) TC_LOG_INFO("realmlist", "Added realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port); else @@ -197,3 +194,208 @@ Realm const* RealmList::GetRealm(Battlenet::RealmHandle const& id) const return NULL; } + +RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const +{ + // List of client builds for verbose version info in realmlist packet + static std::vector<RealmBuildInfo> const ClientBuilds = + { + { 21355, 6, 2, 4, ' ' }, + { 20726, 6, 2, 3, ' ' }, + { 20574, 6, 2, 2, 'a' }, + { 20490, 6, 2, 2, 'a' }, + { 15595, 4, 3, 4, ' ' }, + { 14545, 4, 2, 2, ' ' }, + { 13623, 4, 0, 6, 'a' }, + { 13930, 3, 3, 5, 'a' }, // 3.3.5a China Mainland build + { 12340, 3, 3, 5, 'a' }, + { 11723, 3, 3, 3, 'a' }, + { 11403, 3, 3, 2, ' ' }, + { 11159, 3, 3, 0, 'a' }, + { 10505, 3, 2, 2, 'a' }, + { 9947, 3, 1, 3, ' ' }, + { 8606, 2, 4, 3, ' ' }, + { 6141, 1, 12, 3, ' ' }, + { 6005, 1, 12, 2, ' ' }, + { 5875, 1, 12, 1, ' ' }, + }; + + for (std::size_t i = 0; i < ClientBuilds.size(); ++i) + if (ClientBuilds[i].Build == build) + return &ClientBuilds[i]; + + return nullptr; +} + +void RealmList::WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const +{ + for (std::string const& subRegion : GetSubRegions()) + response->add_attribute_value()->set_string_value(subRegion); +} + +std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const +{ + std::vector<uint8> compressed; + if (Realm const* realm = GetRealm(id)) + { + if (!(realm->Flags & REALM_FLAG_OFFLINE) && realm->Build == build) + { + JSON::RealmList::RealmEntry realmEntry; + realmEntry.set_wowrealmaddress(realm->Id.GetAddress()); + realmEntry.set_cfgtimezonesid(1); + realmEntry.set_populationstate(std::max(uint32(realm->PopulationLevel), 1u)); + realmEntry.set_cfgcategoriesid(realm->Timezone); + + JSON::RealmList::ClientVersion* version = realmEntry.mutable_version(); + if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm->Build)) + { + version->set_versionmajor(buildInfo->MajorVersion); + version->set_versionminor(buildInfo->MinorVersion); + version->set_versionrevision(buildInfo->BugfixVersion); + version->set_versionbuild(buildInfo->Build); + } + else + { + version->set_versionmajor(6); + version->set_versionminor(2); + version->set_versionrevision(4); + version->set_versionbuild(realm->Build); + } + + realmEntry.set_cfgrealmsid(realm->Id.Realm); + realmEntry.set_flags(realm->Flags); + realmEntry.set_name(realm->Name); + realmEntry.set_cfgconfigsid(realm->GetConfigId()); + realmEntry.set_cfglanguagesid(1); + + std::string json = "JamJSONRealmEntry:" + JSON::Serialize(realmEntry); + + uLong compressedLength = compressBound(json.length()); + compressed.resize(compressedLength + 4); + *reinterpret_cast<uint32*>(compressed.data()) = json.length() + 1; + + if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1) == Z_OK) + compressed.resize(compressedLength + 4); + else + compressed.clear(); + } + } + + return compressed; +} + +std::vector<uint8> RealmList::GetRealmList(uint32 build, std::string const& subRegion) const +{ + JSON::RealmList::RealmListUpdates realmList; + for (auto const& realm : _realms) + { + if (realm.second.Id.GetSubRegionAddress() != subRegion) + continue; + + uint32 flag = realm.second.Flags; + if (realm.second.Build != build) + flag |= REALM_FLAG_VERSION_MISMATCH; + + JSON::RealmList::RealmState* state = realmList.add_updates(); + state->mutable_update()->set_wowrealmaddress(realm.second.Id.GetAddress()); + state->mutable_update()->set_cfgtimezonesid(1); + state->mutable_update()->set_populationstate((realm.second.Flags & REALM_FLAG_OFFLINE) ? 0u : std::max(uint32(realm.second.PopulationLevel), 1u)); + state->mutable_update()->set_cfgcategoriesid(realm.second.Timezone); + + JSON::RealmList::ClientVersion* version = state->mutable_update()->mutable_version(); + if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.second.Build)) + { + version->set_versionmajor(buildInfo->MajorVersion); + version->set_versionminor(buildInfo->MinorVersion); + version->set_versionrevision(buildInfo->BugfixVersion); + version->set_versionbuild(buildInfo->Build); + } + else + { + version->set_versionmajor(6); + version->set_versionminor(2); + version->set_versionrevision(4); + version->set_versionbuild(realm.second.Build); + } + + state->mutable_update()->set_cfgrealmsid(realm.second.Id.Realm); + state->mutable_update()->set_flags(flag); + state->mutable_update()->set_name(realm.second.Name); + state->mutable_update()->set_cfgconfigsid(realm.second.GetConfigId()); + state->mutable_update()->set_cfglanguagesid(1); + + state->set_deleting(false); + } + + std::string json = "JSONRealmListUpdates:" + JSON::Serialize(realmList); + + uLong compressedLength = compressBound(json.length()); + std::vector<uint8> compressed; + compressed.resize(4 + compressedLength); + *reinterpret_cast<uint32*>(compressed.data()) = json.length() + 1; + + compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1); + + compressed.resize(compressedLength + 4); + + return compressed; +} + +uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, + LocaleConstant locale, std::string const& os, std::string accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const +{ + if (Realm const* realm = GetRealm(Battlenet::RealmHandle(realmAddress))) + { + if (realm->Flags & REALM_FLAG_OFFLINE || realm->Build != build) + return ERROR_USER_SERVER_NOT_PERMITTED_ON_REALM; + + JSON::RealmList::RealmListServerIPAddresses serverAddresses; + JSON::RealmList::RealmIPAddressFamily* addressFamily = serverAddresses.add_families(); + addressFamily->set_family(1); + + JSON::RealmList::IPAddress* address = addressFamily->add_addresses(); + address->set_ip(realm->GetAddressForClient(clientAddress).address().to_string()); + address->set_port(realm->Port); + + std::string json = "JSONRealmListServerIPAddresses:" + JSON::Serialize(serverAddresses); + + uLong compressedLength = compressBound(json.length()); + std::vector<uint8> compressed; + compressed.resize(4 + compressedLength); + *reinterpret_cast<uint32*>(compressed.data()) = json.length() + 1; + + if (compress(compressed.data() + 4, &compressedLength, reinterpret_cast<uint8 const*>(json.c_str()), json.length() + 1) != Z_OK) + return ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE; + + BigNumber serverSecret; + serverSecret.SetRand(8 * 32); + + SHA256Hash wowSessionKey; + wowSessionKey.UpdateData(clientSecret.data(), clientSecret.size()); + wowSessionKey.UpdateData(serverSecret.AsByteArray(32).get(), 32); + wowSessionKey.Finalize(); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); + stmt->setString(0, ByteArrayToHexStr(wowSessionKey.GetDigest(), wowSessionKey.GetLength(), true)); + stmt->setString(1, clientAddress.to_string()); + stmt->setUInt8(2, locale); + stmt->setString(3, os); + stmt->setString(4, accountName); + LoginDatabase.DirectExecute(stmt); + + bgs::protocol::Attribute* attribute = response->add_attribute(); + attribute->set_name("Param_RealmJoinTicket"); + attribute->mutable_value()->set_blob_value(accountName); + + attribute = response->add_attribute(); + attribute->set_name("Param_ServerAddresses"); + attribute->mutable_value()->set_blob_value(compressed.data(), compressedLength + 4); + + attribute = response->add_attribute(); + attribute->set_name("Param_JoinSecret"); + attribute->mutable_value()->set_blob_value(serverSecret.AsByteArray(32).get(), 32); + return ERROR_OK; + } + + return ERROR_UTIL_SERVER_UNKNOWN_REALM; +} diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index 47d501888cd..3a8761e638f 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -28,6 +28,38 @@ using namespace boost::asio; +struct RealmBuildInfo +{ + uint32 Build; + uint32 MajorVersion; + uint32 MinorVersion; + uint32 BugfixVersion; + uint32 HotfixVersion; +}; + +namespace bgs +{ + namespace protocol + { + namespace game_utilities + { + namespace v1 + { + class ClientResponse; + class GetAllValuesForAttributeResponse; + } + } + } +} + +namespace JSON +{ + namespace RealmList + { + class RealmListUpdates; + } +} + /// Storage object for the list of realms on the server class TC_SHARED_API RealmList { @@ -44,6 +76,14 @@ public: RealmMap const& GetRealms() const { return _realms; } Realm const* GetRealm(Battlenet::RealmHandle const& id) const; + RealmBuildInfo const* GetBuildInfo(uint32 build) const; + std::unordered_set<std::string> const& GetSubRegions() const { return _subRegions; } + void WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const; + std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const; + std::vector<uint8> GetRealmList(uint32 build, std::string const& subRegion) const; + uint32 JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, + LocaleConstant locale, std::string const& os, std::string accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const; + private: RealmList(); @@ -52,6 +92,7 @@ private: ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population); RealmMap _realms; + std::unordered_set<std::string> _subRegions; uint32 _updateInterval; boost::asio::deadline_timer* _updateTimer; boost::asio::ip::tcp::resolver* _resolver; |
