diff --git a/.gitmodules b/.gitmodules index 08ae18e6..e835a944 100644 --- a/.gitmodules +++ b/.gitmodules @@ -35,3 +35,95 @@ path = deps/protobuf url = https://github.com/google/protobuf.git branch = 3.2.x +[submodule "deps/boost/interprocess"] + path = deps/boost/interprocess + url = https://github.com/boostorg/interprocess.git + branch = develop +[submodule "deps/boost/config"] + path = deps/boost/config + url = https://github.com/boostorg/config.git + branch = develop +[submodule "deps/boost/date_time"] + path = deps/boost/date_time + url = https://github.com/boostorg/date_time.git + branch = develop +[submodule "deps/boost/assert"] + path = deps/boost/assert + url = https://github.com/boostorg/assert.git + branch = develop +[submodule "deps/boost/utility"] + path = deps/boost/utility + url = https://github.com/boostorg/utility.git + branch = develop +[submodule "deps/boost/detail"] + path = deps/boost/detail + url = https://github.com/boostorg/detail.git + branch = develop +[submodule "deps/boost/winapi"] + path = deps/boost/winapi + url = https://github.com/boostorg/winapi.git + branch = develop +[submodule "deps/boost/integer"] + path = deps/boost/integer + url = https://github.com/boostorg/integer.git + branch = develop +[submodule "deps/boost/move"] + path = deps/boost/move + url = https://github.com/boostorg/move.git + branch = develop +[submodule "deps/boost/static_assert"] + path = deps/boost/static_assert + url = https://github.com/boostorg/static_assert.git + branch = develop +[submodule "deps/boost/container"] + path = deps/boost/container + url = https://github.com/boostorg/container.git + branch = develop +[submodule "deps/boost/intrusive"] + path = deps/boost/intrusive + url = https://github.com/boostorg/intrusive.git + branch = develop +[submodule "deps/boost/core"] + path = deps/boost/core + url = https://github.com/boostorg/core.git + branch = develop +[submodule "deps/boost/functional"] + path = deps/boost/functional + url = https://github.com/boostorg/functional.git + branch = develop +[submodule "deps/boost/type_traits"] + path = deps/boost/type_traits + url = https://github.com/boostorg/type_traits.git + branch = develop +[submodule "deps/boost/preprocessor"] + path = deps/boost/preprocessor + url = https://github.com/boostorg/preprocessor.git + branch = develop +[submodule "deps/boost/smart_ptr"] + path = deps/boost/smart_ptr + url = https://github.com/boostorg/smart_ptr.git + branch = develop +[submodule "deps/boost/throw_exception"] + path = deps/boost/throw_exception + url = https://github.com/boostorg/throw_exception.git + branch = develop +[submodule "deps/boost/predef"] + path = deps/boost/predef + url = https://github.com/boostorg/predef.git + branch = develop +[submodule "deps/boost/mpl"] + path = deps/boost/mpl + url = https://github.com/boostorg/mpl.git + branch = develop +[submodule "deps/boost/unordered"] + path = deps/boost/unordered + url = https://github.com/boostorg/unordered.git + branch = develop +[submodule "deps/boost/iterator"] + path = deps/boost/iterator + url = https://github.com/boostorg/iterator.git + branch = develop +[submodule "deps/boost/tuple"] + path = deps/boost/tuple + url = https://github.com/boostorg/tuple.git + branch = develop diff --git a/README.md b/README.md index 1587e2f7..c4c4eee9 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,5 @@ | `--disable-bitmessage` | Disable use of BitMessage completely. | | `--disable-node-log` | Disable debugging messages for Nodes in Debug builds. | | `--disable-base128` | Disable base128 encoding for minidumps. | -| `--disable-steam-game` | Disable Steam's in-game setting. | | `--no-new-structure` | Do not use new virtual path structure (separating headers and source files). | | `--enable-dxsdk` | Enable DirectX SDK (required for GfxMap exporting). | diff --git a/deps/boost/assert b/deps/boost/assert new file mode 160000 index 00000000..89e5b86c --- /dev/null +++ b/deps/boost/assert @@ -0,0 +1 @@ +Subproject commit 89e5b86c469c993ea4c53ebc7ed4a9b133f785a6 diff --git a/deps/boost/config b/deps/boost/config new file mode 160000 index 00000000..b4628d91 --- /dev/null +++ b/deps/boost/config @@ -0,0 +1 @@ +Subproject commit b4628d91eb8b2cbf96e3dadee3d6bff97b50ae46 diff --git a/deps/boost/container b/deps/boost/container new file mode 160000 index 00000000..23e9e8b4 --- /dev/null +++ b/deps/boost/container @@ -0,0 +1 @@ +Subproject commit 23e9e8b4946f8b026ced6b048d7a62b4ca81b722 diff --git a/deps/boost/core b/deps/boost/core new file mode 160000 index 00000000..1abd6810 --- /dev/null +++ b/deps/boost/core @@ -0,0 +1 @@ +Subproject commit 1abd68102d26d87109b5eda8d80f8bb0382ce4df diff --git a/deps/boost/date_time b/deps/boost/date_time new file mode 160000 index 00000000..47cf10d5 --- /dev/null +++ b/deps/boost/date_time @@ -0,0 +1 @@ +Subproject commit 47cf10d5fd7cee50d4e53a6132c69a7e1cbb2d0b diff --git a/deps/boost/detail b/deps/boost/detail new file mode 160000 index 00000000..6c111975 --- /dev/null +++ b/deps/boost/detail @@ -0,0 +1 @@ +Subproject commit 6c111975865d112c11101ef8221695cc4cd57562 diff --git a/deps/boost/functional b/deps/boost/functional new file mode 160000 index 00000000..c592e854 --- /dev/null +++ b/deps/boost/functional @@ -0,0 +1 @@ +Subproject commit c592e854919730597b1793f85667e7d88f000d29 diff --git a/deps/boost/integer b/deps/boost/integer new file mode 160000 index 00000000..13b153c6 --- /dev/null +++ b/deps/boost/integer @@ -0,0 +1 @@ +Subproject commit 13b153c657697129cabe7ac8b3e62ef844a62945 diff --git a/deps/boost/interprocess b/deps/boost/interprocess new file mode 160000 index 00000000..0cd4548b --- /dev/null +++ b/deps/boost/interprocess @@ -0,0 +1 @@ +Subproject commit 0cd4548b45a9b9fdac2c58f2acb793095754f821 diff --git a/deps/boost/intrusive b/deps/boost/intrusive new file mode 160000 index 00000000..286f5976 --- /dev/null +++ b/deps/boost/intrusive @@ -0,0 +1 @@ +Subproject commit 286f597606de0d139e256af8c2695d90535be905 diff --git a/deps/boost/iterator b/deps/boost/iterator new file mode 160000 index 00000000..760da84f --- /dev/null +++ b/deps/boost/iterator @@ -0,0 +1 @@ +Subproject commit 760da84f9cbbe87afb7ef845ef5fa6be158637b7 diff --git a/deps/boost/move b/deps/boost/move new file mode 160000 index 00000000..135e598b --- /dev/null +++ b/deps/boost/move @@ -0,0 +1 @@ +Subproject commit 135e598bc4ffc63001d84f93764fddee234f1da2 diff --git a/deps/boost/mpl b/deps/boost/mpl new file mode 160000 index 00000000..3b126bdf --- /dev/null +++ b/deps/boost/mpl @@ -0,0 +1 @@ +Subproject commit 3b126bdf8c7abbfef27101232a379c8e0c3db1ac diff --git a/deps/boost/predef b/deps/boost/predef new file mode 160000 index 00000000..822d09f1 --- /dev/null +++ b/deps/boost/predef @@ -0,0 +1 @@ +Subproject commit 822d09f19bc2f4ea6f42da8e0be83d10ce912ce1 diff --git a/deps/boost/preprocessor b/deps/boost/preprocessor new file mode 160000 index 00000000..d8389ffd --- /dev/null +++ b/deps/boost/preprocessor @@ -0,0 +1 @@ +Subproject commit d8389ffda600ce73d62b077616987744f5f83453 diff --git a/deps/boost/smart_ptr b/deps/boost/smart_ptr new file mode 160000 index 00000000..19147212 --- /dev/null +++ b/deps/boost/smart_ptr @@ -0,0 +1 @@ +Subproject commit 19147212a9edd1facdc9a17cf586b79c92f4116a diff --git a/deps/boost/static_assert b/deps/boost/static_assert new file mode 160000 index 00000000..c2f58a18 --- /dev/null +++ b/deps/boost/static_assert @@ -0,0 +1 @@ +Subproject commit c2f58a187a67502a20aaa14c88625f12e400c5c1 diff --git a/deps/boost/throw_exception b/deps/boost/throw_exception new file mode 160000 index 00000000..f94638e5 --- /dev/null +++ b/deps/boost/throw_exception @@ -0,0 +1 @@ +Subproject commit f94638e5225afff877347576ff7b4170971e7a2a diff --git a/deps/boost/tuple b/deps/boost/tuple new file mode 160000 index 00000000..895af7c9 --- /dev/null +++ b/deps/boost/tuple @@ -0,0 +1 @@ +Subproject commit 895af7c97a2f74980eb459badf67787c2a3ecadf diff --git a/deps/boost/type_traits b/deps/boost/type_traits new file mode 160000 index 00000000..4fffc763 --- /dev/null +++ b/deps/boost/type_traits @@ -0,0 +1 @@ +Subproject commit 4fffc7637da8479e3f94674ef1dd0fc996a7d027 diff --git a/deps/boost/unordered b/deps/boost/unordered new file mode 160000 index 00000000..57cc6d4b --- /dev/null +++ b/deps/boost/unordered @@ -0,0 +1 @@ +Subproject commit 57cc6d4bac1cc93fb8fb05696116b184f3d1fecc diff --git a/deps/boost/utility b/deps/boost/utility new file mode 160000 index 00000000..ccfd741c --- /dev/null +++ b/deps/boost/utility @@ -0,0 +1 @@ +Subproject commit ccfd741c0a423e6c8dc4493e3a4e042b5a34a329 diff --git a/deps/boost/winapi b/deps/boost/winapi new file mode 160000 index 00000000..b017fd88 --- /dev/null +++ b/deps/boost/winapi @@ -0,0 +1 @@ +Subproject commit b017fd886612a9001dfdffeb1aa4663b6e2acda8 diff --git a/deps/protobuf b/deps/protobuf index d1f0939a..2c8346a2 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit d1f0939a42ae8a6b6bca95a4b9048d7416e72865 +Subproject commit 2c8346a259791ccb176da80e31e59f1df479bd6d diff --git a/premake/boost.lua b/premake/boost.lua new file mode 100644 index 00000000..c880e524 --- /dev/null +++ b/premake/boost.lua @@ -0,0 +1,83 @@ +boost = { + settings = nil, +} + +function boost.setup(settings) + if not settings.source then error("Missing source.") end + + boost.settings = settings +end + +function boost.import() + if not boost.settings then error("Run boost.setup first") end + + --links { "boost" } + boost.includes() +end + +function boost.includes() + if not boost.settings then error("Run boost.setup first") end + + submodules = { + "mpl", + "core", + "move", + "tuple", + "assert", + "predef", + "config", + "detail", + "winapi", + "integer", + "utility", + "iterator", + "container", + "unordered", + "date_time", + "smart_ptr", + "intrusive", + "functional", + "type_traits", + "interprocess", + "preprocessor", + "static_assert", + "throw_exception", + } + + for i, submodule in ipairs(submodules) do + includedirs { path.join(boost.settings.source, string.format("%s/include", submodule)) } + end + + includedirs { boost.settings.source } +end + +function boost.project() + if not boost.settings then error("Run boost.setup first") end + +--[[ + project "boost" + language "C++" + + includedirs + { + boost.settings.source, + } + + files + { + path.join(boost.settings.source, "*.cpp"), + path.join(boost.settings.source, "*.hpp"), + } + removefiles + { + path.join(boost.settings.source, "test*"), + } + + -- not our code, ignore POSIX usage warnings for now + warnings "Off" + + defines { "_LIB" } + removedefines { "_USRDLL", "_DLL" } + kind "StaticLib" +]] +end diff --git a/premake5.lua b/premake5.lua index d57a9184..70f9e661 100644 --- a/premake5.lua +++ b/premake5.lua @@ -88,11 +88,6 @@ newoption { description = "Disable base128 encoding for minidumps." } -newoption { - trigger = "disable-steam-game", - description = "Disable Steam's in-game setting." -} - newoption { trigger = "enable-dxsdk", description = "Enable DirectX SDK (required for GfxMap exporting)." @@ -204,6 +199,7 @@ require "premake/pdcurses" require "premake/protobuf" require "premake/sqlite3" require "premake/zlib" +require "premake/boost" base128.setup { @@ -260,6 +256,10 @@ zlib.setup }, source = path.join(depsBasePath, "zlib"), } +boost.setup +{ + source = path.join(depsBasePath, "boost"), +} workspace "iw4x" location "./build" @@ -304,7 +304,7 @@ workspace "iw4x" } includedirs { "%{prj.location}/src", - "./src" + "./src", } resincludedirs { "$(ProjectDir)src" -- fix for VS IDE @@ -341,9 +341,6 @@ workspace "iw4x" if _OPTIONS["disable-base128"] then defines { "DISABLE_BASE128" } end - if _OPTIONS["disable-steam-game"] then - defines { "DISABLE_STEAM_GAME" } - end if _OPTIONS["enable-dxsdk"] then defines { "ENABLE_DXSDK" } includedirs { "%DXSDK_DIR%Include" } @@ -369,6 +366,7 @@ workspace "iw4x" pdcurses.import() protobuf.import() zlib.import() + boost.import() -- fix vpaths for protobuf sources vpaths @@ -397,8 +395,9 @@ workspace "iw4x" -- Pre-build prebuildcommands { - "cd %{_MAIN_SCRIPT_DIR}", + "pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", + "popd", } -- Post-build @@ -486,6 +485,7 @@ workspace "iw4x" pdcurses.project() protobuf.project() zlib.project() + boost.project() rule "ProtobufCompiler" display "Protobuf compiler" diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 7e731941..7afac788 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -43,7 +43,6 @@ namespace Components Loader::Register(new Command()); Loader::Register(new Console()); Loader::Register(new Friends()); - Loader::Register(new IPCPipe()); Loader::Register(new ModList()); Loader::Register(new Network()); Loader::Register(new Theatre()); @@ -68,6 +67,7 @@ namespace Components Loader::Register(new BitMessage()); #endif Loader::Register(new FileSystem()); + Loader::Register(new IPCHandler()); Loader::Register(new ModelSurfs()); Loader::Register(new PlayerName()); Loader::Register(new QuickPatch()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 696897ae..f9da13d3 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -59,7 +59,6 @@ namespace Components #include "Modules/Window.hpp" #include "Modules/Command.hpp" #include "Modules/Console.hpp" -#include "Modules/IPCPipe.hpp" #include "Modules/UIScript.hpp" #include "Modules/ModList.hpp" #include "Modules/Network.hpp" @@ -86,6 +85,7 @@ namespace Components #include "Modules/Threading.hpp" #include "Modules/BitMessage.hpp" #include "Modules/FileSystem.hpp" +#include "Modules/IPCHandler.hpp" #include "Modules/ModelSurfs.hpp" #include "Modules/PlayerName.hpp" #include "Modules/QuickPatch.hpp" diff --git a/src/Components/Modules/AntiCheat.hpp b/src/Components/Modules/AntiCheat.hpp index 4c32f9ee..63ac9b24 100644 --- a/src/Components/Modules/AntiCheat.hpp +++ b/src/Components/Modules/AntiCheat.hpp @@ -6,7 +6,7 @@ #endif // Uncomment to enable process protection (conflicts with steam!) -//#define PROCTECT_PROCESS +#define PROCTECT_PROCESS namespace Components { diff --git a/src/Components/Modules/ConnectProtocol.cpp b/src/Components/Modules/ConnectProtocol.cpp index defdd32f..a70201ee 100644 --- a/src/Components/Modules/ConnectProtocol.cpp +++ b/src/Components/Modules/ConnectProtocol.cpp @@ -212,7 +212,7 @@ namespace Components ConnectProtocol::ConnectProtocol() { // IPC handler - IPCPipe::On("connect", [] (std::string data) + IPCHandler::OnClient("connect", [] (std::string data) { Command::Execute(Utils::String::VA("connect %s", data.data()), false); }); @@ -229,7 +229,7 @@ namespace Components { if (!Singleton::IsFirstInstance()) { - IPCPipe::Write("connect", ConnectProtocol::ConnectString); + IPCHandler::SendClient("connect", ConnectProtocol::ConnectString); ExitProcess(0); } else diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 713658da..d5bb5f66 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -507,7 +507,7 @@ namespace Components { "con_outputWindowColor", { 0.25f, 0.25f, 0.25f, 0.85f } }, }; - for (int i = 0; i < ARRAY_SIZE(patchedColors); ++i) + for (int i = 0; i < ARRAYSIZE(patchedColors); ++i) { if (std::string(name) == patchedColors[i].name) { diff --git a/src/Components/Modules/IPCHandler.cpp b/src/Components/Modules/IPCHandler.cpp new file mode 100644 index 00000000..952035e4 --- /dev/null +++ b/src/Components/Modules/IPCHandler.cpp @@ -0,0 +1,128 @@ +#include "STDInclude.hpp" + +namespace Components +{ + std::unordered_map IPCHandler::WorkerCallbacks; + std::unordered_map IPCHandler::ClientCallbacks; + + std::unique_ptr IPCHandler::WorkerChannel; + std::unique_ptr IPCHandler::ClientChannel; + + void IPCHandler::SendWorker(std::string message, std::string data) + { + IPCHandler::InitChannels(); + + Proto::IPC::Command command; + command.set_command(message); + command.set_data(data); + + IPCHandler::WorkerChannel->send(command.SerializeAsString()); + } + + void IPCHandler::SendClient(std::string message, std::string data) + { + IPCHandler::InitChannels(); + + Proto::IPC::Command command; + command.set_command(message); + command.set_data(data); + + IPCHandler::ClientChannel->send(command.SerializeAsString()); + } + + void IPCHandler::OnWorker(std::string message, IPCHandler::Callback callback) + { + IPCHandler::WorkerCallbacks[message] = callback; + } + + void IPCHandler::OnClient(std::string message, IPCHandler::Callback callback) + { + IPCHandler::ClientCallbacks[message] = callback; + } + + void IPCHandler::InitChannels() + { + if (!IPCHandler::WorkerChannel) + { + IPCHandler::WorkerChannel.reset(new Utils::IPC::BidirectionalChannel("IW4x-Worker-Channel", !Worker::IsWorker())); + } + + if (!IPCHandler::ClientChannel) + { + IPCHandler::ClientChannel.reset(new Utils::IPC::BidirectionalChannel("IW4x-Client-Channel", Singleton::IsFirstInstance())); + } + } + + void IPCHandler::StartWorker() + { + STARTUPINFOA sInfo; + PROCESS_INFORMATION pInfo; + + ZeroMemory(&sInfo, sizeof(sInfo)); + ZeroMemory(&pInfo, sizeof(pInfo)); + sInfo.cb = sizeof(sInfo); + + CreateProcessA("iw4x.exe", const_cast(Utils::String::VA("-parent %d", GetCurrentProcessId())), nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo); + + if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread); + if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess); + } + + void IPCHandler::HandleClient() + { + IPCHandler::InitChannels(); + + std::string packet; + if(IPCHandler::ClientChannel->receive(&packet)) + { + Proto::IPC::Command command; + if(command.ParseFromString(packet)) + { + auto callback = IPCHandler::ClientCallbacks.find(command.command()); + if (callback != IPCHandler::ClientCallbacks.end()) + { + callback->second(command.data()); + } + } + } + } + + void IPCHandler::HandleWorker() + { + IPCHandler::InitChannels(); + + std::string packet; + if (IPCHandler::WorkerChannel->receive(&packet)) + { + Proto::IPC::Command command; + if (command.ParseFromString(packet)) + { + auto callback = IPCHandler::WorkerCallbacks.find(command.command()); + if (callback != IPCHandler::WorkerCallbacks.end()) + { + callback->second(command.data()); + } + } + } + } + + IPCHandler::IPCHandler() + { + if (Dedicated::IsEnabled()) return; + + IPCHandler::InitChannels(); + IPCHandler::StartWorker(); + + QuickPatch::OnFrame([]() + { + IPCHandler::HandleWorker(); + IPCHandler::HandleClient(); + }); + } + + IPCHandler::~IPCHandler() + { + IPCHandler::WorkerCallbacks.clear(); + IPCHandler::ClientCallbacks.clear(); + } +} diff --git a/src/Components/Modules/IPCHandler.hpp b/src/Components/Modules/IPCHandler.hpp new file mode 100644 index 00000000..d63ac912 --- /dev/null +++ b/src/Components/Modules/IPCHandler.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace Components +{ + class IPCHandler : public Component + { + public: + typedef Utils::Slot Callback; + + IPCHandler(); + ~IPCHandler(); + +#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) + const char* getName() override { return "IPCHandler"; }; +#endif + + static void SendWorker(std::string message, std::string data); + static void SendClient(std::string message, std::string data); + + static void OnWorker(std::string message, Callback callback); + static void OnClient(std::string message, Callback callback); + + private: + static std::unique_ptr WorkerChannel; + static std::unique_ptr ClientChannel; + + static std::unordered_map WorkerCallbacks; + static std::unordered_map ClientCallbacks; + + static void InitChannels(); + static void StartWorker(); + + static void HandleClient(); + static void HandleWorker(); + }; +} diff --git a/src/Components/Modules/IPCPipe.cpp b/src/Components/Modules/IPCPipe.cpp deleted file mode 100644 index bc664de4..00000000 --- a/src/Components/Modules/IPCPipe.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#include "STDInclude.hpp" - -namespace Components -{ - Pipe IPCPipe::ServerPipe; - Pipe IPCPipe::ClientPipe; - -#pragma region Pipe - - Pipe::Pipe() : connectCallback(0), pipe(INVALID_HANDLE_VALUE), threadAttached(false), type(IPCTYPE_NONE), reconnectAttempt(0) - { - this->destroy(); - } - - Pipe::~Pipe() - { - this->destroy(); - } - - bool Pipe::connect(std::string name) - { - this->destroy(); - - this->type = IPCTYPE_CLIENT; - this->setName(name); - - this->pipe = CreateFileA(this->pipeFile, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); - - if (INVALID_HANDLE_VALUE == this->pipe) - { - Logger::Print("Failed to connect to the pipe\n"); - - if (this->reconnectAttempt < IPC_MAX_RECONNECTS) - { - Logger::Print("Attempting to reconnect to the pipe.\n"); - ++this->reconnectAttempt; - std::this_thread::sleep_for(500ms); - - return this->connect(name); - } - else - { - this->destroy(); - return false; - } - } - - this->reconnectAttempt = 0; - Logger::Print("Successfully connected to the pipe\n"); - - return true; - } - - bool Pipe::create(std::string name) - { - this->destroy(); - - this->type = IPCTYPE_SERVER; - this->setName(name); - - this->pipe = CreateNamedPipeA(this->pipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->packet), sizeof(this->packet), NMPWAIT_USE_DEFAULT_WAIT, nullptr); - - if (INVALID_HANDLE_VALUE != this->pipe && this->pipe) - { - // Only create the thread, when not performing unit tests! - if (!Loader::PerformingUnitTests()) - { - this->threadAttached = true; - this->thread = std::thread(Pipe::ReceiveThread, this); - } - - Logger::Print("Pipe successfully created\n"); - return true; - } - - Logger::Print("Failed to create the pipe\n"); - this->destroy(); - return false; - } - - void Pipe::onConnect(Pipe::Callback callback) - { - this->connectCallback = callback; - } - - void Pipe::setCallback(std::string command, Utils::Slot callback) - { - this->packetCallbacks[command] = callback; - } - - bool Pipe::write(std::string command, std::string data) - { - if (this->type != IPCTYPE_CLIENT || this->pipe == INVALID_HANDLE_VALUE) return false; - - Pipe::Packet _packet; - strcpy_s(_packet.command, command.data()); - strcpy_s(_packet.buffer, data.data()); - - DWORD cbBytes; - return (WriteFile(this->pipe, &_packet, sizeof(_packet), &cbBytes, nullptr) || GetLastError() == ERROR_IO_PENDING); - } - - void Pipe::destroy() - { - //this->Type = IPCTYPE_NONE; - - //*this->PipeFile = 0; - //*this->PipeName = 0; - - if (this->pipe && INVALID_HANDLE_VALUE != this->pipe) - { - CancelIoEx(this->pipe, nullptr); - //DeleteFileA(this->pipeFile); - - if (this->type == IPCTYPE_SERVER) DisconnectNamedPipe(this->pipe); - - CloseHandle(this->pipe); - Logger::Print("Disconnected from the pipe.\n"); - } - - this->pipe = nullptr; - this->threadAttached = false; - - if (this->thread.joinable()) - { - Logger::Print("Terminating pipe thread...\n"); - - this->thread.join(); - - Logger::Print("Pipe thread terminated.\n"); - } - - this->thread = std::thread(); - } - - void Pipe::setName(std::string name) - { - memset(this->pipeName, 0, sizeof(this->pipeName)); - memset(this->pipeFile, 0, sizeof(this->pipeFile)); - - strncpy_s(this->pipeName, name.data(), sizeof(this->pipeName)); - sprintf_s(this->pipeFile, sizeof(this->pipeFile), "\\\\.\\Pipe\\%s", this->pipeName); - } - - void Pipe::ReceiveThread(Pipe* pipe) - { - if (!pipe || pipe->type != IPCTYPE_SERVER || pipe->pipe == INVALID_HANDLE_VALUE || !pipe->pipe) return; - - if (ConnectNamedPipe(pipe->pipe, nullptr) == FALSE) - { - Logger::Print("Failed to initialize pipe reading.\n"); - return; - } - - Logger::Print("Client connected to the pipe\n"); - pipe->connectCallback(); - - DWORD cbBytes; - - while (pipe->threadAttached && pipe->pipe && pipe->pipe != INVALID_HANDLE_VALUE) - { - BOOL bResult = ReadFile(pipe->pipe, &pipe->packet, sizeof(pipe->packet), &cbBytes, nullptr); - - if (bResult && cbBytes) - { - if (pipe->packetCallbacks.find(pipe->packet.command) != pipe->packetCallbacks.end()) - { - pipe->packetCallbacks[pipe->packet.command](pipe->packet.buffer); - } - } - else if (pipe->threadAttached && pipe->pipe != INVALID_HANDLE_VALUE) - { - Logger::Print("Failed to read from client through pipe\n"); - - DisconnectNamedPipe(pipe->pipe); - ConnectNamedPipe(pipe->pipe, nullptr); - pipe->connectCallback(); - } - - ZeroMemory(&pipe->packet, sizeof(pipe->packet)); - } - } - -#pragma endregion - - // Callback to connect first instance's client pipe to the second instance's server pipe - void IPCPipe::ConnectClient() - { - if (Singleton::IsFirstInstance()) - { - IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_CLIENT); - } - } - - // Writes to the process on the other end of the pipe - bool IPCPipe::Write(std::string command, std::string data) - { - return IPCPipe::ClientPipe.write(command, data); - } - - // Installs a callback for receiving commands from the process on the other end of the pipe - void IPCPipe::On(std::string command, Utils::Slot callback) - { - IPCPipe::ServerPipe.setCallback(command, callback); - } - - IPCPipe::IPCPipe() - { - if (Dedicated::IsEnabled()) return; - - // Server pipe - IPCPipe::ServerPipe.onConnect(IPCPipe::ConnectClient); - IPCPipe::ServerPipe.create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT)); - - // Connect second instance's client pipe to first instance's server pipe - if (!Singleton::IsFirstInstance()) - { - IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_SERVER); - } - - IPCPipe::On("ping", [] (std::string data) - { - Logger::Print("Received ping form pipe, sending pong!\n"); - IPCPipe::Write("pong", data); - }); - - IPCPipe::On("pong", [] (std::string data) - { - Logger::Print("Received pong form pipe!\n"); - }); - - // Test pipe functionality by sending pings - Command::Add("ipcping", [] (Command::Params*) - { - Logger::Print("Sending ping to pipe!\n"); - IPCPipe::Write("ping", ""); - }); - } - - void IPCPipe::preDestroy() - { - IPCPipe::ServerPipe.destroy(); - IPCPipe::ClientPipe.destroy(); - } -} diff --git a/src/Components/Modules/IPCPipe.hpp b/src/Components/Modules/IPCPipe.hpp deleted file mode 100644 index 58bbc713..00000000 --- a/src/Components/Modules/IPCPipe.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#define IPC_MAX_RECONNECTS 3 -#define IPC_COMMAND_SIZE 100 -#define IPC_BUFFER_SIZE 0x2000 - -#define IPC_PIPE_NAME_SERVER "IW4x-Server" -#define IPC_PIPE_NAME_CLIENT "IW4x-Client" - -namespace Components -{ - class Pipe - { - public: - struct Packet - { - char command[IPC_COMMAND_SIZE]; - char buffer[IPC_BUFFER_SIZE]; - }; - - enum Type - { - IPCTYPE_NONE, - IPCTYPE_SERVER, - IPCTYPE_CLIENT - }; - - typedef void(__cdecl PacketCallback)(std::string data); - typedef void(__cdecl Callback)(); - - Pipe(); - ~Pipe(); - - bool connect(std::string name); - bool create(std::string name); - - bool write(std::string command, std::string data); - void setCallback(std::string command, Utils::Slot callback); - void onConnect(Callback callback); - - void destroy(); - - private: - Utils::Slot connectCallback; - std::map> packetCallbacks; - - HANDLE pipe; - std::thread thread; - bool threadAttached; - - Type type; - Packet packet; - - char pipeName[MAX_PATH]; - char pipeFile[MAX_PATH]; - unsigned int reconnectAttempt; - - void setName(std::string name); - - static void ReceiveThread(Pipe* pipe); - }; - - class IPCPipe : public Component - { - public: - IPCPipe(); - -#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) - const char* getName() override { return "IPCPipe"; }; -#endif - - void preDestroy() override; - - static bool Write(std::string command, std::string data); - static void On(std::string command, Utils::Slot callback); - - private: - static Pipe ServerPipe; - static Pipe ClientPipe; - - static void ConnectClient(); - }; -} diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 3c09608b..0cea2fb8 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -244,7 +244,7 @@ namespace Components Game::newMapArena_t* arena = &ArenaLength::NewArenas[i]; if (arena->mapName == map) { - for (int j = 0; j < ARRAY_SIZE(arena->keys); ++j) + for (int j = 0; j < ARRAYSIZE(arena->keys); ++j) { if (arena->keys[j] == "dependency"s) { @@ -267,7 +267,7 @@ namespace Components Game::newMapArena_t* arena = &ArenaLength::NewArenas[i]; if (arena->mapName == map) { - for (int j = 0; j < ARRAY_SIZE(arena->keys); ++j) + for (int j = 0; j < ARRAYSIZE(arena->keys); ++j) { if (arena->keys[j] == "allieschar"s) { diff --git a/src/Components/Modules/ModelSurfs.cpp b/src/Components/Modules/ModelSurfs.cpp index 3a9839ab..36a8121c 100644 --- a/src/Components/Modules/ModelSurfs.cpp +++ b/src/Components/Modules/ModelSurfs.cpp @@ -77,7 +77,7 @@ namespace Components header.sectionHeader[Game::SECTION_FIXUP].buffer = allocator.allocateArray(header.sectionHeader[Game::SECTION_FIXUP].size); // Load section data - for (int i = 0; i < ARRAY_SIZE(header.sectionHeader); ++i) + for (int i = 0; i < ARRAYSIZE(header.sectionHeader); ++i) { model.seek(header.sectionHeader[i].offset, FS_SEEK_SET); if (!model.read(header.sectionHeader[i].buffer, header.sectionHeader[i].size)) diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index cd133499..c0ae951a 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -53,15 +53,8 @@ namespace Components CreateProcessA("updater.exe", nullptr, nullptr, nullptr, false, NULL, nullptr, nullptr, &sInfo, &pInfo); - if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) - { - CloseHandle(pInfo.hThread); - } - - if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) - { - CloseHandle(pInfo.hProcess); - } + if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hThread); + if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pInfo.hProcess); TerminateProcess(GetCurrentProcess(), exitCode); } diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp index f3b16edc..5d62e904 100644 --- a/src/Components/Modules/PlayerName.cpp +++ b/src/Components/Modules/PlayerName.cpp @@ -14,7 +14,7 @@ namespace Components { #if(0) // Disabled for now { - for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) + for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i) { PlayerName::PlayerNames[i] = "mumu"; } @@ -26,7 +26,7 @@ namespace Components PlayerName::~PlayerName() { - for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) + for (int i = 0; i < ARRAYSIZE(PlayerName::PlayerNames); ++i) { PlayerName::PlayerNames[i].clear(); } diff --git a/src/Main.cpp b/src/Main.cpp index 59728f33..3587fd52 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -20,28 +20,43 @@ namespace Main Main::EntryPointHook.uninstall(); Main::SetEnvironment(); - Utils::Cryptography::Initialize(); - Components::Loader::Initialize(); + + if(Worker::IsWorker()) + { + Worker::Initialize(); + } + else + { + Components::Loader::Initialize(); #if defined(DEBUG) || defined(FORCE_UNIT_TESTS) - if (Components::Loader::PerformingUnitTests()) - { - DWORD result = (Components::Loader::PerformUnitTests() ? 0 : -1); - Components::Loader::Uninitialize(); - ExitProcess(result); - } + if (Components::Loader::PerformingUnitTests()) + { + DWORD result = (Components::Loader::PerformUnitTests() ? 0 : -1); + Components::Loader::Uninitialize(); + ExitProcess(result); + } #else - if (Components::Flags::HasFlag("tests")) - { - Components::Logger::Print("Unit tests are disabled outside the debug environment!\n"); - } + if (Components::Flags::HasFlag("tests")) + { + Components::Logger::Print("Unit tests are disabled outside the debug environment!\n"); + } #endif + } } void Uninitialize() { - Components::Loader::Uninitialize(); + if(Worker::IsWorker()) + { + Worker::Uninitialize(); + } + else + { + Components::Loader::Uninitialize(); + } + Utils::Cache::Uninitialize(); google::protobuf::ShutdownProtobufLibrary(); } @@ -51,8 +66,6 @@ BOOL APIENTRY DllMain(HMODULE /*hModule*/, DWORD ul_reason_for_call, LPVOID /*l { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { - Steam::Proxy::RunMod(); - // Ensure we're working with our desired binary if (Utils::Hook::Get(0x4C0FFF) != 0x6824748B) { diff --git a/src/Proto/ipc.proto b/src/Proto/ipc.proto new file mode 100644 index 00000000..f2e71514 --- /dev/null +++ b/src/Proto/ipc.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package Proto.IPC; + +message Command +{ + bytes command = 1; + bytes data = 2; +} diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index be7a6293..971715fd 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -18,6 +18,11 @@ #include #include +#pragma warning(push) +#pragma warning(disable: 4996) +#include +#pragma warning(pop) + #include #include #include @@ -80,10 +85,17 @@ template class Sizer { }; #include "proto/auth.pb.h" #include "proto/node.pb.h" #include "proto/rcon.pb.h" +#include "proto/ipc.pb.h" #pragma warning(pop) +#define ENABLE_BASE64 +#ifndef DISABLE_BASE128 +#define ENABLE_BASE128 +#endif + #include "Utils/IO.hpp" +#include "Utils/IPC.hpp" #include "Utils/CSV.hpp" #include "Utils/Time.hpp" #include "Utils/Cache.hpp" @@ -106,6 +118,7 @@ template class Sizer { }; #include "Utils/Stream.hpp" #include "Components/Loader.hpp" +#include "Worker/Worker.hpp" // Libraries #pragma comment(lib, "Winmm.lib") diff --git a/src/Steam/Proxy.cpp b/src/Steam/Proxy.cpp index 9b845050..e59b00ed 100644 --- a/src/Steam/Proxy.cpp +++ b/src/Steam/Proxy.cpp @@ -5,17 +5,17 @@ namespace Steam ::Utils::Library Proxy::Client; ::Utils::Library Proxy::Overlay; - ISteamClient008* Proxy::SteamClient; - IClientEngine* Proxy::ClientEngine; - IClientUser* Proxy::ClientUser; + ISteamClient008* Proxy::SteamClient = nullptr; + IClientEngine* Proxy::ClientEngine = nullptr; + IClientUser* Proxy::ClientUser = nullptr; - void* Proxy::SteamPipe; - void* Proxy::SteamUser; + void* Proxy::SteamPipe = nullptr; + void* Proxy::SteamUser = nullptr; - Friends15* Proxy::SteamFriends; - Utils* Proxy::SteamUtils; + Friends15* Proxy::SteamFriends = nullptr; + Utils* Proxy::SteamUtils = nullptr; - uint32_t Proxy::AppId; + uint32_t Proxy::AppId = 0; std::recursive_mutex Proxy::CallMutex; std::vector Proxy::Calls; @@ -29,54 +29,15 @@ namespace Steam { Proxy::AppId = appId; - SetEnvironmentVariableA("SteamAppId", ::Utils::String::VA("%lu", appId)); - SetEnvironmentVariableA("SteamGameId", ::Utils::String::VA("%llu", appId & 0xFFFFFF)); +// if (!Components::Flags::HasFlag("nosteam")) +// { +// SetEnvironmentVariableA("SteamAppId", ::Utils::String::VA("%lu", appId)); +// SetEnvironmentVariableA("SteamGameId", ::Utils::String::VA("%llu", appId & 0xFFFFFF)); +// +// ::Utils::IO::WriteFile("steam_appid.txt", ::Utils::String::VA("%lu", appId), false); +// } - ::Utils::IO::WriteFile("steam_appid.txt", ::Utils::String::VA("%lu", appId), false); - } - - void Proxy::SetMod(std::string mod) - { -#if 0 - if (!Proxy::ClientUser) return; - - GameID_t gameID; - gameID.m_nType = 1; // k_EGameIDTypeGameMod - gameID.m_nAppID = Proxy::AppId & 0xFFFFFF; - gameID.m_nModID = 0x01010101; - - char ourPath[MAX_PATH] = { 0 }; - GetModuleFileNameA(GetModuleHandle(nullptr), ourPath, sizeof(ourPath)); - - char ourDirectory[MAX_PATH] = { 0 }; - GetCurrentDirectoryA(sizeof(ourDirectory), ourDirectory); - - char blob[1] = { 0 }; - std::string cmdline = ::Utils::String::VA("\"%s\" -parentProc %d", ourPath, GetCurrentProcessId()); - Proxy::ClientUser->SpawnProcess(blob, 0, ourPath, cmdline.data(), 0, ourDirectory, gameID, Proxy::AppId, mod.data(), 0); -#endif - } - - void Proxy::RunMod() - { - char* command = "-parentProc "; - char* parentProc = strstr(GetCommandLineA(), command); - - if (parentProc) - { - parentProc += strlen(command); - int pid = atoi(parentProc); - - HANDLE processHandle = OpenProcess(SYNCHRONIZE, FALSE, pid); - - if (processHandle && processHandle != INVALID_HANDLE_VALUE) - { - WaitForSingleObject(processHandle, INFINITE); - CloseHandle(processHandle); - } - - TerminateProcess(GetCurrentProcess(), 0); - } + remove("steam_appid.txt"); } void Proxy::RegisterCall(int32_t callId, uint32_t size, uint64_t call) @@ -142,13 +103,13 @@ namespace Steam } Proxy::CallbackMsg message; - while (Proxy::SteamBGetCallback(Proxy::SteamPipe, &message)) + while (Proxy::SteamBGetCallback && Proxy::SteamFreeLastCallback && Proxy::SteamBGetCallback(Proxy::SteamPipe, &message)) { #ifdef DEBUG - Components::Logger::Print("Steam::Proxy: Callback dispatched: %d\n", message.m_iCallback); + printf("Callback dispatched: %d\n", message.m_iCallback); #endif - Steam::Callbacks::RunCallback(message.m_iCallback, message.m_pubParam); + //Steam::Callbacks::RunCallback(message.m_iCallback, message.m_pubParam); Proxy::RunCallback(message.m_iCallback, message.m_pubParam); Proxy::SteamFreeLastCallback(Proxy::SteamPipe); } @@ -163,7 +124,7 @@ namespace Steam ::Utils::Memory::Allocator allocator; #ifdef DEBUG - Components::Logger::Print("Steam::Proxy: Handling call: %d\n", call.callId); + printf("Handling call: %d\n", call.callId); #endif call.handled = true; @@ -172,7 +133,7 @@ namespace Steam { #ifdef DEBUG auto error = Proxy::SteamUtils->GetAPICallFailureReason(call.call); - Components::Logger::Print("Steam::Proxy: API call failed: %X Handle: %llX\n", error, call.call); + printf("API call failed: %X Handle: %llX\n", error, call.call); #endif continue; } @@ -185,7 +146,7 @@ namespace Steam { #ifdef DEBUG auto error = Proxy::SteamUtils->GetAPICallFailureReason(call.call); - Components::Logger::Print("Steam::Proxy: GetAPICallResult failed: %X Handle: %llX\n", error, call.call); + printf("GetAPICallResult failed: %X Handle: %llX\n", error, call.call); #endif continue; } @@ -198,16 +159,19 @@ namespace Steam Proxy::UnregisterCalls(); } - bool Proxy::Inititalize() + bool Proxy::Inititalize(bool overlayOnly) { std::string directoy = Proxy::GetSteamDirectory(); if (directoy.empty()) return false; SetDllDirectoryA(Proxy::GetSteamDirectory().data()); - Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false); Proxy::Overlay = ::Utils::Library(GAMEOVERLAY_LIB, false); - if (!Proxy::Client.valid() || !Proxy::Overlay.valid()) return false; + if (!Proxy::Overlay.valid()) return false; + if (overlayOnly) return true; + + Proxy::Client = ::Utils::Library(STEAMCLIENT_LIB, false); + if (!Proxy::Client.valid()) return false; Proxy::SteamClient = Proxy::Client.get("CreateInterface")("SteamClient008", nullptr); if(!Proxy::SteamClient) return false; diff --git a/src/Steam/Proxy.hpp b/src/Steam/Proxy.hpp index a729e9ce..fe974175 100644 --- a/src/Steam/Proxy.hpp +++ b/src/Steam/Proxy.hpp @@ -334,12 +334,10 @@ namespace Steam class Proxy { public: - static bool Inititalize(); + static bool Inititalize(bool overlayOnly = false); static void Uninititalize(); static void SetGame(uint32_t appId); - static void SetMod(std::string mod); - static void RunMod(); //Overlay related proxies static void SetOverlayNotificationPosition(uint32_t eNotificationPosition); diff --git a/src/Steam/Steam.cpp b/src/Steam/Steam.cpp index bfa450ac..d8e5580a 100644 --- a/src/Steam/Steam.cpp +++ b/src/Steam/Steam.cpp @@ -106,26 +106,12 @@ namespace Steam { bool SteamAPI_Init() { -#ifndef DISABLE_STEAM_GAME - if (!Components::Flags::HasFlag("nosteam")) - { - //Proxy::SetGame(10190); - } -#endif + Proxy::SetGame(10190); - if (!Proxy::Inititalize()) + if (!Proxy::Inititalize(true)) { OutputDebugStringA("Steamproxy not initialized properly"); } - else - { -#ifndef DISABLE_STEAM_GAME - if (!Components::Flags::HasFlag("nosteam")) - { - //Proxy::SetMod("IW4x - Modern Warfare 2"); - } -#endif - } return true; } @@ -143,7 +129,7 @@ namespace Steam void SteamAPI_RunCallbacks() { Callbacks::RunCallbacks(); - Proxy::RunFrame(); + //Proxy::RunFrame(); } void SteamAPI_Shutdown() diff --git a/src/Utils/Cache.cpp b/src/Utils/Cache.cpp index 48de605e..cefdb0da 100644 --- a/src/Utils/Cache.cpp +++ b/src/Utils/Cache.cpp @@ -29,7 +29,7 @@ namespace Utils if (Cache::ValidUrl.empty()) { - for (int i = 0; i < ARRAY_SIZE(Cache::Urls); i++) + for (int i = 0; i < ARRAYSIZE(Cache::Urls); i++) { std::string result = Utils::WebIO(useragent, Cache::GetUrl(Cache::Urls[i], path)).setTimeout(timeout)->get(); diff --git a/src/Utils/IPC.cpp b/src/Utils/IPC.cpp new file mode 100644 index 00000000..3e133b9e --- /dev/null +++ b/src/Utils/IPC.cpp @@ -0,0 +1,104 @@ +#include "STDInclude.hpp" + +namespace Utils +{ + namespace IPC + { + Channel::Channel(std::string _name, int _queueSize, int _bufferSize, bool _remove) : name(_name), remove(_remove) + { + if(this->remove) boost::interprocess::message_queue::remove(this->name.data()); + queue.reset(new boost::interprocess::message_queue(boost::interprocess::open_or_create, this->name.data(), _queueSize, _bufferSize + sizeof(Channel::Header))); + } + + Channel::~Channel() + { + if (this->remove) boost::interprocess::message_queue::remove(this->name.data()); + } + + bool Channel::receive(std::string* data) + { + if (!data) return false; + data->clear(); + + if(this->packet.size() < this->queue->get_max_msg_size()) + { + packet.resize(this->queue->get_max_msg_size()); + } + + const Channel::Header* header = reinterpret_cast(packet.data()); + const char* buffer = reinterpret_cast(header + 1); + + unsigned int priority; + boost::interprocess::message_queue::size_type recvd_size; + + if (this->queue->try_receive(const_cast(packet.data()), packet.size(), recvd_size, priority)) + { + if ((recvd_size - sizeof(Channel::Header)) != header->fragmentSize || header->fragmentPart) return false; + data->append(buffer, header->fragmentSize); + + if(header->fragmented) + { + Channel::Header mainHeader = *header; + unsigned int part = mainHeader.fragmentPart; + + while (true) + { + if (!this->queue->try_receive(const_cast(packet.data()), packet.size(), recvd_size, priority)) return false; + + if (header->packetId != mainHeader.packetId || header->totalSize != mainHeader.totalSize || header->fragmentPart != (++part)) + { + data->clear(); + return false; + } + + data->append(buffer, header->fragmentSize); + + if(header->totalSize <= data->size()) + { + break; + } + } + } + + return true; + } + + return false; + } + + void Channel::send(std::string data) + { + const size_t fragmentSize = (this->queue->get_max_msg_size() - sizeof(Channel::Header)) - 1; + + Channel::Header header; + header.fragmented = (data.size() + sizeof(Channel::Header)) > this->queue->get_max_msg_size(); + header.packetId = static_cast(timeGetTime() + rand());; + header.totalSize = data.size(); + + size_t sentSize = 0; + for (unsigned short i = 0; sentSize < data.size(); ++i) + { + header.fragmentPart = i; + header.fragmentSize = std::min(fragmentSize, data.size() - (fragmentSize * i)); + + std::string buffer; + buffer.append(reinterpret_cast(&header), sizeof(Channel::Header)); + buffer.append(data.data() + sentSize, header.fragmentSize); + Channel::sendMessage(buffer); + + sentSize += header.fragmentSize; + } + } + + void Channel::sendMessage(std::string data) + { + if (data.size() <= this->queue->get_max_msg_size()) + { + while (!this->queue->try_send(data.data(), data.size(), 0)) + { + std::this_thread::sleep_for(100us); + } + } + } + } +} diff --git a/src/Utils/IPC.hpp b/src/Utils/IPC.hpp new file mode 100644 index 00000000..01fc080c --- /dev/null +++ b/src/Utils/IPC.hpp @@ -0,0 +1,94 @@ +#pragma once + +namespace boost +{ + typedef unsigned long long ulong_long_type; +} + +#pragma warning(push) +#pragma warning(disable: 4091) +#pragma warning(disable: 4996) +#define _SCL_SECURE_NO_WARNINGS + +#ifdef sleep +#undef sleep +#endif + +//#define BOOST_DISABLE_WIN32 +#define BOOST_USE_WINDOWS_H +#define BOOST_DATE_TIME_NO_LIB +#include + +#undef _SCL_SECURE_NO_WARNINGS +#pragma warning(pop) + +namespace Utils +{ + namespace IPC + { + class Channel + { + public: + Channel(std::string _name, int _queueSize = 100, int _bufferSize = 1024, bool _remove = false); + ~Channel(); + + bool receive(std::string* data); + void send(std::string data); + + private: + struct Header + { + bool fragmented; + unsigned short packetId; + size_t fragmentSize; + size_t totalSize; + unsigned int fragmentPart; + }; + + void sendMessage(std::string data); + + bool remove; + std::unique_ptr queue; + std::string packet; + std::string name; + }; + + class BidirectionalChannel + { + public: + BidirectionalChannel(std::string name, bool server, int queueSize = 100, int bufferSize = 1024) : isServer(server), + channel1(name, queueSize, bufferSize, server), + channel2(name + "2", queueSize, bufferSize, server) + {} + + bool receive(std::string* data) + { + if(this->isServer) + { + return channel1.receive(data); + } + else + { + return channel2.receive(data); + } + } + + void send(std::string data) + { + if (this->isServer) + { + return channel2.send(data); + } + else + { + return channel1.send(data); + } + } + + private: + const bool isServer; + Channel channel1; + Channel channel2; + }; + } +} diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 8fbfd180..0ce7a9df 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -1,5 +1,5 @@ #include "STDInclude.hpp" -#ifndef DISABLE_BASE128 +#ifdef ENABLE_BASE128 #include "base128.h" #endif @@ -158,7 +158,7 @@ namespace Utils double bytesPerSecond = (1000.0 / milliseconds) * bytes; int i; - for (i = 0; bytesPerSecond > 1000 && i < ARRAY_SIZE(sizes); ++i) // 1024 or 1000? + for (i = 0; bytesPerSecond > 1000 && i < ARRAYSIZE(sizes); ++i) // 1024 or 1000? { bytesPerSecond /= 1000; } @@ -166,6 +166,7 @@ namespace Utils return Utils::String::VA("%.2f %s/s", static_cast(bytesPerSecond), sizes[i]); } +#ifdef ENABLE_BASE64 // Encodes a given string in Base64 std::string EncodeBase64(const char* input, const unsigned long inputSize) { @@ -182,8 +183,9 @@ namespace Utils { return EncodeBase64(input.data(), input.size()); } +#endif -#ifndef DISABLE_BASE128 +#ifdef ENABLE_BASE128 // Encodes a given string in Base128 std::string EncodeBase128(const std::string& input) { diff --git a/src/Worker/Runner.cpp b/src/Worker/Runner.cpp new file mode 100644 index 00000000..be4b63a1 --- /dev/null +++ b/src/Worker/Runner.cpp @@ -0,0 +1,60 @@ +#include "STDInclude.hpp" + +namespace Worker +{ + Runner::Runner(int pid) : processId(pid), terminate(false) + { + + } + + Runner::~Runner() + { + + } + + void Runner::run() + { + HANDLE processHandle = OpenProcess(SYNCHRONIZE, FALSE, this->processId); + if (!processHandle || processHandle == INVALID_HANDLE_VALUE) + { + printf("Unable to attach to parent process\n"); + } + else + { + printf("Successfully attached to parent process\n"); + printf("Starting worker...\n"); + + std::thread workerThread(&Runner::worker, this); + + WaitForSingleObject(processHandle, INFINITE); + CloseHandle(processHandle); + + printf("Awaiting worker termination...\n"); + this->terminate = true; + if (workerThread.joinable()) workerThread.join(); + printf("Worker terminated\n"); + } + } + + void Runner::worker() + { + printf("Worker started\n"); + Utils::IPC::BidirectionalChannel channel("IW4x-Worker-Channel", !Worker::IsWorker()); + + while (!this->terminate) + { + Steam::Proxy::RunFrame(); + + std::string buffer; + if (channel.receive(&buffer)) + { + printf("Data received: %s\n", buffer.data()); + channel.send("OK " + buffer); + } + + std::this_thread::sleep_for(1ms); + } + + printf("Terminating worker\n"); + } +} diff --git a/src/Worker/Runner.hpp b/src/Worker/Runner.hpp new file mode 100644 index 00000000..4c13444b --- /dev/null +++ b/src/Worker/Runner.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace Worker +{ + class Runner + { + public: + Runner(int pid); + ~Runner(); + + void run(); + + private: + void worker(); + + int processId; + bool terminate; + }; +} diff --git a/src/Worker/Worker.cpp b/src/Worker/Worker.cpp new file mode 100644 index 00000000..e27c2619 --- /dev/null +++ b/src/Worker/Worker.cpp @@ -0,0 +1,65 @@ +#include "STDInclude.hpp" + +namespace Worker +{ + int ProcessId; + + int __stdcall EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, char* /*lpCmdLine*/, int /*nCmdShow*/) + { + Runner runner(Worker::ProcessId); + runner.run(); + return 0; + } + + void Initialize() + { + if(!Steam::Proxy::Inititalize()) + { + printf("Failed to initialize worker!\n"); + ExitProcess(1); + } + else + { +#ifdef DEBUG + SetConsoleTitleA("IW4x Worker"); +#else + FreeConsole(); +#endif + + Utils::Hook(0x6BABA1, Worker::EntryPoint, HOOK_CALL).install()->quick(); + } + } + + void Uninitialize() + { + Steam::Proxy::Uninititalize(); + } + + bool ParseWorkerFlag() + { + char* command = "-parent "; + char* parentProc = strstr(GetCommandLineA(), command); + + if (parentProc) + { + parentProc += strlen(command); + Worker::ProcessId = atoi(parentProc); + + return true; + } + + return false; + } + + bool IsWorker() + { + static Utils::Value flag; + + if (!flag.isValid()) + { + flag.set(Worker::ParseWorkerFlag()); + } + + return flag.get(); + } +} diff --git a/src/Worker/Worker.hpp b/src/Worker/Worker.hpp new file mode 100644 index 00000000..4f700b23 --- /dev/null +++ b/src/Worker/Worker.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace Worker +{ + void Initialize(); + void Uninitialize(); + + bool IsWorker(); +} + +#include "Runner.hpp"