Core/Battle.net: Implemented updating realm list after initial login

This commit is contained in:
Shauren
2014-10-11 15:13:30 +02:00
parent 35b14f15e1
commit 56cf7ff2a8
15 changed files with 281 additions and 185 deletions

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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)
{
}

View File

@@ -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>;

View File

@@ -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;

View File

@@ -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

View File

@@ -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)
{
if (out != in)
{
out = in;
changed = true;
}
}
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)
{
// Create new if not exist or update existed
Realm& realm = m_realms[name];
Realm& realm = _realms[id];
realm.m_ID = id;
realm.name = name;
realm.icon = icon;
realm.flag = flag;
realm.timezone = timezone;
realm.allowedSecurityLevel = allowedSecurityLevel;
realm.populationLevel = population;
realm.Keep = true;
realm.Updated = false;
// 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;
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::UpdateIfNeed()
void RealmList::UpdateRealms(boost::system::error_code const& error)
{
// maybe disabled or updated recently
if (!m_UpdateInterval || m_NextUpdateTime > time(NULL))
if (error)
return;
m_NextUpdateTime = time(NULL) + m_UpdateInterval;
// Clears Realm list
m_realms.clear();
// Get the content of the realmlist table in the database
UpdateRealms();
}
void RealmList::UpdateRealms(bool init)
{
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;

View File

@@ -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;
};

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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() });
}

View File

@@ -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;
};
}

View File

@@ -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