From ae233350831992a00b675bf8034de878502cdab7 Mon Sep 17 00:00:00 2001 From: Underlight Development Date: Tue, 18 Dec 2018 17:50:22 -0500 Subject: [PATCH 1/3] first cut of deghost utility --- include/LmPlayerDBC.h | 3 +- libsrc/dbi_mysql/LmPlayerDBC.cpp | 51 ++++++++ libsrc/dbi_mysql/LmPlayerDBC.h | 3 +- util/deghost.cpp | 200 +++++++++++++++++++++++++++++++ util/meson.build | 7 ++ 5 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 util/deghost.cpp diff --git a/include/LmPlayerDBC.h b/include/LmPlayerDBC.h index 540e42d..0c034fd 100644 --- a/include/LmPlayerDBC.h +++ b/include/LmPlayerDBC.h @@ -84,7 +84,8 @@ class LmPlayerDBC { int LocateMares(GMsg_LocateMaresAck* pmare_msg); int FindHouseMembers(GMsg_LocateAvatarAck& locate_msgack, lyra_id_t guild_id, bool gm, lyra_id_t player_id); int NewlyNeedsAnnounce(lyra_id_t player_id, bool* announce); - + int GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned int* num_players, lyra_id_t** player_list); + int ForceDeghost(lyra_id_t player_id); long LastSQLCode() const; void SetLog(LmLog* log); diff --git a/libsrc/dbi_mysql/LmPlayerDBC.cpp b/libsrc/dbi_mysql/LmPlayerDBC.cpp index a30e268..dad4326 100644 --- a/libsrc/dbi_mysql/LmPlayerDBC.cpp +++ b/libsrc/dbi_mysql/LmPlayerDBC.cpp @@ -2315,3 +2315,54 @@ int LmPlayerDBC::LogQuest(lyra_id_t origin_id, lyra_id_t target_id, int art, int return 0; } + +int LmPlayerDBC::GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned int* num_players, lyra_id_t** player_list) +{ + DEFMETHOD(LmPlayerDBC, GetLoggedInPlayersForGamed); + LmLocker mon(lock_); + TCHAR query[512]; + MYSQL_RES* res; + MYSQL_ROW row; + + _stprintf(query, _T("SELECT player_id FROM player WHERE logged_in=1 and gamed_port=%u"), gamed_port); + int error = mysql_query(&m_mysql, query); + if(error) + { + LOG_Error(_T("%s: Could not get logged in players for gamed %u"), method, gamed_port); + return MYSQL_ERROR; + } + + res = mysql_store_result(&m_mysql); + *num_players = mysql_num_rows(res); + + if (!(*num_players)) + { + mysql_free_result(res); + return 0; + } + + *player_list = new lyra_id_t[*num_players]; + for (int i=0; i<*num_players; i++) { + row = mysql_fetch_row(res); + *player_list[i] = ATOI(row[0]); + //player_id = ATOI(row[0]); + } + + return 0; +} + +int LmPlayerDBC::ForceDeghost(lyra_id_t player_id) +{ + DEFMETHOD(LmPlayerDBC, ForceDeghost); + LmLocker mon(lock_); + TCHAR query[512]; + _stprintf(query, _T("UPDATE player SET logged_in=0,level_id=0,room_id=0 WHERE player_id=%u"), player_id); + int error = mysql_query(&m_mysql, query); + if(error) + { + LOG_Error(_T("%s: Could not force deghost player %u for gamed %u"), method, player_id); + return MYSQL_ERROR; + } + + return 0; +} diff --git a/libsrc/dbi_mysql/LmPlayerDBC.h b/libsrc/dbi_mysql/LmPlayerDBC.h index 540e42d..0c034fd 100644 --- a/libsrc/dbi_mysql/LmPlayerDBC.h +++ b/libsrc/dbi_mysql/LmPlayerDBC.h @@ -84,7 +84,8 @@ class LmPlayerDBC { int LocateMares(GMsg_LocateMaresAck* pmare_msg); int FindHouseMembers(GMsg_LocateAvatarAck& locate_msgack, lyra_id_t guild_id, bool gm, lyra_id_t player_id); int NewlyNeedsAnnounce(lyra_id_t player_id, bool* announce); - + int GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned int* num_players, lyra_id_t** player_list); + int ForceDeghost(lyra_id_t player_id); long LastSQLCode() const; void SetLog(LmLog* log); diff --git a/util/deghost.cpp b/util/deghost.cpp new file mode 100644 index 0000000..c3c5003 --- /dev/null +++ b/util/deghost.cpp @@ -0,0 +1,200 @@ +// get_server_status.cpp -*- C++ -*- +// $Id: get_server_status.cpp,v 1.6 1998-02-03 23:38:38-08 jason Exp $ +// Copyright 1996-1997 Lyra LLC, All rights reserved. +// +// program which attempts to make a connection to active Lyra servers, and reports +// their status (contents of status message) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LmGlobalDB.h" +#include "LmSocket.h" +#include "LmServerDBC.h" +#include "LmPlayerDBC.h" +#include "LmConnection.h" +#include "LmSrvMesgBuf.h" +#include "LmServerDBC.h" +#include "SMsg_All.h" + +//void get_status(FILE* outf, LmSocket& sock, bool list_players); +void deghost(int num_players_db, lyra_id_t* players_db, int num_players_server, lyra_id_t* players_server, LmPlayerDBC* pdbc); +void get_logged_in_players(LmSocket& sock, int* num_players, lyra_id_t** players); +void deghost_player(lyra_id_t player, LmPlayerDBC* pdbc); + +void bail(TCHAR* str) +{ + _tprintf(_T("ERROR %s\n"), str); + exit(1); +} + +int _tmain(int argc, TCHAR** argv) +{ + // check args + if (argc != 3) { + bail(_T("usage: deghost root_dir gamed_port")); + } + + pth_init(); + + TCHAR* root_dir = argv[1]; + int gamed_port = _ttoi(argv[2]); + LmGlobalDB* globaldb_ = LmNEW(LmGlobalDB(root_dir)); + LmServerDBC* serverdbc_ = LmNEW(LmServerDBC()); + // load passwords & server info + TCHAR pw_file[FILENAME_MAX]; + globaldb_->GetPasswordFile(pw_file); + serverdbc_->LoadPasswords(pw_file); + LmPlayerDBC* pdbc = LmNEW(LmPlayerDBC(serverdbc_->PlayerDBUsername(), serverdbc_->PlayerDBPassword(), serverdbc_->DatabaseHost(), serverdbc_->DatabasePort())); + serverdbc_->Connect(); + serverdbc_->Load(); + serverdbc_->Disconnect(); + FILE* outf = stdout; + // print time + time_t now = time(NULL); + _ftprintf(outf, _T("TIME %u : %s"), now,_tctime(&now)); //_tctime() adds newline + + // for each server in database + for (int i = 0; i < serverdbc_->NumServers(); ++i) { + // if server arg1 is 0, it's an inactive server, don't try to connect + if (serverdbc_->Arg1(i) == 0) { + continue; + } + + if (serverdbc_->ServerType(i) != 'G') { + continue; + } + + if (serverdbc_->Arg1(i) != gamed_port) { + continue; + } + + // create socket + LmSocket sock; + if (sock.Socket(LmSockType::Inet_Stream()) < 0) { + bail(_T("could not create socket\n")); + } + // get server address + LmSockAddrInet addr; + addr.Init(serverdbc_->HostIPAddr(i), serverdbc_->Arg1(i)); + // print server header + int num_players_db = 0; + lyra_id_t* players_db; + pdbc->GetLoggedInPlayersForGamed(gamed_port, &num_players_db, &players_db); + _ftprintf(outf, _T("SERVER hostid=%s hostname=%s ip=%s type=%c arg1=%d arg2=%d "), + serverdbc_->HostID(i), serverdbc_->HostName(i), addr.AddressString(), serverdbc_->ServerType(i), + serverdbc_->Arg1(i), serverdbc_->Arg2(i)); + // attempt to connect to server + if (sock.Connect(addr) < 0) { + _ftprintf(outf, _T(" STATUS DOWN (%s)\n"), strerror(errno)); + deghost(num_players_db, players_db, 0, NULL, pdbc); + } + else { + int num_players_server = 0; + lyra_id_t* players_server = NULL; + get_logged_in_players(sock, &num_players_server, &players_server); + deghost(num_players_db, players_db, num_players_server, players_server, pdbc); + } + sock.Close(); + break; + } + fclose(outf); + LmDELETE(serverdbc_); + pdbc->Disconnect(); + LmDELETE(pdbc); + pth_kill(); + return 0; +} + +void deghost(int num_players_db, lyra_id_t* players_db, int num_players_server, lyra_id_t* players_server, LmPlayerDBC* pdbc) +{ + if(!num_players_db) + return; // nothing to do + for(int i = 0; i < num_players_db; i++) + { + lyra_id_t dbplayer = players_db[i]; + bool found = false; + // O(n^2), whatever + for(int j = 0; j < num_players_server; j++) + { + if(players_server[i] == dbplayer) + { + found = true; + break; + } + } + + if(!found) + deghost_player(dbplayer, pdbc); + } +} + +void deghost_player(lyra_id_t pid, LmPlayerDBC* pdbc) +{ + // MDA 20181219 -- left here! + // TODO: Fetch player inventory here from LmItemDBC + // Iterate over items in pack + // Fetch player pos from LmPlayerDBC + // ForEach prime in pack: drop prime at pos + // TODO TODO: sendSMsgPutItem when you drop so it updates live. + pdbc->ForceDeghost(pid); +} + +void get_logged_in_players(LmSocket& sock, int* num_players, lyra_id_t** players) +{ + FILE* outf = stdout; + LmSrvMesgBuf msgbuf; + // initialize connection object + LmConnection conn; + conn.Init(sock); + conn.SetMessageRange(SMsg::MIN, SMsg::MAX); + // login to server + SMsg_Login msg_login; + msg_login.Init(LmConnection::CT_MONITOR, 0); + msgbuf.ReadMessage(msg_login); + if (conn.SendMessage(msgbuf) < 0) { + _ftprintf(outf, _T(" STATUS ERROR (could not send login message)\n")); + return; + } + // request server status + SMsg_GetServerStatus msg_getserverstatus; + msg_getserverstatus.Init(SMsg_GetServerStatus::STATUS_SERVER); + msgbuf.ReadMessage(msg_getserverstatus); + if (conn.SendMessage(msgbuf) < 0) { + _ftprintf(outf, _T(" STATUS ERROR (could not send getserverstatus message)\n")); + return; + } + // receive server status + if (conn.ReceiveMessage(msgbuf) < 0) { + _ftprintf(outf, _T(" STATUS ERROR (could not receive serverstatus message)\n")); + return; + } + SMsg_ServerStatus msg_ss; + if (msg_ss.Read(msgbuf) < 0) { + _ftprintf(outf, _T(" STATUS ERROR (could not read serverstatus message; mtype=%d)\n"), msgbuf.Header().MessageType()); + return; + } + // print it + _ftprintf(outf, _T(" STATUS UP pid=%lu ppid=%lu cpu=%.3lf uptime=%d logins=%d players=%d/%d (P=%d M=%d A=%d) conns=%d/%d\n"), + msg_ss.ProcessID(), msg_ss.ParentProcessID(), msg_ss.CPULoad(), msg_ss.Uptime(), msg_ss.TotalLogins(), + msg_ss.NumPlayers(), msg_ss.MaxPlayers(), msg_ss.NumClients(), msg_ss.NumMonsters(), msg_ss.NumAdmin(), + msg_ss.NumConnections(), msg_ss.MaxConnections()); + // get player status for each player + *num_players = msg_ss.NumPlayers(); + if(*num_players) + *players = new lyra_id_t[*num_players]; + for (int i = 0; i < msg_ss.NumPlayers(); ++i) { + lyra_id_t playerid = msg_ss.PlayerID(i); + *players[i] = playerid; + } + // logout from server + SMsg_Logout msg_logout; + msgbuf.ReadMessage(msg_logout); + conn.SendMessage(msgbuf); +} diff --git a/util/meson.build b/util/meson.build index c68e655..07fc06a 100644 --- a/util/meson.build +++ b/util/meson.build @@ -52,6 +52,13 @@ GET_SERVER_STATUS = executable('get_server_status', include_directories: incdir ) +DEGHOST = executable('deghost', + 'deghost.cpp', + link_with: LYRA, + include_directories: incdir +) + + GET_SERVER_STATUS2 = executable('get_server_status2', 'get_server_status2.cpp', link_with: LYRA, From 42480616fc0b854e45c2ccdfedbdcdf5fbd59389 Mon Sep 17 00:00:00 2001 From: Underlight Development Date: Wed, 19 Dec 2018 02:35:25 -0500 Subject: [PATCH 2/3] more work on the deghost utility. it now works, but doesn't drop primes when setting logged_in=0 to run: ./deghost "/full/path/to/lyrahome" --- libsrc/dbi_mysql/LmPlayerDBC.cpp | 6 ++--- util/deghost.cpp | 41 ++++++++++++++++++++++---------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/libsrc/dbi_mysql/LmPlayerDBC.cpp b/libsrc/dbi_mysql/LmPlayerDBC.cpp index dad4326..5a32637 100644 --- a/libsrc/dbi_mysql/LmPlayerDBC.cpp +++ b/libsrc/dbi_mysql/LmPlayerDBC.cpp @@ -2324,7 +2324,7 @@ int LmPlayerDBC::GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned in MYSQL_RES* res; MYSQL_ROW row; - _stprintf(query, _T("SELECT player_id FROM player WHERE logged_in=1 and gamed_port=%u"), gamed_port); + _stprintf(query, _T("SELECT player_id FROM player WHERE logged_in=1 and gamed_port=%u"), gamed_port); int error = mysql_query(&m_mysql, query); if(error) { @@ -2334,7 +2334,7 @@ int LmPlayerDBC::GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned in res = mysql_store_result(&m_mysql); *num_players = mysql_num_rows(res); - + if (!(*num_players)) { mysql_free_result(res); @@ -2344,7 +2344,7 @@ int LmPlayerDBC::GetLoggedInPlayersForGamed(unsigned int gamed_port, unsigned in *player_list = new lyra_id_t[*num_players]; for (int i=0; i<*num_players; i++) { row = mysql_fetch_row(res); - *player_list[i] = ATOI(row[0]); + (*player_list)[i] = ATOI(row[0]); //player_id = ATOI(row[0]); } diff --git a/util/deghost.cpp b/util/deghost.cpp index c3c5003..9e7844a 100644 --- a/util/deghost.cpp +++ b/util/deghost.cpp @@ -47,21 +47,28 @@ int _tmain(int argc, TCHAR** argv) int gamed_port = _ttoi(argv[2]); LmGlobalDB* globaldb_ = LmNEW(LmGlobalDB(root_dir)); LmServerDBC* serverdbc_ = LmNEW(LmServerDBC()); + FILE* outf = stdout; // load passwords & server info TCHAR pw_file[FILENAME_MAX]; globaldb_->GetPasswordFile(pw_file); + //_ftprintf(outf, "Password file is: %s\n", pw_file); serverdbc_->LoadPasswords(pw_file); LmPlayerDBC* pdbc = LmNEW(LmPlayerDBC(serverdbc_->PlayerDBUsername(), serverdbc_->PlayerDBPassword(), serverdbc_->DatabaseHost(), serverdbc_->DatabasePort())); serverdbc_->Connect(); - serverdbc_->Load(); + int rc = serverdbc_->Load(); + if(rc < 0) { + _ftprintf( outf, "Load returned error\n" ); + exit(1); + } serverdbc_->Disconnect(); - FILE* outf = stdout; + pdbc->Connect(); // print time time_t now = time(NULL); _ftprintf(outf, _T("TIME %u : %s"), now,_tctime(&now)); //_tctime() adds newline - + //_ftprintf(outf, _T("Entering loop...\n")); // for each server in database for (int i = 0; i < serverdbc_->NumServers(); ++i) { + //_ftprintf(outf, _T("Considering server %d\n"), i); // if server arg1 is 0, it's an inactive server, don't try to connect if (serverdbc_->Arg1(i) == 0) { continue; @@ -74,22 +81,23 @@ int _tmain(int argc, TCHAR** argv) if (serverdbc_->Arg1(i) != gamed_port) { continue; } - + + _ftprintf(outf, _T("Checking server %d\n"), gamed_port); // create socket LmSocket sock; if (sock.Socket(LmSockType::Inet_Stream()) < 0) { bail(_T("could not create socket\n")); } + // get server address LmSockAddrInet addr; addr.Init(serverdbc_->HostIPAddr(i), serverdbc_->Arg1(i)); // print server header int num_players_db = 0; lyra_id_t* players_db; + _ftprintf(outf, "Retrieving logged in players for gamed %d from playerdb\n", gamed_port); pdbc->GetLoggedInPlayersForGamed(gamed_port, &num_players_db, &players_db); - _ftprintf(outf, _T("SERVER hostid=%s hostname=%s ip=%s type=%c arg1=%d arg2=%d "), - serverdbc_->HostID(i), serverdbc_->HostName(i), addr.AddressString(), serverdbc_->ServerType(i), - serverdbc_->Arg1(i), serverdbc_->Arg2(i)); + _ftprintf(outf, "Done retrieving players from playerdb\n"); // attempt to connect to server if (sock.Connect(addr) < 0) { _ftprintf(outf, _T(" STATUS DOWN (%s)\n"), strerror(errno)); @@ -104,6 +112,7 @@ int _tmain(int argc, TCHAR** argv) sock.Close(); break; } + //_ftprintf(outf, _T("Done with loop...\n")); fclose(outf); LmDELETE(serverdbc_); pdbc->Disconnect(); @@ -119,19 +128,23 @@ void deghost(int num_players_db, lyra_id_t* players_db, int num_players_server, for(int i = 0; i < num_players_db; i++) { lyra_id_t dbplayer = players_db[i]; + _ftprintf(stdout, _T("PID: %u listed ONLINE in db... "), dbplayer); bool found = false; // O(n^2), whatever for(int j = 0; j < num_players_server; j++) { - if(players_server[i] == dbplayer) + if(players_server[j] == dbplayer) { found = true; + _ftprintf(stdout, _T("OK!\n")); break; } } - - if(!found) + + if(!found) { + _ftprintf(stdout, _T("GHOSTED!\n")); deghost_player(dbplayer, pdbc); + } } } @@ -143,7 +156,11 @@ void deghost_player(lyra_id_t pid, LmPlayerDBC* pdbc) // Fetch player pos from LmPlayerDBC // ForEach prime in pack: drop prime at pos // TODO TODO: sendSMsgPutItem when you drop so it updates live. - pdbc->ForceDeghost(pid); + int rc = pdbc->ForceDeghost(pid); + if(rc < 0) + _ftprintf(stdout, "\tERROR DEGHOSTING %u\n", pid); + else + _ftprintf(stdout, "\tDeghosted %d\n", pid); } void get_logged_in_players(LmSocket& sock, int* num_players, lyra_id_t** players) @@ -191,7 +208,7 @@ void get_logged_in_players(LmSocket& sock, int* num_players, lyra_id_t** players *players = new lyra_id_t[*num_players]; for (int i = 0; i < msg_ss.NumPlayers(); ++i) { lyra_id_t playerid = msg_ss.PlayerID(i); - *players[i] = playerid; + (*players)[i] = playerid; } // logout from server SMsg_Logout msg_logout; From c5b946dd2408cfa94364355f49e4c1290dc8192f Mon Sep 17 00:00:00 2001 From: Underlight Development Date: Wed, 19 Dec 2018 03:59:04 -0500 Subject: [PATCH 3/3] add prime check --- util/deghost.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/util/deghost.cpp b/util/deghost.cpp index 9e7844a..275ab9d 100644 --- a/util/deghost.cpp +++ b/util/deghost.cpp @@ -18,15 +18,19 @@ #include "LmSocket.h" #include "LmServerDBC.h" #include "LmPlayerDBC.h" +#include "LmItemDBC.h" #include "LmConnection.h" #include "LmSrvMesgBuf.h" #include "LmServerDBC.h" +#include "LmInventory.h" +#include "LmItem.h" #include "SMsg_All.h" //void get_status(FILE* outf, LmSocket& sock, bool list_players); void deghost(int num_players_db, lyra_id_t* players_db, int num_players_server, lyra_id_t* players_server, LmPlayerDBC* pdbc); void get_logged_in_players(LmSocket& sock, int* num_players, lyra_id_t** players); void deghost_player(lyra_id_t player, LmPlayerDBC* pdbc); +LmItemDBC* idbc; void bail(TCHAR* str) { @@ -54,6 +58,8 @@ int _tmain(int argc, TCHAR** argv) //_ftprintf(outf, "Password file is: %s\n", pw_file); serverdbc_->LoadPasswords(pw_file); LmPlayerDBC* pdbc = LmNEW(LmPlayerDBC(serverdbc_->PlayerDBUsername(), serverdbc_->PlayerDBPassword(), serverdbc_->DatabaseHost(), serverdbc_->DatabasePort())); + idbc = LmNEW(LmItemDBC(serverdbc_->ItemDBUsername(), serverdbc_->ItemDBPassword(), serverdbc_->DatabaseHost(), serverdbc_->DatabasePort())); + serverdbc_->Connect(); int rc = serverdbc_->Load(); if(rc < 0) { @@ -62,6 +68,7 @@ int _tmain(int argc, TCHAR** argv) } serverdbc_->Disconnect(); pdbc->Connect(); + idbc->Connect(); // print time time_t now = time(NULL); _ftprintf(outf, _T("TIME %u : %s"), now,_tctime(&now)); //_tctime() adds newline @@ -116,7 +123,9 @@ int _tmain(int argc, TCHAR** argv) fclose(outf); LmDELETE(serverdbc_); pdbc->Disconnect(); + idbc->Disconnect(); LmDELETE(pdbc); + LmDELETE(idbc); pth_kill(); return 0; } @@ -156,6 +165,23 @@ void deghost_player(lyra_id_t pid, LmPlayerDBC* pdbc) // Fetch player pos from LmPlayerDBC // ForEach prime in pack: drop prime at pos // TODO TODO: sendSMsgPutItem when you drop so it updates live. + LmInventory inventory; + idbc->GetPlayerInventory(pid, inventory); + bool hasprime = false; + for(int i = 0; i < inventory.NumItems(); i++) + { + LmItem item = inventory.ItemByIndex(i); + if(item.FlagSet(LyraItem::FLAG_ALWAYS_DROP)) { + hasprime = true; + break; + } + } + + if(hasprime) { + _ftprintf(stdout, "WARNING: %d GHOSTED while holding prime - NOT DEGHOSTING!\n", pid); + return; + } + int rc = pdbc->ForceDeghost(pid); if(rc < 0) _ftprintf(stdout, "\tERROR DEGHOSTING %u\n", pid);