aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2015-06-20 00:59:31 +0200
committerShauren <shauren.trinity@gmail.com>2015-06-20 00:59:31 +0200
commit0e49eefe85790ac365c90202a2e22ce6b266ac31 (patch)
treea1e906d6fb3cf0f0da4fcdf19cd9ed7fab509b28 /src
parentcec05ff07d1751649b6eecff07f23f52ca5443cd (diff)
Core/DBLayer: Sprinkle some async magic on worldserver auth/session load process
* Implemented base for loading account wide data
Diffstat (limited to 'src')
-rw-r--r--src/server/bnetserver/Server/Session.cpp4
-rw-r--r--src/server/game/Accounts/RBAC.cpp22
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Server/WorldSession.cpp131
-rw-r--r--src/server/game/Server/WorldSession.h12
-rw-r--r--src/server/game/Server/WorldSocket.cpp322
-rw-r--r--src/server/game/Server/WorldSocket.h17
-rw-r--r--src/server/game/World/World.cpp22
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp21
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h2
11 files changed, 388 insertions, 171 deletions
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index 89818873335..822a90b5222 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -677,8 +677,8 @@ bool Battlenet::Session::Update()
if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
- _queryCallback(_queryFuture.get());
- _queryCallback = nullptr;
+ auto callback = std::move(_queryCallback);
+ callback(_queryFuture.get());
}
return true;
diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp
index 74ff060636e..3f5cd6b38cf 100644
--- a/src/server/game/Accounts/RBAC.cpp
+++ b/src/server/game/Accounts/RBAC.cpp
@@ -180,7 +180,24 @@ void RBACData::LoadFromDB()
stmt->setUInt32(0, GetId());
stmt->setInt32(1, GetRealmId());
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ LoadFromDBCallback(LoginDatabase.Query(stmt));
+}
+
+PreparedQueryResultFuture RBACData::LoadFromDBAsync()
+{
+ ClearData();
+
+ TC_LOG_DEBUG("rbac", "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str());
+ // Load account permissions (granted and denied) that affect current realm
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+
+ return LoginDatabase.AsyncQuery(stmt);
+}
+
+void RBACData::LoadFromDBCallback(PreparedQueryResult result)
+{
if (result)
{
do
@@ -190,8 +207,7 @@ void RBACData::LoadFromDB()
GrantPermission(fields[0].GetUInt32());
else
DenyPermission(fields[0].GetUInt32());
- }
- while (result->NextRow());
+ } while (result->NextRow());
}
// Add default permissions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 6d56774e447..78110d83726 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -907,6 +907,8 @@ class RBACData
/// Loads all permissions assigned to current account
void LoadFromDB();
+ PreparedQueryResultFuture LoadFromDBAsync();
+ void LoadFromDBCallback(PreparedQueryResult result);
/// Sets security level
void SetSecurityLevel(uint8 id)
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 650e100f514..9e89f4f1380 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -104,7 +104,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet)
}
/// WorldSession constructor
-WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter):
+WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter):
m_muteTime(mute_time),
m_timeOutTime(0),
AntiDOS(this),
@@ -112,6 +112,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr
_player(NULL),
_security(sec),
_accountId(id),
+ _accountName(std::move(name)),
_battlenetAccountId(battlenetAccountId),
m_expansion(expansion),
_warden(NULL),
@@ -711,13 +712,6 @@ void WorldSession::SendConnectToInstance(WorldPackets::Auth::ConnectToSerial ser
SendPacket(connectTo.Write());
}
-void WorldSession::LoadGlobalAccountData()
-{
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA);
- stmt->setUInt32(0, GetAccountId());
- LoadAccountData(CharacterDatabase.Query(stmt), GLOBAL_CACHE_MASK);
-}
-
void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask)
{
for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
@@ -780,13 +774,11 @@ void WorldSession::SetAccountData(AccountDataType type, uint32 time, std::string
_accountData[type].Data = data;
}
-void WorldSession::LoadTutorialsData()
+void WorldSession::LoadTutorialsData(PreparedQueryResult result)
{
memset(_tutorials, 0, sizeof(uint32) * MAX_ACCOUNT_TUTORIAL_VALUES);
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS);
- stmt->setUInt32(0, GetAccountId());
- if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
+ if (result)
for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
_tutorials[i] = (*result)[i].GetUInt32();
@@ -959,6 +951,10 @@ void WorldSession::ProcessQueryCallbacks()
{
PreparedQueryResult result;
+ if (_realmAccountLoginCallback.valid() && _realmAccountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready &&
+ _accountLoginCallback.valid() && _accountLoginCallback.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+ InitializeSessionCallback(_realmAccountLoginCallback.get(), _accountLoginCallback.get());
+
//! HandleCharEnumOpcode and HandleCharUndeleteEnumOpcode
if (_charEnumCallback.IsReady())
{
@@ -1094,15 +1090,118 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os)
void WorldSession::LoadPermissions()
{
uint32 id = GetAccountId();
- std::string name;
- AccountMgr::GetName(id, name);
uint8 secLevel = GetSecurity();
- _RBACData = new rbac::RBACData(id, name, realmHandle.Index, secLevel);
+ TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]",
+ id, _accountName.c_str(), realmHandle.Index, secLevel);
+
+ _RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel);
_RBACData->LoadFromDB();
+}
+
+PreparedQueryResultFuture WorldSession::LoadPermissionsAsync()
+{
+ uint32 id = GetAccountId();
+ uint8 secLevel = GetSecurity();
TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]",
- id, name.c_str(), realmHandle.Index, secLevel);
+ id, _accountName.c_str(), realmHandle.Index, secLevel);
+
+ _RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel);
+ return _RBACData->LoadFromDBAsync();
+}
+
+class AccountInfoQueryHolderPerRealm : public SQLQueryHolder
+{
+public:
+ enum
+ {
+ GLOBAL_ACCOUNT_DATA = 0,
+ TUTORIALS,
+
+ MAX_QUERIES
+ };
+
+ AccountInfoQueryHolderPerRealm() { SetSize(MAX_QUERIES); }
+
+ bool Initialize(uint32 accountId, uint32 /*battlenetAccountId*/)
+ {
+ bool ok = true;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA);
+ stmt->setUInt32(0, accountId);
+ ok = SetPreparedQuery(GLOBAL_ACCOUNT_DATA, stmt) && ok;
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS);
+ stmt->setUInt32(0, accountId);
+ ok = SetPreparedQuery(TUTORIALS, stmt) && ok;
+
+ return ok;
+ }
+};
+
+class AccountInfoQueryHolder : public SQLQueryHolder
+{
+public:
+ enum
+ {
+ MAX_QUERIES
+ };
+
+ AccountInfoQueryHolder() { SetSize(MAX_QUERIES); }
+
+ bool Initialize(uint32 /*accountId*/, uint32 /*battlenetAccountId*/)
+ {
+ bool ok = true;
+
+ return ok;
+ }
+};
+
+void WorldSession::InitializeSession()
+{
+ AccountInfoQueryHolderPerRealm* realmHolder = new AccountInfoQueryHolderPerRealm();
+ if (!realmHolder->Initialize(GetAccountId(), GetBattlenetAccountId()))
+ {
+ delete realmHolder;
+ SendAuthResponse(AUTH_SYSTEM_ERROR, false);
+ return;
+ }
+
+ AccountInfoQueryHolder* holder = new AccountInfoQueryHolder();
+ if (!holder->Initialize(GetAccountId(), GetBattlenetAccountId()))
+ {
+ delete realmHolder;
+ delete holder;
+ SendAuthResponse(AUTH_SYSTEM_ERROR, false);
+ return;
+ }
+
+ _realmAccountLoginCallback = CharacterDatabase.DelayQueryHolder(realmHolder);
+ _accountLoginCallback = LoginDatabase.DelayQueryHolder(holder);
+}
+
+void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder)
+{
+ LoadAccountData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK);
+ LoadTutorialsData(realmHolder->GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS));
+
+ if (!m_inQueue)
+ SendAuthResponse(AUTH_OK, false);
+ else
+ SendAuthWaitQue(0);
+
+ SetInQueue(false);
+ ResetTimeOutTime();
+
+ SendSetTimeZoneInformation();
+ SendFeatureSystemStatusGlueScreen();
+ SendAddonsInfo();
+ SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION));
+ SendTutorialsData();
+
+ delete realmHolder;
+ delete holder;
}
rbac::RBACData* WorldSession::GetRBACData()
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index b46afe6378a..4ea97367d4b 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -743,7 +743,7 @@ struct PacketCounter
class WorldSession
{
public:
- WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter);
+ WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter);
~WorldSession();
bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); }
@@ -768,9 +768,13 @@ class WorldSession
void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0);
void SendClientCacheVersion(uint32 version);
+ void InitializeSession();
+ void InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQueryHolder* holder);
+
rbac::RBACData* GetRBACData();
bool HasPermission(uint32 permissionId);
void LoadPermissions();
+ PreparedQueryResultFuture LoadPermissionsAsync();
void InvalidateRBACData(); // Used to force LoadPermissions at next HasPermission check
AccountTypes GetSecurity() const { return _security; }
@@ -853,10 +857,9 @@ class WorldSession
// Account Data
AccountData const* GetAccountData(AccountDataType type) const { return &_accountData[type]; }
void SetAccountData(AccountDataType type, uint32 time, std::string const& data);
- void LoadGlobalAccountData();
void LoadAccountData(PreparedQueryResult result, uint32 mask);
- void LoadTutorialsData();
+ void LoadTutorialsData(PreparedQueryResult result);
void SendTutorialsData();
void SaveTutorialsData(SQLTransaction& trans);
uint32 GetTutorialInt(uint8 index) const { return _tutorials[index]; }
@@ -1537,6 +1540,8 @@ class WorldSession
void InitializeQueryCallbackParameters();
void ProcessQueryCallbacks();
+ QueryResultHolderFuture _realmAccountLoginCallback;
+ QueryResultHolderFuture _accountLoginCallback;
PreparedQueryResultFuture _addIgnoreCallback;
PreparedQueryResultFuture _stablePetCallback;
QueryCallback<PreparedQueryResult, bool> _charEnumCallback;
@@ -1610,6 +1615,7 @@ class WorldSession
AccountTypes _security;
uint32 _accountId;
+ std::string _accountName;
uint32 _battlenetAccountId;
uint8 m_expansion;
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index bc1306d73e1..15dc782a7de 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -72,6 +72,40 @@ WorldSocket::~WorldSocket()
void WorldSocket::Start()
{
+ std::string ip_address = GetRemoteIpAddress().to_string();
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
+ stmt->setString(0, ip_address);
+ stmt->setUInt32(1, inet_addr(ip_address.c_str()));
+
+ _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1);
+ _queryFuture = LoginDatabase.AsyncQuery(stmt);
+}
+
+void WorldSocket::CheckIpCallback(PreparedQueryResult result)
+{
+ if (result)
+ {
+ bool banned = false;
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[0].GetUInt64() != 0)
+ banned = true;
+
+ if (!fields[1].GetString().empty())
+ _ipCountry = fields[1].GetString();
+
+ } while (result->NextRow());
+
+ if (banned)
+ {
+ SendAuthResponseError(AUTH_REJECT);
+ TC_LOG_ERROR("network", "WorldSocket::CheckIpCallback: Sent Auth Response (IP %s banned).", GetRemoteIpAddress().to_string().c_str());
+ DelayedCloseSocket();
+ return;
+ }
+ }
+
AsyncRead();
MessageBuffer initializer;
@@ -84,6 +118,23 @@ void WorldSocket::Start()
QueuePacket(std::move(initializer), guard);
}
+bool WorldSocket::Update()
+{
+ if (!BaseSocket::Update())
+ return false;
+
+ {
+ std::lock_guard<std::mutex> lock(_queryLock);
+ if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
+ {
+ auto callback = std::move(_queryCallback);
+ callback(_queryFuture.get());
+ }
+ }
+
+ return true;
+}
+
void WorldSocket::HandleSendAuthSession()
{
_encryptSeed.SetRand(16 * 8);
@@ -246,8 +297,8 @@ bool WorldSocket::ReadDataHandler()
return false;
}
- WorldPackets::Auth::AuthSession authSession(std::move(packet));
- authSession.Read();
+ std::shared_ptr<WorldPackets::Auth::AuthSession> authSession = std::make_shared<WorldPackets::Auth::AuthSession>(std::move(packet));
+ authSession->Read();
HandleAuthSession(authSession);
break;
}
@@ -262,8 +313,8 @@ bool WorldSocket::ReadDataHandler()
return false;
}
- WorldPackets::Auth::AuthContinuedSession authSession(std::move(packet));
- authSession.Read();
+ std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet));
+ authSession->Read();
HandleAuthContinuedSession(authSession);
break;
}
@@ -470,23 +521,83 @@ uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet)
return bufferSize - _compressionStream->avail_out;
}
-void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession)
+struct AccountInfo
{
- uint8 security;
- uint32 id;
- LocaleConstant locale;
- SHA1Hash sha;
- BigNumber k;
- bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
+ struct
+ {
+ uint32 Id;
+ bool IsLockedToIP;
+ std::string LastIP;
+ LocaleConstant Locale;
+ std::string OS;
+ bool IsBanned;
+
+ std::string LockCountry;
+ } BattleNet;
+
+ struct
+ {
+ uint32 Id;
+ BigNumber SessionKey;
+ uint8 Expansion;
+ int64 MuteTime;
+ uint32 Recruiter;
+ bool IsRectuiter;
+ AccountTypes Security;
+ bool IsBanned;
+ } Game;
+
+ bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; }
+
+ explicit AccountInfo(Field* fields)
+ {
+ // 0 1 2 3 4 5 6 7 8 9 10
+ // SELECT a.id, a.sessionkey, ba.last_ip, ba.locked, a.expansion, a.mutetime, ba.locale, a.recruiter, ba.os, ba.id, aa.gmLevel,
+ // 11 12 13
+ // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id
+ // FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?)
+ // LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter
+ // WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1
+ Game.Id = fields[0].GetUInt32();
+ Game.SessionKey.SetHexStr(fields[1].GetCString());
+ BattleNet.LastIP = fields[2].GetString();
+ BattleNet.IsLockedToIP = fields[3].GetBool();
+ Game.Expansion = fields[4].GetUInt8();
+ Game.MuteTime = fields[5].GetInt64();
+ BattleNet.Locale = LocaleConstant(fields[6].GetUInt8());
+ Game.Recruiter = fields[7].GetUInt32();
+ BattleNet.OS = fields[8].GetString();
+ BattleNet.Id = fields[9].GetUInt32();
+ Game.Security = AccountTypes(fields[10].GetUInt8());
+ BattleNet.IsBanned = fields[11].GetUInt64() != 0;
+ Game.IsBanned = fields[12].GetUInt64() != 0;
+ Game.IsRectuiter = fields[13].GetUInt32() != 0;
+
+ uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
+ if (Game.Expansion > world_expansion)
+ Game.Expansion = world_expansion;
+
+ if (BattleNet.Locale >= TOTAL_LOCALES)
+ BattleNet.Locale = LOCALE_enUS;
+ }
+};
+void WorldSocket::HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession)
+{
// Get the account information from the auth database
- // 0 1 2 3 4 5 6 7 8
- // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME);
- stmt->setString(0, authSession.Account);
+ stmt->setInt32(0, int32(realmHandle.Index));
+ stmt->setString(1, authSession->Account);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ {
+ std::lock_guard<std::mutex> lock(_queryLock);
+ _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1);
+ _queryFuture = LoginDatabase.AsyncQuery(stmt);
+ }
+}
+void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result)
+{
// Stop if the account is not found
if (!result)
{
@@ -497,32 +608,20 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession
return;
}
- Field* fields = result->Fetch();
-
- uint8 expansion = fields[4].GetUInt8();
- uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION);
- if (expansion > world_expansion)
- expansion = world_expansion;
+ AccountInfo account(result->Fetch());
// For hook purposes, we get Remoteaddress at this point.
std::string address = GetRemoteIpAddress().to_string();
// As we don't know if attempted login process by ip works, we update last_attempt_ip right away
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
-
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
stmt->setString(0, address);
- stmt->setString(1, authSession.Account);
-
+ stmt->setString(1, authSession->Account);
LoginDatabase.Execute(stmt);
// This also allows to check for possible "hack" attempts on account
- // id has to be fetched at this point, so that first actual account response that fails can be logged
- id = fields[0].GetUInt32();
-
- k.SetHexStr(fields[1].GetCString());
-
// even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
- _authCrypt.Init(&k);
+ _authCrypt.Init(&account.Game.SessionKey);
_headerBuffer.Resize(SizeOfClientHeader[1][1]);
// First reject the connection if packet contains invalid data or realm state doesn't allow logging in
@@ -534,7 +633,7 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession
return;
}
- if (authSession.RealmID != realmHandle.Index)
+ if (authSession->RealmID != realmHandle.Index)
{
SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm).");
@@ -542,13 +641,20 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession
return;
}
- std::string os = fields[8].GetString();
-
// Must be done before WorldSession is created
- if (wardenActive && os != "Win" && os != "OSX")
+ bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
+ if (wardenActive && account.BattleNet.OS != "Win" && account.BattleNet.OS != "Wn64" && account.BattleNet.OS != "Mc64")
+ {
+ SendAuthResponseError(AUTH_REJECT);
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), account.BattleNet.OS.c_str());
+ DelayedCloseSocket();
+ return;
+ }
+
+ if (!account.BattleNet.Id || authSession->LoginServerType != 1)
{
SendAuthResponseError(AUTH_REJECT);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str());
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s (%s) attempted to log in using deprecated login method (GRUNT).", authSession->Account.c_str(), address.c_str());
DelayedCloseSocket();
return;
}
@@ -556,151 +662,138 @@ void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession
// Check that Key and account name are the same on client and server
uint32 t = 0;
- sha.UpdateData(authSession.Account);
+ SHA1Hash sha;
+ sha.UpdateData(authSession->Account);
sha.UpdateData((uint8*)&t, 4);
- sha.UpdateData((uint8*)&authSession.LocalChallenge, 4);
+ sha.UpdateData((uint8*)&authSession->LocalChallenge, 4);
sha.UpdateData((uint8*)&_authSeed, 4);
- sha.UpdateBigNumbers(&k, NULL);
+ sha.UpdateBigNumbers(&account.Game.SessionKey, NULL);
sha.Finalize();
- if (memcmp(sha.GetDigest(), authSession.Digest, SHA_DIGEST_LENGTH) != 0)
+ if (memcmp(sha.GetDigest(), authSession->Digest, SHA_DIGEST_LENGTH) != 0)
{
SendAuthResponseError(AUTH_FAILED);
- TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, authSession.Account.c_str(), address.c_str());
+ TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", account.Game.Id, authSession->Account.c_str(), address.c_str());
DelayedCloseSocket();
return;
}
///- Re-check ip locking (same check as in auth).
- if (fields[3].GetUInt8() == 1) // if ip is locked
+ if (account.BattleNet.IsLockedToIP)
+ {
+ if (account.BattleNet.LastIP != address)
+ {
+ SendAuthResponseError(AUTH_FAILED);
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", account.BattleNet.LastIP.c_str(), address.c_str());
+ // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
+ sScriptMgr->OnFailedAccountLogin(account.Game.Id);
+ DelayedCloseSocket();
+ return;
+ }
+ }
+ else if (!account.BattleNet.LockCountry.empty() && !_ipCountry.empty())
{
- if (strcmp(fields[2].GetCString(), address.c_str()) != 0)
+ if (account.BattleNet.LockCountry != _ipCountry)
{
SendAuthResponseError(AUTH_FAILED);
- TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str());
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account country differs. Original country: %s, new country: %s).", account.BattleNet.LockCountry.c_str(), _ipCountry.c_str());
// We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
- sScriptMgr->OnFailedAccountLogin(id);
+ sScriptMgr->OnFailedAccountLogin(account.Game.Id);
DelayedCloseSocket();
return;
}
}
- int64 mutetime = fields[5].GetInt64();
+ int64 mutetime = account.Game.MuteTime;
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
if (mutetime < 0)
{
mutetime = time(NULL) + llabs(mutetime);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
-
stmt->setInt64(0, mutetime);
- stmt->setUInt32(1, id);
-
+ stmt->setUInt32(1, account.Game.Id);
LoginDatabase.Execute(stmt);
}
- locale = LocaleConstant(fields[6].GetUInt8());
- if (locale >= TOTAL_LOCALES)
- locale = LOCALE_enUS;
-
- uint32 recruiter = fields[7].GetUInt32();
-
- uint32 battlenetAccountId = 0;
- if (authSession.LoginServerType == 1)
- battlenetAccountId = Battlenet::AccountMgr::GetIdByGameAccount(id);
-
- // Checks gmlevel per Realm
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
-
- stmt->setUInt32(0, id);
- stmt->setInt32(1, int32(realmHandle.Index));
-
- result = LoginDatabase.Query(stmt);
-
- if (!result)
- security = 0;
- else
- {
- fields = result->Fetch();
- security = fields[0].GetUInt8();
- }
-
- // Re-check account ban (same check as in auth)
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BANS);
-
- stmt->setUInt32(0, id);
- stmt->setString(1, address);
-
- PreparedQueryResult banresult = LoginDatabase.Query(stmt);
-
- if (banresult) // if account banned
+ if (account.IsBanned())
{
SendAuthResponseError(AUTH_BANNED);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
- sScriptMgr->OnFailedAccountLogin(id);
+ sScriptMgr->OnFailedAccountLogin(account.Game.Id);
DelayedCloseSocket();
return;
}
// Check locked state for server
AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit();
- TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security));
- if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType)
+ TC_LOG_DEBUG("network", "Allowed Level: %u Player Level %u", allowedAccountType, account.Game.Security);
+ if (allowedAccountType > SEC_PLAYER && account.Game.Security < allowedAccountType)
{
SendAuthResponseError(AUTH_UNAVAILABLE);
TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
- sScriptMgr->OnFailedAccountLogin(id);
+ sScriptMgr->OnFailedAccountLogin(account.Game.Id);
DelayedCloseSocket();
return;
}
- TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
- authSession.Account.c_str(), address.c_str());
-
- // Check if this user is by any chance a recruiter
- stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER);
-
- stmt->setUInt32(0, id);
-
- result = LoginDatabase.Query(stmt);
-
- bool isRecruiter = false;
- if (result)
- isRecruiter = true;
+ TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", authSession->Account.c_str(), address.c_str());
// Update the last_ip in the database as it was successful for login
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
stmt->setString(0, address);
- stmt->setString(1, authSession.Account);
+ stmt->setString(1, authSession->Account);
LoginDatabase.Execute(stmt);
// At this point, we can safely hook a successful login
- sScriptMgr->OnAccountLogin(id);
+ sScriptMgr->OnAccountLogin(account.Game.Id);
_authed = true;
- _worldSession = new WorldSession(id, battlenetAccountId, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter);
- _worldSession->LoadGlobalAccountData();
- _worldSession->LoadTutorialsData();
- _worldSession->ReadAddonsInfo(authSession.AddonInfo);
- _worldSession->LoadPermissions();
+ _worldSession = new WorldSession(account.Game.Id, std::move(authSession->Account), account.BattleNet.Id, shared_from_this(), account.Game.Security,
+ account.Game.Expansion, mutetime, account.BattleNet.Locale, account.Game.Recruiter, account.Game.IsRectuiter);
+ _worldSession->ReadAddonsInfo(authSession->AddonInfo);
// Initialize Warden system only if it is enabled by config
if (wardenActive)
- _worldSession->InitWarden(&k, os);
+ _worldSession->InitWarden(&account.Game.SessionKey, account.BattleNet.OS);
+
+ _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1);
+ _queryFuture = _worldSession->LoadPermissionsAsync();
+}
+
+void WorldSocket::LoadSessionPermissionsCallback(PreparedQueryResult result)
+{
+ // RBAC must be loaded before adding session to check for skip queue permission
+ _worldSession->GetRBACData()->LoadFromDBCallback(result);
sWorld->AddSession(_worldSession);
}
-void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession)
+void WorldSocket::HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession)
{
- uint32 accountId = PAIR64_LOPART(authSession.Key);
- _type = ConnectionType(PAIR64_HIPART(authSession.Key));
+ _type = ConnectionType(PAIR64_HIPART(authSession->Key));
+ if (_type != CONNECTION_TYPE_INSTANCE)
+ {
+ SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
+ DelayedCloseSocket();
+ return;
+ }
+ uint32 accountId = PAIR64_LOPART(authSession->Key);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION);
stmt->setUInt32(0, accountId);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ {
+ std::lock_guard<std::mutex> lock(_queryLock);
+ _queryCallback = std::bind(&WorldSocket::HandleAuthContinuedSessionCallback, this, authSession, std::placeholders::_1);
+ _queryFuture = LoginDatabase.AsyncQuery(stmt);
+ }
+}
+
+void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result)
+{
if (!result)
{
SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
@@ -708,6 +801,7 @@ void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSe
return;
}
+ uint32 accountId = PAIR64_LOPART(authSession->Key);
Field* fields = result->Fetch();
std::string login = fields[0].GetString();
BigNumber k;
@@ -722,7 +816,7 @@ void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSe
sha.UpdateData((uint8*)&_authSeed, 4);
sha.Finalize();
- if (memcmp(sha.GetDigest(), authSession.Digest, sha.GetLength()))
+ if (memcmp(sha.GetDigest(), authSession->Digest, sha.GetLength()))
{
SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str());
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index b82029f88d5..bb4e3c3ee4a 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -72,6 +72,8 @@ class WorldSocket : public Socket<WorldSocket>
static std::string const ClientConnectionInitialize;
static uint32 const MinSizeForCompression;
+ typedef Socket<WorldSocket> BaseSocket;
+
public:
WorldSocket(tcp::socket&& socket);
~WorldSocket();
@@ -80,6 +82,7 @@ public:
WorldSocket& operator=(WorldSocket const& right) = delete;
void Start() override;
+ bool Update() override;
void SendPacket(WorldPacket const& packet);
@@ -94,6 +97,8 @@ protected:
bool ReadHeaderHandler();
bool ReadDataHandler();
private:
+ void CheckIpCallback(PreparedQueryResult result);
+
/// writes network.opcode log
/// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock
void LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const;
@@ -103,8 +108,11 @@ private:
uint32 CompressPacket(uint8* buffer, WorldPacket const& packet);
void HandleSendAuthSession();
- void HandleAuthSession(WorldPackets::Auth::AuthSession& authSession);
- void HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession);
+ void HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession);
+ void HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result);
+ void HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession);
+ void HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result);
+ void LoadSessionPermissionsCallback(PreparedQueryResult result);
void HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed& connectToFailed);
bool HandlePing(WorldPacket& recvPacket);
@@ -131,6 +139,11 @@ private:
z_stream_s* _compressionStream;
bool _initialized;
+
+ std::mutex _queryLock;
+ PreparedQueryResultFuture _queryFuture;
+ std::function<void(PreparedQueryResult)> _queryCallback;
+ std::string _ipCountry;
};
#endif
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 0e98eb265cc..54c926eea71 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -282,14 +282,7 @@ void World::AddSession_(WorldSession* s)
return;
}
- s->SendAuthResponse(AUTH_OK, false);
-
- s->SendSetTimeZoneInformation();
- s->SendFeatureSystemStatusGlueScreen();
-
- s->SendAddonsInfo();
- s->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION));
- s->SendTutorialsData();
+ s->InitializeSession();
UpdateMaxSessionCounters();
@@ -394,18 +387,7 @@ bool World::RemoveQueuedPlayer(WorldSession* sess)
if ((!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty())
{
WorldSession* pop_sess = m_QueuedPlayer.front();
- pop_sess->SetInQueue(false);
- pop_sess->ResetTimeOutTime();
- pop_sess->SendAuthWaitQue(0);
-
- pop_sess->SendSetTimeZoneInformation();
- pop_sess->SendFeatureSystemStatusGlueScreen();
-
- pop_sess->SendAddonsInfo();
-
- pop_sess->SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION));
- pop_sess->SendTutorialsData();
-
+ pop_sess->InitializeSession();
m_QueuedPlayer.pop_front();
// update iter to point first queued socket or end() if queue is empty now
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 277ccd4569a..53fc0bba831 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -276,7 +276,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_PLAYER_CURRENCY, "DELETE FROM character_currency WHERE CharacterGuid = ?", CONNECTION_ASYNC);
// Account data
- PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_REP_ACCOUNT_DATA, "REPLACE INTO account_data (accountId, type, time, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ACCOUNT_DATA, "DELETE FROM account_data WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA, "SELECT type, time, data FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC);
@@ -284,7 +284,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA, "DELETE FROM character_account_data WHERE guid = ?", CONNECTION_ASYNC);
// Tutorials
- PrepareStatement(CHAR_SEL_TUTORIALS, "SELECT tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7 FROM account_tutorial WHERE accountId = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_TUTORIALS, "SELECT tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7 FROM account_tutorial WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_HAS_TUTORIALS, "SELECT 1 FROM account_tutorial WHERE accountId = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_TUTORIALS, "INSERT INTO account_tutorial(tut0, tut1, tut2, tut3, tut4, tut5, tut6, tut7, accountId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_TUTORIALS, "UPDATE account_tutorial SET tut0 = ?, tut1 = ?, tut2 = ?, tut3 = ?, tut4 = ?, tut5 = ?, tut6 = ?, tut7 = ? WHERE accountId = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index 0b2967f8922..51a0217ac17 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -34,12 +34,17 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_ALL, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC);
- PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION, "SELECT username, sessionkey FROM account WHERE id = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION, "SELECT username, sessionkey FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.sessionkey, ba.last_ip, ba.locked, a.expansion, a.mutetime, ba.locale, a.recruiter, ba.os, ba.id, aa.gmLevel, "
+ "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id "
+ "FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) "
+ "LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter "
+ "WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1", CONNECTION_ASYNC);
+
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_BY_ID, "SELECT 1 FROM account WHERE id = ?", CONNECTION_SYNCH);
@@ -83,8 +88,6 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO, "SELECT a.username, a.last_ip, aa.gmlevel, a.expansion FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST, "SELECT 1 FROM account_access WHERE id = ? AND gmlevel > ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS, "SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_ACCOUNT_RECRUITER, "SELECT 1 FROM account WHERE recruiter = ?", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_BANS, "SELECT 1 FROM account_banned WHERE id = ? AND active = 1 UNION SELECT 1 FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
@@ -103,7 +106,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_INS_FALP_IP_LOGGING, "INSERT INTO logs_ip_actions (account_id,character_guid,type,ip,systemnote,unixtime,time) VALUES ((SELECT id FROM account WHERE username = ?), 0, 1, ?, ?, unix_timestamp(NOW()), NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_BOTH);
PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC);
@@ -113,10 +116,14 @@ void LoginDatabaseConnection::DoPrepareStatements()
#define BnetAccountInfo "ba.id, UPPER(ba.email), ba.locked, ba.lock_country, ba.last_ip, ba.failed_logins, bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, bab.unbandate = bab.bandate"
#define BnetGameAccountInfo "a.id, a.username, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, ab.unbandate = ab.bandate, aa.gmlevel"
- PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", ba.sha_pass_hash, ba.v, ba.s, " BnetGameAccountInfo " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_INFO, "SELECT " BnetAccountInfo ", ba.sha_pass_hash, ba.v, ba.s, " BnetGameAccountInfo
+ " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account"
+ " LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_VS_FIELDS, "UPDATE battlenet_accounts SET v = ?, s = ? WHERE email = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_SESSION_KEY, "UPDATE battlenet_accounts SET sessionKey = ?, online = ? WHERE id = ?", CONNECTION_ASYNC);
- PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT " BnetAccountInfo ", ba.sessionKey, " BnetGameAccountInfo " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? AND a.username = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_BNET_RECONNECT_INFO, "SELECT " BnetAccountInfo ", ba.sessionKey, " BnetGameAccountInfo
+ " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account"
+ " LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID = -1 WHERE ba.email = ? AND a.username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_FAILED_LOGINS, "UPDATE battlenet_accounts SET failed_logins = failed_logins + 1 WHERE email = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS, "SELECT rc.numchars, r.id, r.Region, r.Battlegroup, r.gamebuild FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index c0aa178f199..06d13f29da3 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -101,8 +101,6 @@ enum LoginDatabaseStatements
LOGIN_SEL_ACCOUNT_INFO,
LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST,
LOGIN_SEL_ACCOUNT_ACCESS,
- LOGIN_SEL_ACCOUNT_RECRUITER,
- LOGIN_SEL_BANS,
LOGIN_SEL_ACCOUNT_WHOIS,
LOGIN_SEL_REALMLIST_SECURITY_LEVEL,
LOGIN_DEL_ACCOUNT,