From 5ccb4f1f3c177a871c31422db9d4c03abf2438ad Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Thu, 1 Sep 2016 21:52:00 +0200 Subject: [PATCH] Added Console logging over network as mentionted in Issue The PrintMessageStub must be changed a bit to add the channel info and timestamp. --- src/Components/Modules/Logger.cpp | 243 +++++++++++++++++++++++++++++- src/Components/Modules/Logger.hpp | 40 ++++- src/Game/Functions.hpp | 13 ++ 3 files changed, 288 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index c2b4d5a8..771a82cc 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -4,6 +4,16 @@ namespace Components { std::mutex Logger::MessageMutex; std::vector Logger::MessageQueue; + std::vector Logger::addresses; + std::vector Logger::gaddresses; + + static char* writeFile; + static char* writeFolder; + //static DWORD fsBuildOSPathForThreadHookLoc = 0x642139; + DWORD fsBuildOSPathForThreadHookLocRet = 0x64213F; + Game::dvar_t* iw4m_onelog; + + void(*Logger::PipeCallback)(std::string) = nullptr; bool Logger::IsConsoleReady() @@ -26,21 +36,46 @@ namespace Components if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests()) { printf("%s", message.data()); + /*if (Logger::addresses.size()) { + for (size_t i = 0; i < Logger::addresses.size(); i++) { + const char* toSend = Utils::String::VA("%i %s", channel, message); + Network::Send(Logger::addresses[i], toSend); + } + }*/ fflush(stdout); + return; } if (!Logger::IsConsoleReady()) { OutputDebugStringA(message.data()); + /*if (Logger::addresses.size()) { + for (size_t i = 0; i < Logger::addresses.size(); i++) { + const char* toSend = Utils::String::VA("%i %s", channel, message); + Network::Send(Logger::addresses[i], toSend); + } + }*/ } if (!Game::Sys_IsMainThread()) { Logger::EnqueueMessage(message); + /*if (Logger::addresses.size()) { + for (size_t i = 0; i < Logger::addresses.size(); i++) { + const char* toSend = Utils::String::VA("%i %s", channel, message); + Network::Send(Logger::addresses[i], toSend); + } + }*/ } else { + /*if (Logger::addresses.size()) { + for (size_t i = 0; i < Logger::addresses.size(); i++) { + const char* toSend = Utils::String::VA("%i %s", channel, message); + Network::Send(Logger::addresses[i], toSend); + } + }*/ Game::Com_PrintMessage(channel, message.data(), 0); } } @@ -83,6 +118,7 @@ namespace Components for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) { + Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0); if (!Logger::IsConsoleReady()) @@ -104,6 +140,7 @@ namespace Components { if (Logger::PipeCallback) { + Logger::PipeCallback(data); } } @@ -116,17 +153,17 @@ namespace Components test eax, eax jz returnPrint - push [esp + 8h] + push[esp + 8h] call Logger::PrintMessagePipe add esp, 4h - retn + - returnPrint: + returnPrint : push esi - mov esi, [esp + 0Ch] + mov esi, [esp + 0Ch] - mov eax, 4AA835h - jmp eax + mov eax, 4AA835h + jmp eax } } @@ -137,13 +174,52 @@ namespace Components Logger::MessageMutex.unlock(); } + void Logger::test(std::string message) + { + + if (Logger::addresses.size()) { + for (size_t i = 0; i < Logger::addresses.size(); i++) { + const char* toSend = Utils::String::VA("%i %s", 0, message); + Network::Send(Logger::addresses[i], toSend); + } + } + //Logger::PrintMessagePipe(message.c_str()); + + } + + Logger::Logger() { - Logger::PipeOutput(nullptr); + Logger::PipeOutput(&test); QuickPatch::OnFrame(Logger::Frame); Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); + + //Logging over network stuff + Game::Cmd_AddCommand("log_add", Game::Cbuf_AddServerText, &sv_log_add, 0); + Game::Cmd_AddServerCommand("log_add", Logger::SV_Log_Add_f, &sv_log_add2); + + Game::Cmd_AddCommand("log_del", Game::Cbuf_AddServerText, &sv_log_del, 0); + Game::Cmd_AddServerCommand("log_del", Logger::SV_Log_Del_f, &sv_log_del2); + + Game::Cmd_AddCommand("log_list", Game::Cbuf_AddServerText, &sv_log_list, 0); + Game::Cmd_AddServerCommand("log_list", Logger::SV_Log_List_f, &sv_log_list2); + + Game::Cmd_AddCommand("g_log_add", Game::Cbuf_AddServerText, &sv_glog_add, 0); + Game::Cmd_AddServerCommand("g_log_add", Logger::SV_GLog_Add_f, &sv_glog_add2); + + Game::Cmd_AddCommand("g_log_del", Game::Cbuf_AddServerText, &sv_glog_del, 0); + Game::Cmd_AddServerCommand("g_log_del", Logger::SV_GLog_Del_f, &sv_glog_del2); + + Game::Cmd_AddCommand("g_log_list", Game::Cbuf_AddServerText, &sv_glog_list, 0); + Game::Cmd_AddServerCommand("g_log_list", Logger::SV_GLog_List_f, &sv_glog_list2); + + Utils::Hook(Logger::fsBuildOSPathForThreadHookLoc, FS_BuildOSPathForThreadHookFunc, HOOK_JUMP).Install()->Quick(); + Logger::FS_BuildOSPathForThreadHookTest(); + iw4m_onelog = (Game::dvar_t*)Game::Dvar_RegisterBool("iw4x_onelog", false, Game::DVAR_FLAG_LATCHED || Game::DVAR_FLAG_SAVED, "Only write the game log to the '" BASEGAME "' OS folder"); + + } Logger::~Logger() @@ -152,4 +228,157 @@ namespace Components Logger::MessageQueue.clear(); Logger::MessageMutex.unlock(); } + + //Logging over network stuff + + + void Logger::SV_GLog_Add_f() { + if (Game::Cmd_Argc() != 2) { + Game::Com_Printf(0, "USAGE: %s \n", Game::Cmd_Argv(0)); + return; + } + Game::netadr_t ip; + if (!Game::NET_StringToAdr(Game::Cmd_Argv(1), &ip)) { + Game::Com_Printf(0, "Invalid address: %s\n", Game::Cmd_Argv(1)); + return; + } + for (size_t i = 0; i < Logger::gaddresses.size(); i++) { + if (Game::NET_CompareAdr(Logger::gaddresses[i], ip)) { + Game::Com_Printf(0, "Address %s already exists (#%i)\n", Game::Cmd_Argv(1), i); + return; + } + } + //all good + Logger::gaddresses.push_back(ip); + int size = Logger::gaddresses.size(); + Game::Com_Printf(101, "Address %s (#%i) added to games_mp.log stream list\n", Game::NET_AdrToString(Logger::gaddresses[size - 1]), size - 1); + } + void Logger::SV_Log_Add_f() { + if (Game::Cmd_Argc() != 2) { + Game::Com_Printf(0, "USAGE: %s \n", Game::Cmd_Argv(0)); + return; + } + Game::netadr_t ip; + if (!Game::NET_StringToAdr(Game::Cmd_Argv(1), &ip)) { + Game::Com_Printf(0, "Invalid address: %s\n", Game::Cmd_Argv(1)); + return; + } + for (size_t i = 0; i < Logger::addresses.size(); i++) { + if (Game::NET_CompareAdr(Logger::addresses[i], ip)) { + Game::Com_Printf(0, "Address %s already exists (#%i)\n", Game::Cmd_Argv(1), i); + return; + } + } + //all good + Logger::addresses.push_back(ip); + int size = Logger::addresses.size(); + Game::Com_Printf(101, "Address %s (#%i) added to console_mp.log stream list\n", Game::NET_AdrToString(Logger::addresses[size - 1]), size - 1); + } + + + void Logger::SV_GLog_Del_f() { + if (Game::Cmd_Argc() != 2) { + Game::Com_Printf(0, "USAGE: %s \n", Game::Cmd_Argv(0)); + return; + } + int index = 0; + if (!Logger::validInt(Game::Cmd_Argv(1))) { + Game::Com_Printf(0, "%s is NaN\n", Game::Cmd_Argv(1)); + return; + } + index = atoi(Game::Cmd_Argv(1)); + if (index > -1 && index < (int)Logger::gaddresses.size()) { + Game::Com_Printf(0, "Address %s (ID %i) removed\n", Game::NET_AdrToString(Logger::gaddresses[index]), index); + Logger::gaddresses.erase(Logger::gaddresses.begin() + index); + } + else { + Game::Com_Printf(0, "ID %i is not valid\n", index); + } + } + + void Logger::SV_Log_Del_f() { + if (Game::Cmd_Argc() != 2) { + Game::Com_Printf(0, "USAGE: %s \n", Game::Cmd_Argv(0)); + return; + } + int index = 0; + if (!Logger::validInt(Game::Cmd_Argv(1))) { + Game::Com_Printf(0, "%s is NaN\n", Game::Cmd_Argv(1)); + return; + } + index = atoi(Game::Cmd_Argv(1)); + if (index > -1 && index < (int)Logger::addresses.size()) { + Game::Com_Printf(0, "Address %s (ID %i) removed\n", Game::NET_AdrToString(Logger::addresses[index]), index); + Logger::addresses.erase(Logger::addresses.begin() + index); + } + else { + Game::Com_Printf(0, "ID %i is not valid\n", index); + } + } + + void Logger::SV_GLog_List_f() { + Game::Com_Printf(0, "# ID: Address\n"); + Game::Com_Printf(0, "-------------\n"); + for (size_t i = 0; i < Logger::gaddresses.size(); i++) { + Game::Com_Printf(0, "#%03d: %5s\n", i, Game::NET_AdrToString(Logger::gaddresses[i])); + } + } + void Logger::SV_Log_List_f() { + Game::Com_Printf(0, "# ID: Address\n"); + Game::Com_Printf(0, "-------------\n"); + for (size_t i = 0; i < Logger::addresses.size(); i++) { + Game::Com_Printf(0, "#%03d: %5s\n", i, Game::NET_AdrToString(Logger::addresses[i])); + } + } + + + bool Logger::validInt(char* str) { + for (size_t i = 0; i < strlen(str); i++) { + if (str[i] < '0' || str[i] > '9') { + return false; + } + } + return true; + } + + + + + + + void Logger::FS_BuildOSPathForThreadHookTest() + { + Game::dvar_t* g_log = *(Game::dvar_t**)0x1A45D9C; + + if (g_log && strcmp(writeFile, g_log->current.string) == 0) + { + if (strcmp(writeFolder, BASEGAME) != 0) + { + if (iw4m_onelog->current.boolean) + { + strcpy_s(writeFolder, 256, BASEGAME); + } + } + } + } + void __declspec(naked) Logger::FS_BuildOSPathForThreadHookFunc() + { + __asm + { + mov eax, [esp + 8h] + mov writeFolder, eax + mov eax, [esp + 0Ch] + mov writeFile, eax + + mov eax, [esp + 8h] + push ebp + push esi + mov esi, [esp + 0Ch] + + jmp fsBuildOSPathForThreadHookLocRet + } + + + } + } diff --git a/src/Components/Modules/Logger.hpp b/src/Components/Modules/Logger.hpp index 504038e4..50400d15 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -20,17 +20,55 @@ namespace Components static bool IsConsoleReady(); static void PipeOutput(void(*callback)(std::string)); - + static bool validInt(char* str); + static const DWORD fsBuildOSPathForThreadHookLoc = 0x642139; + //static const DWORD fsBuildOSPathForThreadHookLocRet = 0x64213F; + Game::cmd_function_t sv_log_add; + Game::cmd_function_t sv_log_add2; + + Game::cmd_function_t sv_log_del; + Game::cmd_function_t sv_log_del2; + + Game::cmd_function_t sv_log_list; + Game::cmd_function_t sv_log_list2; + + Game::cmd_function_t sv_glog_add; + Game::cmd_function_t sv_glog_add2; + + Game::cmd_function_t sv_glog_del; + Game::cmd_function_t sv_glog_del2; + + Game::cmd_function_t sv_glog_list; + Game::cmd_function_t sv_glog_list2; + static void test(std::string message); private: static std::mutex MessageMutex; static std::vector MessageQueue; + static std::vector addresses; + static std::vector gaddresses; static void(*PipeCallback)(std::string); + static void Frame(); static void PrintMessageStub(); static void PrintMessagePipe(const char* data); static void EnqueueMessage(std::string message); static std::string Format(const char** message); + + //Logging over network stuff +static void FS_BuildOSPathForThreadHookFunc(); + static void FS_BuildOSPathForThreadHookTest(); + static void SV_GLog_Add_f(); + static void SV_Log_Add_f(); + static void SV_GLog_Del_f(); + static void SV_Log_Del_f(); + static void SV_GLog_List_f(); + static void SV_Log_List_f(); + + + + + }; } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index c3f29b05..76b8eee1 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -518,4 +518,17 @@ namespace Game void IN_KeyUp(kbutton_t* button); void IN_KeyDown(kbutton_t* button); + + inline int Cmd_Argc(void) + { + return cmd_argc[*cmd_id]; + } + + inline char *Cmd_Argv(int arg) + { + if ((unsigned)arg >= cmd_argc[*cmd_id]) { + return ""; + } + return (char*)(cmd_argv[*cmd_id][arg]); + } }