From 9297fc38f6816268ed4d031def92f1af117bebc9 Mon Sep 17 00:00:00 2001 From: KimLS Date: Fri, 26 Jul 2019 19:22:29 -0700 Subject: [PATCH 1/5] Log kick events --- zone/aa.cpp | 2 +- zone/client.cpp | 10 ++++++++-- zone/client.h | 2 +- zone/client_packet.cpp | 8 +++----- zone/command.cpp | 6 +++--- zone/inventory.cpp | 4 ++-- zone/lua_client.cpp | 2 +- zone/perl_client.cpp | 2 +- zone/questmgr.cpp | 8 ++++---- zone/trading.cpp | 4 ++-- zone/worldserver.cpp | 2 +- zone/zonedb.cpp | 8 ++++++++ zone/zonedb.h | 1 + 13 files changed, 36 insertions(+), 23 deletions(-) diff --git a/zone/aa.cpp b/zone/aa.cpp index 48ee715f7..4d9854d86 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -489,7 +489,7 @@ void Client::ResetAA() { database.DeleteCharacterLeadershipAAs(CharacterID()); // undefined for these clients if (ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) - Kick(); + Kick("AA Reset on client that doesn't support it"); } void Client::SendClearAA() diff --git a/zone/client.cpp b/zone/client.cpp index 57f6ba865..17521b769 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -845,7 +845,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s { if(AttemptedMessages > RuleI(Chat, MaxMessagesBeforeKick)) { - Kick(); + Kick("Sent too many chat messages at once."); return; } if(GlobalChatLimiterTimer) @@ -2586,13 +2586,19 @@ void Client::SetPVP(bool toggle, bool message) { Save(); } +void Client::Kick(const std::string &reason) { + client_state = CLIENT_KICKED; + + database.CreateKickEvent(GetName(), reason); +} + void Client::WorldKick() { auto outapp = new EQApplicationPacket(OP_GMKick, sizeof(GMKick_Struct)); GMKick_Struct* gmk = (GMKick_Struct *)outapp->pBuffer; strcpy(gmk->name,GetName()); QueuePacket(outapp); safe_delete(outapp); - Kick(); + Kick("World kick issued"); } void Client::GMKill() { diff --git a/zone/client.h b/zone/client.h index 0272fb21b..586541ca6 100644 --- a/zone/client.h +++ b/zone/client.h @@ -371,9 +371,9 @@ public: inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); } - inline void Kick() { client_state = CLIENT_KICKED; } inline void Disconnect() { eqs->Close(); client_state = DISCONNECTED; } inline bool IsLD() const { return (bool) (client_state == CLIENT_LINKDEAD); } + void Kick(const std::string &reason); void WorldKick(); inline uint8 GetAnon() const { return m_pp.anon; } inline PlayerProfile_Struct& GetPP() { return m_pp; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f0eb00d13..2c8636014 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1169,10 +1169,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) Log(Logs::General, Logs::Client_Login, "%s failed zone auth check.", cze->char_name); if (nullptr != client) { client->Save(); - client->Kick(); + client->Kick("Failed auth check"); } - //ret = false; // TODO: Can we tell the client to get lost in a good way - client_state = CLIENT_KICKED; return; } @@ -9756,7 +9754,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) casting_spell_id); database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName()); safe_delete_array(detect); - Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots + Kick("Inventory desync"); // Kick client to prevent client and server from getting out-of-sync inventory slots return; } } @@ -9800,7 +9798,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app) void Client::Handle_OP_MoveMultipleItems(const EQApplicationPacket *app) { - Kick(); // TODO: lets not desync though + Kick("Unimplemented move multiple items"); // TODO: lets not desync though } void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app) diff --git a/zone/command.cpp b/zone/command.cpp index bd5aa71c9..16e4edd55 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -1912,7 +1912,7 @@ void command_permaclass(Client *c, const Seperator *sep) Log(Logs::General, Logs::Normal, "Class change request from %s for %s, requested class:%i", c->GetName(), t->GetName(), atoi(sep->arg[1]) ); t->SetBaseClass(atoi(sep->arg[1])); t->Save(); - t->Kick(); + t->Kick("Class was changed."); } } @@ -3895,7 +3895,7 @@ void command_kick(Client *c, const Seperator *sep) client->Message(0, "You have been kicked by %s", c->GetName()); auto outapp = new EQApplicationPacket(OP_GMKick, 0); client->QueuePacket(outapp); - client->Kick(); + client->Kick("Ordered kicked by command"); c->Message(0, "Kick: local: kicking %s", sep->arg[1]); } } @@ -5187,7 +5187,7 @@ void command_name(Client *c, const Seperator *sep) c->Message(0, "Successfully renamed %s to %s", oldname, sep->arg[1]); // until we get the name packet working right this will work c->Message(0, "Sending player to char select."); - target->Kick(); + target->Kick("Name was changed"); } else c->Message(13, "ERROR: Unable to rename %s. Check that the new name '%s' isn't already taken.", oldname, sep->arg[2]); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index ec4f095b0..96f0fe15b 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1608,7 +1608,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { banker ? banker->GetName() : "UNKNOWN NPC", distance); database.SetMQDetectionFlag(AccountName(), GetName(), hacked_string, zone->GetShortName()); safe_delete_array(hacked_string); - Kick(); // Kicking player to avoid item loss do to client and server inventories not being sync'd + Kick("Inventory desync"); // Kicking player to avoid item loss do to client and server inventories not being sync'd return false; } } @@ -1822,7 +1822,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { // Step 4: Check for entity trade if (dst_slot_id >= EQEmu::invslot::TRADE_BEGIN && dst_slot_id <= EQEmu::invslot::TRADE_END) { if (src_slot_id != EQEmu::invslot::slotCursor) { - Kick(); + Kick("Trade with non-cursor item"); return false; } if (with) { diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 9447c48af..c50f6b2f3 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -47,7 +47,7 @@ bool Lua_Client::InZone() { void Lua_Client::Kick() { Lua_Safe_Call_Void(); - self->Kick(); + self->Kick("Lua Quest"); } void Lua_Client::Disconnect() { diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index be1bf2a8e..f86228feb 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -174,7 +174,7 @@ XS(XS_Client_Kick) { if (THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - THIS->Kick(); + THIS->Kick("Perl Quest"); } XSRETURN_EMPTY; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 79f5af8a5..dafc3f1e6 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -809,7 +809,7 @@ void QuestManager::changedeity(int diety_id) { initiator->SetDeity(diety_id); initiator->Message(15,"Your Deity has been changed/set to: %i", diety_id); initiator->Save(1); - initiator->Kick(); + initiator->Kick("Deity change by QuestManager"); } else { @@ -943,7 +943,7 @@ void QuestManager::permaclass(int class_id) { //Makes the client the class specified initiator->SetBaseClass(class_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base class change by QuestManager"); } void QuestManager::permarace(int race_id) { @@ -951,7 +951,7 @@ void QuestManager::permarace(int race_id) { //Makes the client the race specified initiator->SetBaseRace(race_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base race change by QuestManager"); } void QuestManager::permagender(int gender_id) { @@ -959,7 +959,7 @@ void QuestManager::permagender(int gender_id) { //Makes the client the gender specified initiator->SetBaseGender(gender_id); initiator->Save(2); - initiator->Kick(); + initiator->Kick("Base gender change by QuestManager"); } uint16 QuestManager::scribespells(uint8 max_level, uint8 min_level) { diff --git a/zone/trading.cpp b/zone/trading.cpp index 154fdf148..fe9a72daa 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -112,7 +112,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { // (it just didn't handle partial stack move actions) if (stack_size > 0) { if (!inst->IsStackable() || !inst2 || !inst2->GetItem() || (inst->GetID() != inst2->GetID()) || (stack_size > inst->GetCharges())) { - client->Kick(); + client->Kick("Error stacking item in trade"); return; } @@ -138,7 +138,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) { } else { if (inst2 && inst2->GetID()) { - client->Kick(); + client->Kick("Attempting to add null item to trade"); return; } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 864f11448..c2f913d7d 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -559,7 +559,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) auto client = entity_list.GetClientByLSID(drop->lsid); if (client) { - client->Kick(); + client->Kick("Dropped by world CLE subsystem"); client->Save(); } } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e2825da5a..acf619aba 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3835,6 +3835,14 @@ void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type QueryDatabase(query); } +void ZoneDatabase::CreateKickEvent(const std::string &character_name, const std::string &reason) +{ + std::string query = + StringFormat("INSERT INTO character_kick_events (Name, Reason) VALUES ('%s', '%s')", character_name.c_str(), reason.c_str()); + + QueryDatabase(query); +} + void ZoneDatabase::LoadPetInfo(Client *client) { diff --git a/zone/zonedb.h b/zone/zonedb.h index f2103715a..285166042 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -292,6 +292,7 @@ public: void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp); + void CreateKickEvent(const std::string &character_name, const std::string &reason); bool DeleteCharacterAAs(uint32 character_id); bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id); From 3f2f7b3929f10e27be6ba3f2accb0263676858d9 Mon Sep 17 00:00:00 2001 From: KimLS Date: Fri, 26 Jul 2019 19:23:47 -0700 Subject: [PATCH 2/5] SQL --- .../sql/git/required/2019_07_26_char_kick_events.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 utils/sql/git/required/2019_07_26_char_kick_events.sql diff --git a/utils/sql/git/required/2019_07_26_char_kick_events.sql b/utils/sql/git/required/2019_07_26_char_kick_events.sql new file mode 100644 index 000000000..0b5308be0 --- /dev/null +++ b/utils/sql/git/required/2019_07_26_char_kick_events.sql @@ -0,0 +1,11 @@ +CREATE TABLE `character_kick_events` ( + `Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `Name` VARCHAR(64) NOT NULL, + `Reason` TEXT NOT NULL, + `Created` TIMESTAMP NOT NULL DEFAULT '', + PRIMARY KEY (`Id`), + INDEX `Name` (`Name`), + INDEX `Created` (`Created`) +) +ENGINE=InnoDB +; From b754ddbc6728871cf42109928d3b0d84952d45bd Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 27 Jul 2019 20:13:04 -0700 Subject: [PATCH 3/5] Change drop client code to not be two step process --- world/client.cpp | 4 +--- zone/worldserver.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/world/client.cpp b/world/client.cpp index 022bf0d41..393e9959b 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -1118,6 +1118,7 @@ bool Client::Process() { Log(Logs::General, Logs::World_Server, "Zone bootup timer expired, bootup failed or too slow."); TellClientZoneUnavailable(); } + if(connect.Check()){ SendGuildList();// Send OPCode: OP_GuildsList SendApproveWorld(); @@ -1189,9 +1190,6 @@ void Client::EnterWorld(bool TryBootup) { else zone_server = zoneserver_list.FindByZoneID(zone_id); - //Tell all the zones to drop any client with this lsid because we're coming back in. - zoneserver_list.DropClient(GetLSID()); - const char *zone_name = database.GetZoneName(zone_id, true); if (zone_server) { // warn the world we're comming, so it knows not to shutdown diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index c2f913d7d..ffe777808 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -536,6 +536,13 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) SetZoneData(zone->GetZoneID(), zone->GetInstanceID()); if (szic->zoneid == zone->GetZoneID()) { + auto client = entity_list.GetClientByLSID(szic->lsid); + if (client) { + client->Kick("Dropped by world CLE subsystem"); + client->Save(); + } + + zone->RemoveAuth(szic->lsid); zone->AddAuth(szic); // This packet also doubles as "incoming client" notification, lets not shut down before they get here zone->StartShutdownTimer(AUTHENTICATION_TIMEOUT * 1000); From e56edd923135fc3383f9b83262114a0eb3506fd8 Mon Sep 17 00:00:00 2001 From: KimLS Date: Tue, 30 Jul 2019 19:12:44 -0700 Subject: [PATCH 4/5] Some changes to ordering of login authorization for world<->zone --- world/client.cpp | 30 +++++++++++++++++++++--------- world/client.h | 1 + world/zonelist.cpp | 9 +++++++-- world/zonelist.h | 2 +- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/world/client.cpp b/world/client.cpp index 393e9959b..c29b7d698 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -104,6 +104,7 @@ Client::Client(EQStreamInterface* ieqs) char_name[0] = 0; charid = 0; zone_waiting_for_bootup = 0; + enter_world_triggered = false; StartInTutorial = false; m_ClientVersion = eqs->ClientVersion(); @@ -1192,8 +1193,16 @@ void Client::EnterWorld(bool TryBootup) { const char *zone_name = database.GetZoneName(zone_id, true); if (zone_server) { - // warn the world we're comming, so it knows not to shutdown - zone_server->IncomingClient(this); + if (false == enter_world_triggered) { + //Drop any clients we own in other zones. + zoneserver_list.DropClient(GetLSID(), zone_server); + + // warn the zone we're coming + zone_server->IncomingClient(this); + + //tell the server not to trigger this multiple times before we get a zone unavailable + enter_world_triggered = true; + } } else { if (TryBootup) { @@ -1212,9 +1221,17 @@ void Client::EnterWorld(bool TryBootup) { return; } } + zone_waiting_for_bootup = 0; - if(!cle) { + if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zone_id)) { + Log(Logs::General, Logs::World_Server, "Enter world failed. Zone is locked."); + TellClientZoneUnavailable(); + return; + } + + if (!cle) { + TellClientZoneUnavailable(); return; } @@ -1231,12 +1248,6 @@ void Client::EnterWorld(bool TryBootup) { ); if (seen_character_select) { - if (GetAdmin() < 80 && zoneserver_list.IsZoneLocked(zone_id)) { - Log(Logs::General, Logs::World_Server, "Enter world failed. Zone is locked."); - TellClientZoneUnavailable(); - return; - } - auto pack = new ServerPacket; pack->opcode = ServerOP_AcceptWorldEntrance; pack->size = sizeof(WorldToZone_Struct); @@ -1356,6 +1367,7 @@ void Client::TellClientZoneUnavailable() { zone_id = 0; zone_waiting_for_bootup = 0; + enter_world_triggered = false; autobootup_timeout.Disable(); } diff --git a/world/client.h b/world/client.h index e7ab52fa3..4dbad85c5 100644 --- a/world/client.h +++ b/world/client.h @@ -82,6 +82,7 @@ private: bool is_player_zoning; Timer autobootup_timeout; uint32 zone_waiting_for_bootup; + bool enter_world_triggered; bool StartInTutorial; EQEmu::versions::ClientVersion m_ClientVersion; diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 1d06071c4..77782ee9b 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -708,11 +708,16 @@ void ZSList::WorldShutDown(uint32 time, uint32 interval) } } -void ZSList::DropClient(uint32 lsid) { +void ZSList::DropClient(uint32 lsid, ZoneServer *ignore_zoneserver) { ServerPacket packet(ServerOP_DropClient, sizeof(ServerZoneDropClient_Struct)); auto drop = (ServerZoneDropClient_Struct*)packet.pBuffer; drop->lsid = lsid; - SendPacket(&packet); + + for (auto &zs : zone_server_list) { + if (zs.get() != ignore_zoneserver) { + zs->SendPacket(&packet); + } + } } void ZSList::OnTick(EQ::Timer *t) diff --git a/world/zonelist.h b/world/zonelist.h index b99a88e09..8b8525f57 100644 --- a/world/zonelist.h +++ b/world/zonelist.h @@ -57,7 +57,7 @@ public: void SOPZoneBootup(const char *adminname, uint32 ZoneServerID, const char *zonename, bool iMakeStatic = false); void UpdateUCSServerAvailable(bool ucss_available = true); void WorldShutDown(uint32 time, uint32 interval); - void DropClient(uint32 lsid); + void DropClient(uint32 lsid, ZoneServer *ignore_zoneserver); ZoneServer* FindByPort(uint16 port); ZoneServer* FindByID(uint32 ZoneID); From 17c8af3814ffc216df90575def00c9385709986e Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 10 Aug 2019 02:47:08 -0500 Subject: [PATCH 5/5] Drop db logging, up stale connections --- common/net/daybreak_connection.h | 2 +- ucs/clientlist.cpp | 2 +- .../sql/git/required/2019_07_26_char_kick_events.sql | 11 ----------- zone/client.cpp | 2 +- zone/zonedb.cpp | 8 -------- zone/zonedb.h | 1 - 6 files changed, 3 insertions(+), 23 deletions(-) delete mode 100644 utils/sql/git/required/2019_07_26_char_kick_events.sql diff --git a/common/net/daybreak_connection.h b/common/net/daybreak_connection.h index b4f3ca41c..883ecefac 100644 --- a/common/net/daybreak_connection.h +++ b/common/net/daybreak_connection.h @@ -257,7 +257,7 @@ namespace EQ resend_delay_min = 150; resend_delay_max = 5000; connect_delay_ms = 500; - stale_connection_ms = 30000; + stale_connection_ms = 60000; connect_stale_ms = 5000; crc_length = 2; max_packet_size = 512; diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index a433705e6..26ef62b82 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -471,7 +471,7 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) { Clientlist::Clientlist(int ChatPort) { EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false); chat_opts.opcode_size = 1; - chat_opts.daybreak_options.stale_connection_ms = 300000; + chat_opts.daybreak_options.stale_connection_ms = 600000; chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); diff --git a/utils/sql/git/required/2019_07_26_char_kick_events.sql b/utils/sql/git/required/2019_07_26_char_kick_events.sql deleted file mode 100644 index 0b5308be0..000000000 --- a/utils/sql/git/required/2019_07_26_char_kick_events.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE `character_kick_events` ( - `Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, - `Name` VARCHAR(64) NOT NULL, - `Reason` TEXT NOT NULL, - `Created` TIMESTAMP NOT NULL DEFAULT '', - PRIMARY KEY (`Id`), - INDEX `Name` (`Name`), - INDEX `Created` (`Created`) -) -ENGINE=InnoDB -; diff --git a/zone/client.cpp b/zone/client.cpp index 60a6d1d8c..7e6baf180 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2590,7 +2590,7 @@ void Client::SetPVP(bool toggle, bool message) { void Client::Kick(const std::string &reason) { client_state = CLIENT_KICKED; - database.CreateKickEvent(GetName(), reason); + Log(Logs::General, Logs::Client_Login, "Client [%s] kicked, reason [%s]", GetCleanName(), reason.c_str()); } void Client::WorldKick() { diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index acf619aba..e2825da5a 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3835,14 +3835,6 @@ void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type QueryDatabase(query); } -void ZoneDatabase::CreateKickEvent(const std::string &character_name, const std::string &reason) -{ - std::string query = - StringFormat("INSERT INTO character_kick_events (Name, Reason) VALUES ('%s', '%s')", character_name.c_str(), reason.c_str()); - - QueryDatabase(query); -} - void ZoneDatabase::LoadPetInfo(Client *client) { diff --git a/zone/zonedb.h b/zone/zonedb.h index 285166042..f2103715a 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -292,7 +292,6 @@ public: void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp); - void CreateKickEvent(const std::string &character_name, const std::string &reason); bool DeleteCharacterAAs(uint32 character_id); bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);