aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared/Realm
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-03-28 17:12:57 +0200
committerShauren <shauren.trinity@gmail.com>2016-03-28 17:12:57 +0200
commitdde620c402daf4ea8d132fb72a77eabc22f7a6d0 (patch)
tree7c12161d7a22915736b0c9a106de896eeb283399 /src/server/shared/Realm
parent619669c6209441fc2fb5b483d553badee8c30ad5 (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.cpp10
-rw-r--r--src/server/shared/Realm/Realm.h5
-rw-r--r--src/server/shared/Realm/RealmList.cpp228
-rw-r--r--src/server/shared/Realm/RealmList.h41
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;