diff --git a/common/database.cpp b/common/database.cpp index b14e8009b..c492f975a 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1469,41 +1469,25 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 return base_cap; } -uint32 Database::GetCharacterInfo( - const char *iName, - uint32 *oAccID, - uint32 *oZoneID, - uint32 *oInstanceID, - float *oX, - float *oY, - float *oZ -) +uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id) { - std::string query = StringFormat( - "SELECT `id`, `account_id`, `zone_id`, `zone_instance`, `x`, `y`, `z` FROM `character_data` WHERE `name` = '%s'", - EscapeString(iName).c_str() + auto query = fmt::format( + "SELECT `id`, `account_id`, `zone_id`, `zone_instance` FROM `character_data` WHERE `name` = '{}'", + EscapeString(character_name) ); auto results = QueryDatabase(query); - - if (!results.Success()) { + if (!results.Success() || !results.RowCount()) { return 0; } - if (results.RowCount() != 1) { - return 0; - } + auto row = results.begin(); + auto character_id = std::stoul(row[0]); + *account_id = std::stoul(row[1]); + *zone_id = std::stoul(row[2]); + *instance_id = std::stoul(row[3]); - auto row = results.begin(); - uint32 charid = atoi(row[0]); - if (oAccID) { *oAccID = atoi(row[1]); } - if (oZoneID) { *oZoneID = atoi(row[2]); } - if (oInstanceID) { *oInstanceID = atoi(row[3]); } - if (oX) { *oX = atof(row[4]); } - if (oY) { *oY = atof(row[5]); } - if (oZ) { *oZ = atof(row[6]); } - - return charid; + return character_id; } bool Database::UpdateLiveChar(char* charname, uint32 account_id) { @@ -1627,29 +1611,36 @@ uint32 Database::GetGroupID(const char* name){ return atoi(row[0]); } -/* Is this really getting used properly... A half implementation ? Akkadius */ -char* Database::GetGroupLeaderForLogin(const char* name, char* leaderbuf) { - strcpy(leaderbuf, ""); +std::string Database::GetGroupLeaderForLogin(std::string character_name) { uint32 group_id = 0; - std::string query = StringFormat("SELECT `groupid` FROM `group_id` WHERE `name` = '%s'", name); + auto query = fmt::format( + "SELECT `groupid` FROM `group_id` WHERE `name` = '{}'", + character_name + ); auto results = QueryDatabase(query); - for (auto row = results.begin(); row != results.end(); ++row) - if (row[0]) - group_id = atoi(row[0]); + if (results.Success() && results.RowCount()) { + auto row = results.begin(); + group_id = std::stoul(row[0]); + } - if (group_id == 0) - return leaderbuf; + if (!group_id) { + return std::string(); + } - query = StringFormat("SELECT `leadername` FROM `group_leaders` WHERE `gid` = '%u' LIMIT 1", group_id); + query = fmt::format( + "SELECT `leadername` FROM `group_leaders` WHERE `gid` = {} LIMIT 1", + group_id + ); results = QueryDatabase(query); - for (auto row = results.begin(); row != results.end(); ++row) - if (row[0]) - strcpy(leaderbuf, row[0]); + if (results.Success() && results.RowCount()) { + auto row = results.begin(); + return row[0]; + } - return leaderbuf; + return std::string(); } void Database::SetGroupLeaderName(uint32 gid, const char* name) { @@ -2244,28 +2235,32 @@ bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year } int Database::GetIPExemption(std::string account_ip) { - std::string query = StringFormat("SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '%s'", account_ip.c_str()); - auto results = QueryDatabase(query); - - if (results.Success() && results.RowCount() > 0) { - auto row = results.begin(); - return atoi(row[0]); - } - - return RuleI(World, MaxClientsPerIP); -} - -void Database::SetIPExemption(std::string account_ip, int exemption_amount) { - std::string query = fmt::format( - "SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'", + auto query = fmt::format( + "SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'", account_ip ); auto results = QueryDatabase(query); + if (!results.Success() || !results.RowCount()) { + return RuleI(World, MaxClientsPerIP); + } + + auto row = results.begin(); + return std::stoi(row[0]); +} + +void Database::SetIPExemption(std::string account_ip, int exemption_amount) { + auto query = fmt::format( + "SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'", + account_ip + ); + uint32 exemption_id = 0; - if (results.Success() && results.RowCount() > 0) { + + auto results = QueryDatabase(query); + if (results.Success() && results.RowCount()) { auto row = results.begin(); - exemption_id = atoi(row[0]); + exemption_id = std::stoul(row[0]); } query = fmt::format( @@ -2274,13 +2269,14 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) { exemption_amount ); - if (exemption_id != 0) { + if (exemption_id) { query = fmt::format( "UPDATE `ip_exemptions` SET `exemption_amount` = {} WHERE `exemption_ip` = '{}'", exemption_amount, account_ip ); } + QueryDatabase(query); } diff --git a/common/database.h b/common/database.h index b11c07671..9a1933b33 100644 --- a/common/database.h +++ b/common/database.h @@ -131,7 +131,7 @@ public: uint32 GetAccountIDByChar(uint32 char_id); uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0); uint32 GetCharacterID(const char *name); - uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0); + uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id); uint32 GetGuildIDByCharID(uint32 char_id); uint32 GetGroupIDByCharID(uint32 char_id); uint32 GetRaidIDByCharID(uint32 char_id); @@ -207,8 +207,8 @@ public: /* Groups */ - char* GetGroupLeaderForLogin(const char* name,char* leaderbuf); - char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); + std::string GetGroupLeaderForLogin(std::string character_name); + char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr); uint32 GetGroupID(const char* name); diff --git a/world/client.cpp b/world/client.cpp index 50689520c..555b0f24c 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -721,38 +721,40 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) { } bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { - if (GetAccountID() == 0) { - LogInfo("Enter world with no logged in account"); + auto account_id = GetAccountID(); + if (!account_id) { + LogInfo("Enter world with no logged in account."); eqs->Close(); return true; } - if(GetAdmin() < 0) - { - LogInfo("Account banned or suspended"); + if (GetAdmin() < 0) { + LogInfo("Account [{}] is banned or suspended.", account_id); eqs->Close(); return true; } - if (RuleB(World, EnableIPExemptions) || RuleI(World, MaxClientsPerIP) >= 0) { + if ( + RuleB(World, EnableIPExemptions) || + RuleI(World, MaxClientsPerIP) > 0 + ) { client_list.GetCLEIP(GetIP()); //Check current CLE Entry IPs against incoming connection } - EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer; - strn0cpy(char_name, ew->name, 64); + auto ew = (EnterWorld_Struct *) app->pBuffer; + strn0cpy(char_name, ew->name, sizeof(char_name)); - EQApplicationPacket *outapp; - uint32 tmpaccid = 0; - charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id); - if (charid == 0) { + uint32 temporary_account_id = 0; + charid = database.GetCharacterInfo(char_name, &temporary_account_id, &zone_id, &instance_id); + if (!charid) { LogInfo("Could not get CharInfo for [{}]", char_name); eqs->Close(); return true; } // Make sure this account owns this character - if (tmpaccid != GetAccountID()) { - LogInfo("This account does not own the character named [{}]", char_name); + if (temporary_account_id != account_id) { + LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id); eqs->Close(); return true; } @@ -761,25 +763,26 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { // (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration) if (!is_player_zoning) { size_t character_limit = EQ::constants::StaticLookup(eqs->ClientVersion())->CharacterCreationLimit; - if (character_limit > EQ::constants::CHARACTER_CREATION_LIMIT) { character_limit = EQ::constants::CHARACTER_CREATION_LIMIT; } - if (eqs->ClientVersion() == EQ::versions::ClientVersion::Titanium) { character_limit = Titanium::constants::CHARACTER_CREATION_LIMIT; } + if (character_limit > EQ::constants::CHARACTER_CREATION_LIMIT) { + character_limit = EQ::constants::CHARACTER_CREATION_LIMIT; + } - std::string tgh_query = StringFormat( - "SELECT " - "`id`, " - "name, " - "`level`, " - "last_login " - "FROM " - "character_data " - "WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit); - auto tgh_results = database.QueryDatabase(tgh_query); + if (eqs->ClientVersion() == EQ::versions::ClientVersion::Titanium) { + character_limit = Titanium::constants::CHARACTER_CREATION_LIMIT; + } + + auto query = fmt::format( + "SELECT `id`, `name`, `level`, `last_login` FROM character_data WHERE `account_id` = {} ORDER BY `name` LIMIT {}", + account_id, + character_limit + ); + auto results = database.QueryDatabase(query); /* Check GoHome */ if (ew->return_home && !ew->tutorial) { bool home_enabled = false; - for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { - if (strcasecmp(row[1], char_name) == 0) { + for (auto row : results) { + if (!strcasecmp(row[1], char_name)) { if (RuleB(World, EnableReturnHomeButton)) { int now = time(nullptr); if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) { @@ -792,9 +795,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if (home_enabled) { zone_id = database.MoveCharacterToBind(charid, 4); - } - else { - LogInfo("[{}] is trying to go home before they're able", char_name); + } else { + LogInfo("[{}] is trying to go home before they're able.", char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able."); eqs->Close(); return true; @@ -804,9 +806,12 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { /* Check Tutorial*/ if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) { bool tutorial_enabled = false; - for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { - if (strcasecmp(row[1], char_name) == 0) { - if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) { + for (auto row : results) { + if (!strcasecmp(row[1], char_name)) { + if ( + RuleB(World, EnableTutorialButton) && + std::stoi(row[2]) <= RuleI(World, MaxLevelForTutorial) + ) { tutorial_enabled = true; break; } @@ -816,9 +821,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if (tutorial_enabled) { zone_id = RuleI(World, TutorialZoneID); database.MoveCharacterToZone(charid, zone_id); - } - else { - LogInfo("[{}] is trying to go to tutorial but are not allowed", char_name); + } else { + LogInfo("[{}] is trying to go to the Tutorial but they are not allowed.", char_name); database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character."); eqs->Close(); return true; @@ -826,17 +830,17 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { } } - if (zone_id == 0 || !ZoneName(zone_id)) { + if (!zone_id || !ZoneName(zone_id)) { // This is to save people in an invalid zone, once it's removed from the DB database.MoveCharacterToZone(charid, ZoneID("arena")); - LogInfo("Zone not found in database zone_id=[{}], moveing char to arena character:[{}]", zone_id, char_name); + LogInfo("Zone [{}] not found, moving [{}] to Arena.", zone_id, char_name); } - if(instance_id > 0) - { - if (!database.VerifyInstanceAlive(instance_id, GetCharID()) || - !database.VerifyZoneInstance(zone_id, instance_id)) - { + if (instance_id) { + if ( + !database.VerifyInstanceAlive(instance_id, GetCharID()) || + !database.VerifyZoneInstance(zone_id, instance_id) + ) { zone_id = database.MoveCharacterToInstanceSafeReturn(charid, zone_id, instance_id); instance_id = 0; } @@ -845,83 +849,80 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if(!is_player_zoning) { database.SetGroupID(char_name, 0, charid); database.SetLoginFlags(charid, false, false, 1); - } - else{ - uint32 groupid = database.GetGroupID(char_name); - if(groupid > 0){ - char* leader = 0; - char leaderbuf[64] = {0}; - if((leader = database.GetGroupLeaderForLogin(char_name, leaderbuf)) && strlen(leader)>1){ - auto outapp3 = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); - GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer; + } else { + auto group_id = database.GetGroupID(char_name); + if (group_id) { + auto leader_name = database.GetGroupLeaderForLogin(char_name); + if (!leader_name.empty()) { + auto pack = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct)); + auto gj = (GroupJoin_Struct*) pack->pBuffer; gj->action=8; - strcpy(gj->yourname, char_name); - strcpy(gj->membername, leader); - QueuePacket(outapp3); - safe_delete(outapp3); + strn0cpy(gj->yourname, char_name, sizeof(gj->yourname)); + strn0cpy(gj->membername, leader_name.c_str(), sizeof(gj->membername)); + QueuePacket(pack); + safe_delete(pack); } } } - outapp = new EQApplicationPacket(OP_MOTD); - std::string tmp; - if (database.GetVariable("MOTD", tmp)) { - outapp->size = tmp.length() + 1; + auto outapp = new EQApplicationPacket(OP_MOTD); + std::string motd_message; + if (database.GetVariable("MOTD", motd_message)) { + outapp->size = motd_message.length() + 1; outapp->pBuffer = new uchar[outapp->size]; - memset(outapp->pBuffer,0,outapp->size); - strcpy((char*)outapp->pBuffer, tmp.c_str()); - - } else { - // Null Message of the Day. :) + memset(outapp->pBuffer, 0, outapp->size); + strcpy((char*)outapp->pBuffer, motd_message.c_str()); + } else { // Null Message of the Day. :) outapp->size = 1; outapp->pBuffer = new uchar[outapp->size]; outapp->pBuffer[0] = 0; } + QueuePacket(outapp); safe_delete(outapp); // set mailkey - used for duration of character session - int MailKey = emu_random.Int(1, INT_MAX); + int mail_key = emu_random.Int(1, INT_MAX); - database.SetMailKey(charid, GetIP(), MailKey); + database.SetMailKey(charid, GetIP(), mail_key); if (UCSServerAvailable_) { - const WorldConfig *Config = WorldConfig::get(); + auto config = WorldConfig::get(); std::string buffer; - EQ::versions::UCSVersion ConnectionType = EQ::versions::ucsUnknown; + auto connection_type = EQ::versions::ucsUnknown; // chat server packet switch (GetClientVersion()) { - case EQ::versions::ClientVersion::Titanium: - ConnectionType = EQ::versions::ucsTitaniumChat; - break; - case EQ::versions::ClientVersion::SoF: - ConnectionType = EQ::versions::ucsSoFCombined; - break; - case EQ::versions::ClientVersion::SoD: - ConnectionType = EQ::versions::ucsSoDCombined; - break; - case EQ::versions::ClientVersion::UF: - ConnectionType = EQ::versions::ucsUFCombined; - break; - case EQ::versions::ClientVersion::RoF: - ConnectionType = EQ::versions::ucsRoFCombined; - break; - case EQ::versions::ClientVersion::RoF2: - ConnectionType = EQ::versions::ucsRoF2Combined; - break; - default: - ConnectionType = EQ::versions::ucsUnknown; - break; + case EQ::versions::ClientVersion::Titanium: + connection_type = EQ::versions::ucsTitaniumChat; + break; + case EQ::versions::ClientVersion::SoF: + connection_type = EQ::versions::ucsSoFCombined; + break; + case EQ::versions::ClientVersion::SoD: + connection_type = EQ::versions::ucsSoDCombined; + break; + case EQ::versions::ClientVersion::UF: + connection_type = EQ::versions::ucsUFCombined; + break; + case EQ::versions::ClientVersion::RoF: + connection_type = EQ::versions::ucsRoFCombined; + break; + case EQ::versions::ClientVersion::RoF2: + connection_type = EQ::versions::ucsRoF2Combined; + break; + default: + connection_type = EQ::versions::ucsUnknown; + break; } - buffer = StringFormat("%s,%i,%s.%s,%c%08X", - Config->ChatHost.c_str(), - Config->ChatPort, - Config->ShortName.c_str(), + buffer = fmt::format("{},{},{}.{},{}{:08X}", + config->ChatHost, + config->ChatPort, + config->ShortName, GetCharName(), - ConnectionType, - MailKey + static_cast(connection_type), + mail_key ); outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1)); @@ -933,21 +934,21 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { // mail server packet switch (GetClientVersion()) { - case EQ::versions::ClientVersion::Titanium: - ConnectionType = EQ::versions::ucsTitaniumMail; - break; - default: - // retain value from previous switch - break; + case EQ::versions::ClientVersion::Titanium: + connection_type = EQ::versions::ucsTitaniumMail; + break; + default: + // retain value from previous switch + break; } - buffer = StringFormat("%s,%i,%s.%s,%c%08X", - Config->MailHost.c_str(), - Config->MailPort, - Config->ShortName.c_str(), + buffer = fmt::format("{},{},{}.{},{}{:08X}", + config->MailHost, + config->MailPort, + config->ShortName, GetCharName(), - ConnectionType, - MailKey + static_cast(connection_type), + mail_key ); outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1)); diff --git a/world/clientlist.cpp b/world/clientlist.cpp index d2b016af4..8fb35964b 100644 --- a/world/clientlist.cpp +++ b/world/clientlist.cpp @@ -100,67 +100,101 @@ ClientListEntry* ClientList::GetCLE(uint32 iID) { //Check current CLE Entry IPs against incoming connection -void ClientList::GetCLEIP(uint32 iIP) { - ClientListEntry* countCLEIPs = 0; +void ClientList::GetCLEIP(uint32 in_ip) { + ClientListEntry* cle = nullptr; LinkedListIterator iterator(clientlist); - int IPInstances = 0; + int count = 0; iterator.Reset(); - while(iterator.MoreElements()) { - countCLEIPs = iterator.GetData(); - if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0))) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt) - IPInstances++; // Increment the occurences of this IP address - LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); + while (iterator.MoreElements()) { + cle = iterator.GetData(); + if ( + cle->GetIP() == in_ip && + ( + cle->Admin() < RuleI(World, ExemptMaxClientsStatus) || + RuleI(World, ExemptMaxClientsStatus) < 0 + ) + ) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt) + auto ip_string = long2ip(cle->GetIP()); + count++; // Increment the occurences of this IP address + LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}]", cle->LSID(), cle->LSName(), ip_string); + if (RuleB(World, EnableIPExemptions)) { - LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str())); - if (IPInstances > database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str())) { - if(RuleB(World, IPLimitDisconnectAll)) { - LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str()); - DisconnectByIP(iIP); + LogClientLogin( + "Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", + cle->LSID(), + cle->LSName(), + ip_string, + count, + database.GetIPExemption(ip_string) + ); + + auto exemption_amount = database.GetIPExemption(ip_string); + if (exemption_amount > 0 && count > exemption_amount) { + if (RuleB(World, IPLimitDisconnectAll)) { + LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string); + DisconnectByIP(in_ip); return; } else { - LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); - countCLEIPs->SetOnline(CLE_Status::Offline); + LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string); + cle->SetOnline(CLE_Status::Offline); iterator.RemoveCurrent(); continue; } } } else { - if (IPInstances > (RuleI(World, MaxClientsPerIP))) { // If the number of connections exceeds the lower limit + if ( + RuleI(World, MaxClientsPerIP) > 0 && + count > RuleI(World, MaxClientsPerIP) + ) { // If the number of connections exceeds the lower limit if (RuleB(World, MaxClientsSetByStatus)) { // If MaxClientsSetByStatus is set to True, override other IP Limit Rules - LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, countCLEIPs->Admin()); - if (IPInstances > countCLEIPs->Admin()) { // The IP Limit is set by the status of the account if status > MaxClientsPerIP - if(RuleB(World, IPLimitDisconnectAll)) { - LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str()); - DisconnectByIP(iIP); + LogClientLogin( + "Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", + cle->LSID(), + cle->LSName(), + ip_string, + count, + cle->Admin() + ); + + if (count > cle->Admin()) { // The IP Limit is set by the status of the account if status > MaxClientsPerIP + if (RuleB(World, IPLimitDisconnectAll)) { + LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string); + DisconnectByIP(in_ip); return; } else { - LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); - countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection + LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string); + cle->SetOnline(CLE_Status::Offline); // Remove the connection iterator.RemoveCurrent(); continue; } } - } else if ((countCLEIPs->Admin() < RuleI(World, AddMaxClientsStatus)) || (RuleI(World, AddMaxClientsStatus) < 0)) { // Else if the Admin status of the connection is not eligible for the higher limit, or there is no higher limit (AddMaxClientStatus < 0) - if(RuleB(World, IPLimitDisconnectAll)) { - LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str()); - DisconnectByIP(iIP); + } else if ( + cle->Admin() < RuleI(World, AddMaxClientsStatus) || + RuleI(World, AddMaxClientsStatus) < 0 + ) { // Else if the Admin status of the connection is not eligible for the higher limit, or there is no higher limit (AddMaxClientStatus < 0) + if (RuleB(World, IPLimitDisconnectAll)) { + LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string); + DisconnectByIP(in_ip); return; } else { - LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); - countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection + LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string); + cle->SetOnline(CLE_Status::Offline); // Remove the connection iterator.RemoveCurrent(); continue; } - } else if (IPInstances > RuleI(World, AddMaxClientsPerIP)) { // else they are eligible for the higher limit, but if they exceed that - if(RuleB(World, IPLimitDisconnectAll)) { - LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str()); - DisconnectByIP(iIP); + } else if ( + RuleI(World, AddMaxClientsPerIP) > 0 && + count > RuleI(World, AddMaxClientsPerIP) + ) { // else they are eligible for the higher limit, but if they exceed that + if (RuleB(World, IPLimitDisconnectAll)) { + LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string); + DisconnectByIP(in_ip); return; } else { - LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str()); - countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection + LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string); + cle->SetOnline(CLE_Status::Offline); // Remove the connection iterator.RemoveCurrent(); continue; } @@ -168,46 +202,54 @@ void ClientList::GetCLEIP(uint32 iIP) { } } } + iterator.Advance(); } } -uint32 ClientList::GetCLEIPCount(uint32 iIP) { - ClientListEntry* countCLEIPs = 0; +uint32 ClientList::GetCLEIPCount(uint32 in_ip) { + ClientListEntry* cle = nullptr; LinkedListIterator iterator(clientlist); - int IPInstances = 0; + int count = 0; iterator.Reset(); while (iterator.MoreElements()) { - countCLEIPs = iterator.GetData(); - if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status::Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt) - IPInstances++; // Increment the occurences of this IP address + cle = iterator.GetData(); + if ( + cle->GetIP() == in_ip && + ( + cle->Admin() < RuleI(World, ExemptMaxClientsStatus) || + RuleI(World, ExemptMaxClientsStatus) < 0 + ) && + cle->Online() >= CLE_Status::Online + ) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt) + count++; // Increment the occurences of this IP address } iterator.Advance(); } - return IPInstances; + return count; } -void ClientList::DisconnectByIP(uint32 iIP) { - ClientListEntry* countCLEIPs = 0; +void ClientList::DisconnectByIP(uint32 in_ip) { + ClientListEntry* cle = nullptr; LinkedListIterator iterator(clientlist); iterator.Reset(); - while(iterator.MoreElements()) { - countCLEIPs = iterator.GetData(); - if ((countCLEIPs->GetIP() == iIP)) { - if(strlen(countCLEIPs->name())) { + while (iterator.MoreElements()) { + cle = iterator.GetData(); + if (cle->GetIP() == in_ip) { + if (strlen(cle->name())) { auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct)); - ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer; - strcpy(skp->adminname, "SessionLimit"); - strcpy(skp->name, countCLEIPs->name()); + auto skp = (ServerKickPlayer_Struct*) pack->pBuffer; + strn0cpy(skp->adminname, "SessionLimit", sizeof(skp->adminname)); + strn0cpy(skp->name, cle->name(), sizeof(skp->name)); skp->adminrank = 255; zoneserver_list.SendPacket(pack); safe_delete(pack); } - countCLEIPs->SetOnline(CLE_Status::Offline); + cle->SetOnline(CLE_Status::Offline); iterator.RemoveCurrent(); } iterator.Advance(); diff --git a/world/clientlist.h b/world/clientlist.h index 2f9583784..2ab6be60d 100644 --- a/world/clientlist.h +++ b/world/clientlist.h @@ -57,9 +57,9 @@ public: ClientListEntry* FindCLEByCharacterID(uint32 iCharID); ClientListEntry* FindCLEByLSID(uint32 iLSID); ClientListEntry* GetCLE(uint32 iID); - void GetCLEIP(uint32 iIP); + void GetCLEIP(uint32 in_ip); uint32 GetCLEIPCount(uint32 iLSAccountID); - void DisconnectByIP(uint32 iIP); + void DisconnectByIP(uint32 in_ip); void CLCheckStale(); void CLEKeepAlive(uint32 numupdates, uint32* wid); void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = AccountStatus::Player, uint32 ip = 0, uint8 local=0); diff --git a/world/main.cpp b/world/main.cpp index ee9f12705..17552952f 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -44,6 +44,7 @@ #include "../common/rulesys.h" #include "../common/platform.h" #include "../common/crash.h" +#include "../common/misc.h" #include "client.h" #include "worlddb.h" @@ -658,7 +659,7 @@ int main(int argc, char **argv) eqsm.OnNewConnection( [&stream_identifier](std::shared_ptr stream) { stream_identifier.AddStream(stream); - LogInfo("New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort())); + LogInfo("New connection from IP {}:{}", long2ip(stream->GetRemoteIP()), ntohs(stream->GetRemotePort())); } ); diff --git a/zone/main.cpp b/zone/main.cpp index f92ea9ea8..15be8f77a 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -36,6 +36,7 @@ #include "../common/memory_mapped_file.h" #include "../common/spdat.h" #include "../common/eqemu_logsys.h" +#include "../common/misc.h" #include "api_service.h" #include "zone_config.h" @@ -514,7 +515,7 @@ int main(int argc, char** argv) { eqsm->OnNewConnection([&stream_identifier](std::shared_ptr stream) { stream_identifier.AddStream(stream); - LogF(Logs::Detail, Logs::WorldServer, "New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort())); + LogInfo("New connection from IP {}:{}", long2ip(stream->GetRemoteIP()), ntohs(stream->GetRemotePort())); }); }