From 369267ef39d4996dd22c90cb53582cbd2a3c29c5 Mon Sep 17 00:00:00 2001 From: /dev/root Date: Thu, 25 Aug 2016 18:17:47 +0200 Subject: [PATCH 01/81] added submodules for bitmrc --- .gitmodules | 6 ++++ deps/bitmrc | 1 + deps/libcryptopp | 1 + premake/bitmrc.lua | 52 ++++++++++++++++++++++++++++ premake/libcryptopp.lua | 49 ++++++++++++++++++++++++++ premake5.lua | 14 ++++++++ src/Components/Modules/Exception.cpp | 1 + src/STDInclude.hpp | 2 ++ 8 files changed, 126 insertions(+) create mode 160000 deps/bitmrc create mode 160000 deps/libcryptopp create mode 100644 premake/bitmrc.lua create mode 100644 premake/libcryptopp.lua diff --git a/.gitmodules b/.gitmodules index dc5c9e50..2af34286 100644 --- a/.gitmodules +++ b/.gitmodules @@ -29,3 +29,9 @@ [submodule "deps/Wink-Signals"] path = deps/Wink-Signals url = https://github.com/miguelmartin75/Wink-Signals.git +[submodule "deps/bitmrc"] + path = deps/bitmrc + url = https://github.com/mrc-g/BitMRC.git +[submodule "deps/libcryptopp"] + path = deps/libcryptopp + url = https://github.com/weidai11/cryptopp.git diff --git a/deps/bitmrc b/deps/bitmrc new file mode 160000 index 00000000..92a1bb86 --- /dev/null +++ b/deps/bitmrc @@ -0,0 +1 @@ +Subproject commit 92a1bb86fbab92896ab53cbc102e51531fa281ca diff --git a/deps/libcryptopp b/deps/libcryptopp new file mode 160000 index 00000000..65e91a8c --- /dev/null +++ b/deps/libcryptopp @@ -0,0 +1 @@ +Subproject commit 65e91a8caa8c1846cb311bc83d8507e12699d6d3 diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua new file mode 100644 index 00000000..5513e4d1 --- /dev/null +++ b/premake/bitmrc.lua @@ -0,0 +1,52 @@ +bitmrc = { + settings = nil, +} + +function bitmrc.setup(settings) + if not settings.source then error("Missing source.") end + + bitmrc.settings = settings +end + +function bitmrc.import() + if not bitmrc.settings then error("Run bitmrc.setup first") end + + bitmrc.includes() +end + +function bitmrc.includes() + if not bitmrc.settings then error("Run bitmrc.setup first") end + + includedirs { path.join(bitmrc.settings.source, "BitMRC/include") } +end + +function bitmrc.project() + if not bitmrc.settings then error("Run bitmrc.setup first") end + + project "bitmrc" + language "C++" + + includedirs + { + path.join(bitmrc.settings.source, "src"), + } + files + { + path.join(bitmrc.settings.source, "src/**.cc"), + } + removefiles + { + -- path.join(bitmrc.settings.source, "src/**/*test.cc"), + path.join(bitmrc.settings.source, "BitMRC/main.cpp"), + } + + -- dependencies + libcryptopp.import() + + -- not our code, ignore POSIX usage warnings for now + defines { "_SCL_SECURE_NO_WARNINGS" } + warnings "Off" + + -- always build as static lib, as we include our custom classes and therefore can't perform shared linking + kind "StaticLib" +end diff --git a/premake/libcryptopp.lua b/premake/libcryptopp.lua new file mode 100644 index 00000000..fea7ec83 --- /dev/null +++ b/premake/libcryptopp.lua @@ -0,0 +1,49 @@ +libcryptopp = { + settings = nil, +} + +function libcryptopp.setup(settings) + if not settings.source then error("Missing source.") end + + libcryptopp.settings = settings +end + +function libcryptopp.import() + if not libcryptopp.settings then error("Run libcryptopp.setup first") end + + libcryptopp.includes() +end + +function libcryptopp.includes() + if not libcryptopp.settings then error("Run libcryptopp.setup first") end + + includedirs { libcryptopp.settings.source } +end + +function libcryptopp.project() + if not libcryptopp.settings then error("Run libcryptopp.setup first") end + + project "libcryptopp" + language "C++" + + includedirs + { + libcryptopp.settings.source + } + files + { + path.join(libcryptopp.settings.source, "src/**.cpp"), + } + removefiles + { + path.join(libcryptopp.settings.source, "TestData/**"), + path.join(libcryptopp.settings.source, "TestVectors/**"), + } + + -- not our code, ignore POSIX usage warnings for now + defines { "_SCL_SECURE_NO_WARNINGS" } + warnings "Off" + + -- always build as static lib, as we include our custom classes and therefore can't perform shared linking + kind "StaticLib" +end diff --git a/premake5.lua b/premake5.lua index 49f45a63..87f1a491 100644 --- a/premake5.lua +++ b/premake5.lua @@ -134,6 +134,8 @@ require "premake/pdcurses" require "premake/protobuf" require "premake/winksignals" require "premake/zlib" +require "premake/bitmrc" +require "premake/libcryptopp" fmt.setup { @@ -182,6 +184,14 @@ zlib.setup }, source = path.join(depsBasePath, "zlib"), } +bitmrc.setup +{ + source = path.join(depsBasePath, "bitmrc"), +} +libcryptopp.setup +{ + source = path.join(depsBasePath, "libcryptopp"), +} workspace "iw4x" location "./build" @@ -254,6 +264,8 @@ workspace "iw4x" protobuf.import() winksignals.import() zlib.import() + bitmrc.import() + libcryptopp.import() -- fix vpaths for protobuf sources vpaths @@ -353,6 +365,8 @@ workspace "iw4x" winksignals.project() zlib.project() protobuf.project() + bitmrc.project() + libcryptopp.project() rule "ProtobufCompiler" display "Protobuf compiler" diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 12aafa65..97fd4aa2 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -1,5 +1,6 @@ #include "STDInclude.hpp" + // Stuff causes warnings #pragma warning(push) #pragma warning(disable: 4091) diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 73032776..98bbbfc3 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -60,6 +60,8 @@ #include #include #include +// Bitmessage +#include #ifdef max #undef max From e6cfae9e6ff94250167dd38305a989c881248030 Mon Sep 17 00:00:00 2001 From: /dev/root Date: Thu, 25 Aug 2016 18:38:45 +0200 Subject: [PATCH 02/81] latest version bitmrc --- premake/bitmrc.lua | 5 +++-- premake5.lua | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index 5513e4d1..f5d68c1f 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -28,16 +28,17 @@ function bitmrc.project() includedirs { - path.join(bitmrc.settings.source, "src"), + path.join(bitmrc.settings.source, "BitMRC/include"), } files { - path.join(bitmrc.settings.source, "src/**.cc"), + path.join(bitmrc.settings.source, "BitMRC/**.cpp"), } removefiles { -- path.join(bitmrc.settings.source, "src/**/*test.cc"), path.join(bitmrc.settings.source, "BitMRC/main.cpp"), + path.join(bitmrc.settings.source, "BitMRC/tests/**"), } -- dependencies diff --git a/premake5.lua b/premake5.lua index 87f1a491..c1dc70a3 100644 --- a/premake5.lua +++ b/premake5.lua @@ -134,8 +134,8 @@ require "premake/pdcurses" require "premake/protobuf" require "premake/winksignals" require "premake/zlib" -require "premake/bitmrc" require "premake/libcryptopp" +require "premake/bitmrc" fmt.setup { @@ -184,14 +184,14 @@ zlib.setup }, source = path.join(depsBasePath, "zlib"), } -bitmrc.setup -{ - source = path.join(depsBasePath, "bitmrc"), -} libcryptopp.setup { source = path.join(depsBasePath, "libcryptopp"), } +bitmrc.setup +{ + source = path.join(depsBasePath, "bitmrc"), +} workspace "iw4x" location "./build" @@ -264,8 +264,8 @@ workspace "iw4x" protobuf.import() winksignals.import() zlib.import() - bitmrc.import() libcryptopp.import() + bitmrc.import() -- fix vpaths for protobuf sources vpaths @@ -365,8 +365,8 @@ workspace "iw4x" winksignals.project() zlib.project() protobuf.project() - bitmrc.project() libcryptopp.project() + bitmrc.project() rule "ProtobufCompiler" display "Protobuf compiler" From fb737eb9d2fe96bfa7e40415b7b80f51dcd7811b Mon Sep 17 00:00:00 2001 From: /dev/root Date: Thu, 25 Aug 2016 18:45:00 +0200 Subject: [PATCH 03/81] added more ignores --- premake/bitmrc.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index f5d68c1f..058632cc 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -39,6 +39,8 @@ function bitmrc.project() -- path.join(bitmrc.settings.source, "src/**/*test.cc"), path.join(bitmrc.settings.source, "BitMRC/main.cpp"), path.join(bitmrc.settings.source, "BitMRC/tests/**"), + path.join(bitmrc.settings.source, "BitMRC/Storage/**"), + path.join(bitmrc.settings.source, "BitMRC/Debug/**"), } -- dependencies From 9ea71dfb1dbc8e44d03c57086777742a5e39a95e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 26 Aug 2016 12:23:28 +0200 Subject: [PATCH 04/81] New deps --- deps/fmt | 2 +- deps/mongoose | 2 +- deps/protobuf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/fmt b/deps/fmt index f19d8f96..2ae6bca4 160000 --- a/deps/fmt +++ b/deps/fmt @@ -1 +1 @@ -Subproject commit f19d8f9655d550234f19c6c1f5a99c7eda798c0e +Subproject commit 2ae6bca488795929a0207d109e135751f10c53d9 diff --git a/deps/mongoose b/deps/mongoose index af6fc64a..b3fb21da 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit af6fc64ab9bec64e91b2bebc16f71d07d5d2e208 +Subproject commit b3fb21dacccfb08b046b73740eec52cd66e944de diff --git a/deps/protobuf b/deps/protobuf index 549dde19..3d9d1a12 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 549dde19282767af6ba875ace06644ab5cfd14e2 +Subproject commit 3d9d1a1255583bac550f7bf94f3016e8c238fa5e From 1c9badb4a23778204d2e619c8f458a6db46e8a57 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 20:44:36 +0200 Subject: [PATCH 05/81] Premake: Fix libcryptopp build and use files shipped with bitmrc. --- .gitmodules | 19 +++---- deps/libcryptopp | 1 - premake/libcryptopp.lua | 110 ++++++++++++++++++++++++++++++++++++---- premake5.lua | 16 +++--- 4 files changed, 115 insertions(+), 31 deletions(-) delete mode 160000 deps/libcryptopp diff --git a/.gitmodules b/.gitmodules index 2af34286..9955a042 100644 --- a/.gitmodules +++ b/.gitmodules @@ -23,15 +23,12 @@ path = deps/mongoose url = https://github.com/cesanta/mongoose.git ignore = dirty -[submodule "deps/fmt"] - path = deps/fmt - url = https://github.com/fmtlib/fmt.git -[submodule "deps/Wink-Signals"] - path = deps/Wink-Signals - url = https://github.com/miguelmartin75/Wink-Signals.git +[submodule "deps/fmt"] + path = deps/fmt + url = https://github.com/fmtlib/fmt.git +[submodule "deps/Wink-Signals"] + path = deps/Wink-Signals + url = https://github.com/miguelmartin75/Wink-Signals.git [submodule "deps/bitmrc"] - path = deps/bitmrc - url = https://github.com/mrc-g/BitMRC.git -[submodule "deps/libcryptopp"] - path = deps/libcryptopp - url = https://github.com/weidai11/cryptopp.git + path = deps/bitmrc + url = https://github.com/mrc-g/BitMRC.git diff --git a/deps/libcryptopp b/deps/libcryptopp deleted file mode 160000 index 65e91a8c..00000000 --- a/deps/libcryptopp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 65e91a8caa8c1846cb311bc83d8507e12699d6d3 diff --git a/premake/libcryptopp.lua b/premake/libcryptopp.lua index fea7ec83..9d7fff45 100644 --- a/premake/libcryptopp.lua +++ b/premake/libcryptopp.lua @@ -17,33 +17,121 @@ end function libcryptopp.includes() if not libcryptopp.settings then error("Run libcryptopp.setup first") end - includedirs { libcryptopp.settings.source } + filter "Debug*" + defines { "_DEBUG" } + + filter "Release*" + defines { "NDEBUG" } + + filter "system:windows" + defines { "_WINDOWS", "WIN32" } + filter {} + + includedirs { libcryptopp.settings.source } end function libcryptopp.project() if not libcryptopp.settings then error("Run libcryptopp.setup first") end + externalrule "MASM" + buildmessage "Building and assembling %(Identity)..." + propertydefinition { + name = "PreprocessorDefinitions", + kind = "string", + value = "", + switch = "/D", + } + propertydefinition { + name = "UseSafeExceptionHandlers", + kind = "boolean", + value = false, + switch = "/safeseh", + } + + --[[ + rule "CustomProtoBuildTool" + display "C++ prototype copy" + location "./build" + fileExtension ".proto" + buildmessage "Preparing %(Identity)..." + buildcommands { + 'if not exist "$(ProjectDir)\\src\\%(Filename)" copy "%(Identity)" "$(ProjectDir)\\src\\%(Filename)"', + 'echo: >> "src\\%(Filename).copied"', + } + buildoutputs { + '$(ProjectDir)\\src\\%(Filename)', + } + ]] + project "libcryptopp" language "C++" + characterset "MBCS" + defines { + "USE_PRECOMPILED_HEADERS" + } includedirs { - libcryptopp.settings.source + libcryptopp.settings.source, } files { - path.join(libcryptopp.settings.source, "src/**.cpp"), - } - removefiles - { - path.join(libcryptopp.settings.source, "TestData/**"), - path.join(libcryptopp.settings.source, "TestVectors/**"), + path.join(libcryptopp.settings.source, "*.cpp"), + --path.join(libcryptopp.settings.source, "*.cpp.proto"), + path.join(libcryptopp.settings.source, "*.h"), + path.join(libcryptopp.settings.source, "*.txt"), } - -- not our code, ignore POSIX usage warnings for now + removefiles { + path.join(libcryptopp.settings.source, "eccrypto.cpp"), + path.join(libcryptopp.settings.source, "eprecomp.cpp"), + path.join(libcryptopp.settings.source, "bench*"), + path.join(libcryptopp.settings.source, "*test.*"), + path.join(libcryptopp.settings.source, "fipsalgt.*"), + path.join(libcryptopp.settings.source, "cryptlib_bds.*"), + path.join(libcryptopp.settings.source, "validat*.*"), + } + + -- Pre-compiled header + pchheader "pch.h" -- must be exactly same as used in #include directives + pchsource(path.join(libcryptopp.settings.source, "pch.cpp")) -- real path + defines { "_SCL_SECURE_NO_WARNINGS" } warnings "Off" - -- always build as static lib, as we include our custom classes and therefore can't perform shared linking - kind "StaticLib" + vectorextensions "SSE" + + rules { + "MASM", + --"CustomProtoBuildTool", + } + + kind "SharedLib" + filter "*Static" + kind "StaticLib" + + filter "kind:SharedLib" + defines { "CRYPTOPP_IMPORTS" } + + filter "architecture:x86" + exceptionhandling "SEH" + masmVars { + UseSafeExceptionHandlers = true, + PreprocessorDefinitions = "_M_X86", + } + filter "architecture:x64" + files { + path.join(libcryptopp.settings.source, "x64masm.asm"), + } + masmVars { + PreprocessorDefinitions = "_M_X64", + } + filter { "architecture:x64", "kind:SharedLib" } + files { + path.join(libcryptopp.settings.source, "x64dll.asm"), + } + + filter("files:" .. path.join(libcryptopp.settings.source, "dll.cpp") + .. " or files:" .. path.join(libcryptopp.settings.source, "iterhash.cpp")) + flags { "NoPCH" } end diff --git a/premake5.lua b/premake5.lua index c1dc70a3..f582e8ba 100644 --- a/premake5.lua +++ b/premake5.lua @@ -137,6 +137,10 @@ require "premake/zlib" require "premake/libcryptopp" require "premake/bitmrc" +bitmrc.setup +{ + source = path.join(depsBasePath, "bitmrc"), +} fmt.setup { source = path.join(depsBasePath, "fmt"), @@ -145,6 +149,10 @@ json11.setup { source = path.join(depsBasePath, "json11"), } +libcryptopp.setup +{ + source = path.join(depsBasePath, "bitmrc/libcryptopp"), +} libtomcrypt.setup { defines = { @@ -184,14 +192,6 @@ zlib.setup }, source = path.join(depsBasePath, "zlib"), } -libcryptopp.setup -{ - source = path.join(depsBasePath, "libcryptopp"), -} -bitmrc.setup -{ - source = path.join(depsBasePath, "bitmrc"), -} workspace "iw4x" location "./build" From a7d80f7187e6f8c871cf4189718136932d50f3a1 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 20:51:20 +0200 Subject: [PATCH 06/81] Premake: Fix BitMRC build and add shipped sqlite3 as separate project. --- premake/bitmrc.lua | 15 ++++++++------ premake/sqlite3.lua | 50 +++++++++++++++++++++++++++++++++++++++++++++ premake5.lua | 18 +++++++++------- 3 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 premake/sqlite3.lua diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index 058632cc..758c8457 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -11,6 +11,9 @@ end function bitmrc.import() if not bitmrc.settings then error("Run bitmrc.setup first") end + sqlite3.import() + libcryptopp.import() + bitmrc.includes() end @@ -29,27 +32,27 @@ function bitmrc.project() includedirs { path.join(bitmrc.settings.source, "BitMRC/include"), + path.join(bitmrc.settings.source, "BitMRC/Storage/include"), } files { - path.join(bitmrc.settings.source, "BitMRC/**.cpp"), + path.join(bitmrc.settings.source, "BitMRC/*.cpp"), + path.join(bitmrc.settings.source, "BitMRC/Storage/*.cpp"), } removefiles { -- path.join(bitmrc.settings.source, "src/**/*test.cc"), - path.join(bitmrc.settings.source, "BitMRC/main.cpp"), + path.join(bitmrc.settings.source, "BitMRC/main.*"), + path.join(bitmrc.settings.source, "BitMRC/class.*"), path.join(bitmrc.settings.source, "BitMRC/tests/**"), - path.join(bitmrc.settings.source, "BitMRC/Storage/**"), - path.join(bitmrc.settings.source, "BitMRC/Debug/**"), } -- dependencies + sqlite3.import() libcryptopp.import() - -- not our code, ignore POSIX usage warnings for now defines { "_SCL_SECURE_NO_WARNINGS" } warnings "Off" - -- always build as static lib, as we include our custom classes and therefore can't perform shared linking kind "StaticLib" end diff --git a/premake/sqlite3.lua b/premake/sqlite3.lua new file mode 100644 index 00000000..ad4597e7 --- /dev/null +++ b/premake/sqlite3.lua @@ -0,0 +1,50 @@ +sqlite3 = { + settings = nil, +} + +function sqlite3.setup(settings) + if not settings.source then error("Missing source.") end + + sqlite3.settings = settings +end + +function sqlite3.import() + if not sqlite3.settings then error("Run sqlite3.setup first") end + + links { "sqlite3" } + sqlite3.includes() +end + +function sqlite3.includes() + if not sqlite3.settings then error("Run sqlite3.setup first") end + + includedirs { sqlite3.settings.source } +end + +function sqlite3.project() + if not sqlite3.settings then error("Run sqlite3.setup first") end + + project "sqlite3" + language "C++" + + includedirs + { + sqlite3.settings.source, + } + + files + { + path.join(sqlite3.settings.source, "*.c"), + path.join(sqlite3.settings.source, "*.h"), + } + + -- not our code, ignore POSIX usage warnings for now + warnings "Off" + + kind "SharedLib" + filter "*Static" + kind "StaticLib" + filter "kind:StaticLib" + defines { "_LIB" } + removedefines { "_USRDLL", "_DLL" } +end diff --git a/premake5.lua b/premake5.lua index f582e8ba..30942cab 100644 --- a/premake5.lua +++ b/premake5.lua @@ -125,17 +125,18 @@ newaction { depsBasePath = "./deps" +require "premake/bitmrc" require "premake/fmt" require "premake/json11" +require "premake/libcryptopp" require "premake/libtomcrypt" require "premake/libtommath" require "premake/mongoose" require "premake/pdcurses" require "premake/protobuf" +require "premake/sqlite3" require "premake/winksignals" require "premake/zlib" -require "premake/libcryptopp" -require "premake/bitmrc" bitmrc.setup { @@ -181,6 +182,10 @@ protobuf.setup { source = path.join(depsBasePath, "protobuf"), } +sqlite3.setup +{ + source = path.join(depsBasePath, "bitmrc/windows/sqlite3"), +} winksignals.setup { source = path.join(depsBasePath, "Wink-Signals"), @@ -255,6 +260,7 @@ workspace "iw4x" buildoptions { "/Zm200" } -- Dependency libraries + bitmrc.import() fmt.import() json11.import() libtomcrypt.import() @@ -264,8 +270,6 @@ workspace "iw4x" protobuf.import() winksignals.import() zlib.import() - libcryptopp.import() - bitmrc.import() -- fix vpaths for protobuf sources vpaths @@ -356,17 +360,17 @@ workspace "iw4x" } group "External dependencies" + bitmrc.project() fmt.project() json11.project() + libcryptopp.project() libtomcrypt.project() libtommath.project() mongoose.project() pdcurses.project() + protobuf.project() winksignals.project() zlib.project() - protobuf.project() - libcryptopp.project() - bitmrc.project() rule "ProtobufCompiler" display "Protobuf compiler" From 70a9cc62d84a5f6f89027d3ece597b06559a0a17 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 21:24:41 +0200 Subject: [PATCH 07/81] Premake: Implement a working hack to change MASM parameters for libcryptopp. --- premake/libcryptopp.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/premake/libcryptopp.lua b/premake/libcryptopp.lua index 9d7fff45..a003ca24 100644 --- a/premake/libcryptopp.lua +++ b/premake/libcryptopp.lua @@ -33,7 +33,14 @@ end function libcryptopp.project() if not libcryptopp.settings then error("Run libcryptopp.setup first") end + rule "MASM_dummy" + location "./build" + fileextension "" + filename "masm_dummy" + externalrule "MASM" + filename "masm_dummy" + location "./build" buildmessage "Building and assembling %(Identity)..." propertydefinition { name = "PreprocessorDefinitions", From ee46d2fe203fbba9122835655d479abf1ceb0450 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 21:38:13 +0200 Subject: [PATCH 08/81] Premake: Fix missing links for BitMRC and Crypto++. --- premake/bitmrc.lua | 6 +++++- premake/libcryptopp.lua | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index 758c8457..3608710a 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -13,10 +13,14 @@ function bitmrc.import() sqlite3.import() libcryptopp.import() - + bitmrc.links() bitmrc.includes() end +function bitmrc.links() + links { "bitmrc" } +end + function bitmrc.includes() if not bitmrc.settings then error("Run bitmrc.setup first") end diff --git a/premake/libcryptopp.lua b/premake/libcryptopp.lua index a003ca24..d0a05021 100644 --- a/premake/libcryptopp.lua +++ b/premake/libcryptopp.lua @@ -11,9 +11,14 @@ end function libcryptopp.import() if not libcryptopp.settings then error("Run libcryptopp.setup first") end + libcryptopp.links() libcryptopp.includes() end +function libcryptopp.links() + links { "libcryptopp" } +end + function libcryptopp.includes() if not libcryptopp.settings then error("Run libcryptopp.setup first") end From bcb10258e1b96a2a5acf170ebdfb9ebb8a675733 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 22:46:07 +0200 Subject: [PATCH 09/81] Switch to our own fork of BitMRC. This gets rid of the useless and bad practice style "using namespace" usage in the public headers of BitMRC. I plan on submitting this to the developer as a pull request at some point. --- .gitmodules | 2 +- deps/bitmrc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9955a042..83990074 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,4 +31,4 @@ url = https://github.com/miguelmartin75/Wink-Signals.git [submodule "deps/bitmrc"] path = deps/bitmrc - url = https://github.com/mrc-g/BitMRC.git + url = git@github.com:iw4x-dev-urandom/BitMRC.git diff --git a/deps/bitmrc b/deps/bitmrc index 92a1bb86..3b2766db 160000 --- a/deps/bitmrc +++ b/deps/bitmrc @@ -1 +1 @@ -Subproject commit 92a1bb86fbab92896ab53cbc102e51531fa281ca +Subproject commit 3b2766db750b7a5a5e499ffa72e82c2d86a357f0 From 86c6450ac2359de209d91269e850425b631ec44f Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 22:46:37 +0200 Subject: [PATCH 10/81] Premake: Fix SQLite inclusion. --- premake/sqlite3.lua | 10 +++++++--- premake5.lua | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/premake/sqlite3.lua b/premake/sqlite3.lua index ad4597e7..730eea78 100644 --- a/premake/sqlite3.lua +++ b/premake/sqlite3.lua @@ -11,8 +11,12 @@ end function sqlite3.import() if not sqlite3.settings then error("Run sqlite3.setup first") end - links { "sqlite3" } sqlite3.includes() + sqlite3.links() +end + +function sqlite3.links() + links { "sqlite3" } end function sqlite3.includes() @@ -34,8 +38,8 @@ function sqlite3.project() files { - path.join(sqlite3.settings.source, "*.c"), - path.join(sqlite3.settings.source, "*.h"), + path.join(sqlite3.settings.source, "sqlite3*.c"), + path.join(sqlite3.settings.source, "sqlite3*.h"), } -- not our code, ignore POSIX usage warnings for now diff --git a/premake5.lua b/premake5.lua index 30942cab..db2bd73b 100644 --- a/premake5.lua +++ b/premake5.lua @@ -369,6 +369,7 @@ workspace "iw4x" mongoose.project() pdcurses.project() protobuf.project() + sqlite3.project() winksignals.project() zlib.project() From 481a9483ed3a2c7957b9ccfdfda0af3e6f73c3d7 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 23:41:01 +0200 Subject: [PATCH 11/81] Premake: Fix exported include paths for BitMRC. --- premake/bitmrc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index 3608710a..2bd48484 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -11,8 +11,8 @@ end function bitmrc.import() if not bitmrc.settings then error("Run bitmrc.setup first") end - sqlite3.import() - libcryptopp.import() + sqlite3.links() + libcryptopp.links() bitmrc.links() bitmrc.includes() end From addb746a59cab287c72cd37782df88cc23da45a3 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Fri, 26 Aug 2016 23:41:57 +0200 Subject: [PATCH 12/81] Update BitMRC fork and set _CRT_SECURE_NO_WARNINGS for 3rd party includes. --- deps/bitmrc | 2 +- src/STDInclude.hpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/bitmrc b/deps/bitmrc index 3b2766db..adb44b1b 160000 --- a/deps/bitmrc +++ b/deps/bitmrc @@ -1 +1 @@ -Subproject commit 3b2766db750b7a5a5e499ffa72e82c2d86a357f0 +Subproject commit adb44b1b2418b5e185e35ae2cb2c5d5a00746573 diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 98bbbfc3..ede6eb31 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -46,6 +46,7 @@ #pragma warning(disable: 4100) #pragma warning(disable: 4389) #pragma warning(disable: 4702) +#pragma warning(disable: 4996) // _CRT_SECURE_NO_WARNINGS #pragma warning(disable: 6001) #pragma warning(disable: 6011) #pragma warning(disable: 6031) From 47568510482f6e10b2464b37b5c69117b9d2f09e Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 06:51:00 +0200 Subject: [PATCH 13/81] Add implementation of BitMessage in form of bm_* commands. --- src/Components/Loader.cpp | 3 + src/Components/Loader.hpp | 1 + src/Components/Modules/BitMessage.cpp | 261 ++++++++++++++++++++++++++ src/Components/Modules/BitMessage.hpp | 56 ++++++ 4 files changed, 321 insertions(+) create mode 100644 src/Components/Modules/BitMessage.cpp create mode 100644 src/Components/Modules/BitMessage.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index e6284704..4c02a459 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -16,6 +16,9 @@ namespace Components Loader::Register(new Maps()); Loader::Register(new News()); Loader::Register(new Node()); +#ifndef DISABLE_BITMESSAGE + Loader::Register(new BitMessage()); +#endif Loader::Register(new RCon()); Loader::Register(new Menus()); Loader::Register(new Toast()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 4681166e..5a18b299 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -49,6 +49,7 @@ namespace Components #include "Modules\Network.hpp" #include "Modules\Theatre.hpp" #include "Modules\Node.hpp" +#include "Modules\BitMessage.hpp" #include "Modules\RCon.hpp" #include "Modules\Party.hpp" // Destroys the order, but requires network classes :D #include "Modules\Download.hpp" diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp new file mode 100644 index 00000000..69fe6f21 --- /dev/null +++ b/src/Components/Modules/BitMessage.cpp @@ -0,0 +1,261 @@ +#include "STDInclude.hpp" + +#ifndef DISABLE_BITMESSAGE + +#include + +using namespace Utils; + +namespace Components +{ + BitMessage* BitMessage::Singleton = nullptr; + + BitMessage::BitMessage() + { + if (Singleton != nullptr) + { + throw new std::runtime_error("Only 1 BitMessage instance allowed at the same time."); + } + Singleton = this; + + Logger::Print("Initializing BitMessage...\n"); + this->LoadObjectsAndKeys(); + this->LoadNodes(); + + if (this->BMClient->PrivAddresses.empty()) + { + if (!this->InitAddr()) + { + // Generate a random address ready to use + throw std::runtime_error("Failed to prepare source address for exception handling"); + } + this->SaveObjectsAndKeys(); + } + + this->BMClient->start(); + + Command::Add("bm_sendb", [](Command::Params) { + ustring msg; + msg.appendVarString("testing"); + Singleton->BMClient->sendBroadcast(msg, Singleton->BMClient->PrivAddresses[0]); + }); + Command::Add("bm_check_messages", [](Command::Params) { + while (Singleton->BMClient->new_messages.size() > 0) + { + auto msg = Singleton->BMClient->new_messages.pop(); + Logger::Print("New message:\nFrom: %s\nTo: %s\nMessage:\n%s\n", msg.from.c_str(), msg.to.c_str(), msg.info.c_str()); + } + }); + Command::Add("bm_check_connections", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_nodes); + + for (auto& node : Singleton->BMClient->Nodes) + { + switch (node->state) { + case 0: // Not connected + Logger::Print("%s: Disconnected\n", node->Ip.c_str()); + break; + case 1: // Connecting + Logger::Print("%s: Connecting\n", node->Ip.c_str()); + break; + case 2: // Connected + Logger::Print("%s: Connected\n", node->Ip.c_str()); + break; + case 3: // Reconnecting + Logger::Print("%s: Reconnecting\n", node->Ip.c_str()); + break; + } + } + + mlock.unlock(); + }); + Command::Add("bm_check_privatekey", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_priv); + + if (Singleton->BMClient->PrivAddresses.empty()) { + Logger::Print("No private key\n"); + } + else + for (auto& addr : Singleton->BMClient->PrivAddresses) + { + Logger::Print("%s\n", addr.getAddress().c_str()); + } + + mlock.unlock(); + }); + Command::Add("bm_check_publickey", [](Command::Params) { + std::shared_lock mlock(Singleton->BMClient->mutex_pub); + + if (Singleton->BMClient->PubAddresses.empty()) { + Logger::Print("No public key\n"); + } + else + for (auto& addr : Singleton->BMClient->PubAddresses) + { + Logger::Print("%s\n", addr.getAddress().c_str()); + } + + mlock.unlock(); + }); + Command::Add("bm_save", [](Command::Params) { + Singleton->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); + }); + Command::Add("bm_save_nodes", [](Command::Params) { + Singleton->SaveNodes(); + }); + Command::Add("bm_address_public", [](Command::Params params) { + if (params.Length() < 1) return; + + ustring addre; + addre.fromString(params[0]); + PubAddr address; + if (address.loadAddr(addre)) + { + Logger::Print("Asking public key!\n"); + Singleton->BMClient->getPubKey(address); + Logger::Print("Asked! check publickey for news on that address!\n"); + } + else + { + Logger::Print("Address not correct!\n"); + } + }); + Command::Add("bm_address_broadcast", [](Command::Params params) { + if (params.Length() < 1) return; + + ustring addre; + addre.fromString(params[0]); + PubAddr address; + if (address.loadAddr(addre)) + { + Logger::Print("Adding subscription!\n"); + Singleton->BMClient->addSubscription(address); + } + else + { + Logger::Print("Address not correct!\n"); + } + }); + } + + bool BitMessage::InitAddr() + { + Logger::Print("Generating BM address...\n"); + Addr myAddress; + if (!myAddress.generateRandom()) + { + return false; + } + BMClient->addAddr(myAddress); + return true; + } + + void BitMessage::LoadObjectsAndKeys() + { + Logger::Print("Loading BM objects and keys...\n"); + this->BMClient->load(BITMESSAGE_OBJECT_STORAGE_FILENAME); + } + + void BitMessage::SaveObjectsAndKeys() + { + Logger::Print("Saving BM objects and keys...\n"); + this->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); + } + + void BitMessage::SaveNodes() + { + Logger::Print("Saving BM nodes...\n"); + Proto::Node::List list; + std::vector nodeList; // keep track of dupes + + std::shared_lock mlock(Singleton->BMClient->mutex_nodes); + + for (auto& node : Singleton->BMClient->Nodes) + { + std::string nodeStr = String::VA("%s:%s", node->Ip.c_str(), node->Port.c_str()); + switch (node->state) { + case 0: // Not connected + break; + case 1: // Connecting + break; + case 2: // Connected + if (std::find(nodeList.begin(), nodeList.end(), nodeStr) == nodeList.end()) + { + // This allows us to keep track of duplicates + nodeList.push_back(nodeStr); + + DWORD ip = 0; + unsigned short port = 0; + sscanf_s(nodeStr.c_str(), "%d.%d.%d.%d:%hu", &ip, &ip + 1, &ip + 2, &ip + 3, &port); + + Network::Address address; + address.SetIP(ip); + address.SetPort(port); + + address.Serialize(list.add_address()); + + Logger::Print("Saved node: %s\n", address.GetCString()); + } + break; + case 3: // Reconnecting + break; + } + } + + mlock.unlock(); + + if (list.address_size() <= 0) + return; + + // Create directory if it doesn't exist yet + auto dirName = const_cast(BITMESSAGE_NODE_STORAGE_FILENAME.c_str()); + PathRemoveFileSpecA(dirName); + CreateDirectoryA(dirName, NULL); + + // Now write the actual file + Utils::IO::WriteFile(BITMESSAGE_NODE_STORAGE_FILENAME, list.SerializeAsString()); + } + + void BitMessage::LoadNodes() + { + Logger::Print("Loading BM nodes...\n"); + // Load nodes stored in file + Proto::Node::List list; + std::string nodes = IO::ReadFile(BITMESSAGE_NODE_STORAGE_FILENAME); + if (!nodes.empty() && list.ParseFromString(nodes)) + { + for (int i = 0; i < list.address_size(); ++i) + { + Network::Address address = list.address(i); + + this->BMClient->connectNode(new NodeConnection( + String::VA("%d.%d.%d.%d", address.GetIP().bytes[0], address.GetIP().bytes[1], address.GetIP().bytes[2], address.GetIP().bytes[3]), // urgh. + String::VA("%d", address.GetPort()), this->BMClient)); + } + } + + // Load default nodes if not connected to yet + for (auto addr : bitmessageKnownNodes) { + auto portStr = std::string(String::VA("%d", addr.second)); + if (!this->HasNode(addr.first, portStr)) + { + this->BMClient->connectNode(new NodeConnection(addr.first, portStr, this->BMClient)); + } + } + } + + bool BitMessage::HasNode(std::string ip, std::string port) + { + for (auto& node : this->BMClient->Nodes) + { + if (node->Ip == ip && node->Port == port) + { + return true; + } + } + + return false; + } +} + +#endif \ No newline at end of file diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp new file mode 100644 index 00000000..8eb67952 --- /dev/null +++ b/src/Components/Modules/BitMessage.hpp @@ -0,0 +1,56 @@ +#pragma once + +#ifndef DISABLE_BITMESSAGE + +#define BITMESSAGE_NODE_STORAGE_FILENAME std::string("players/bmnodes.dat") +#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("save") + +static const std::map bitmessageKnownNodes = { + // https://github.com/Bitmessage/PyBitmessage/blob/4622d952e47a7dbb3a90aa79f4d20163aa14b041/src/defaultKnownNodes.py#L15-L23 + + // Stream 1 + //{ "2604:2000:1380:9f:82e:148b:2746:d0c7", 8080 }, + { "5.45.99.75", 8444 }, + { "75.167.159.54", 8444 }, + { "95.165.168.168", 8444 }, + { "85.180.139.241", 8444 }, + { "158.222.211.81", 8080 }, + { "178.62.12.187", 8448 }, + { "24.188.198.204", 8111 }, + { "109.147.204.113", 1195 }, + { "178.11.46.221", 8444 }, + + // Stream 2 has none yet + + // Stream 3 has none yet +}; + +namespace Components +{ + class BitMessage : public Component + { + public: + BitMessage(); + +#ifdef DEBUG + const char* GetName() { return "BitMessage"; }; +#endif + + static BitMessage* Singleton; + BitMRC* BMClient = new BitMRC(); + + void SaveNodes(); + bool HasNode(std::string ip, std::string port); + + void SaveObjectsAndKeys(); + + private: + void LoadNodes(); + + void LoadObjectsAndKeys(); + + bool InitAddr(); + }; +} + +#endif \ No newline at end of file From 073e984f69bb79d10ee359eb01e433513e41c926 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 10:16:12 +0200 Subject: [PATCH 14/81] Fix logic mistake with parsing parameters for bm_* commands. --- src/Components/Modules/BitMessage.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 69fe6f21..f28b4bf0 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -34,10 +34,14 @@ namespace Components this->BMClient->start(); - Command::Add("bm_sendb", [](Command::Params) { + Command::Add("bm_sendb", [](Command::Params params) { + if (params.Length() < 2) return; + ustring msg; - msg.appendVarString("testing"); + msg.appendVarString(params.Join(1)); + Logger::Print("Sending broadcast...\n"); Singleton->BMClient->sendBroadcast(msg, Singleton->BMClient->PrivAddresses[0]); + Logger::Print("Broadcast done.\n"); }); Command::Add("bm_check_messages", [](Command::Params) { while (Singleton->BMClient->new_messages.size() > 0) @@ -104,10 +108,10 @@ namespace Components Singleton->SaveNodes(); }); Command::Add("bm_address_public", [](Command::Params params) { - if (params.Length() < 1) return; + if (params.Length() < 2) return; ustring addre; - addre.fromString(params[0]); + addre.fromString(params.Join(1)); PubAddr address; if (address.loadAddr(addre)) { @@ -121,10 +125,10 @@ namespace Components } }); Command::Add("bm_address_broadcast", [](Command::Params params) { - if (params.Length() < 1) return; + if (params.Length() < 2) return; ustring addre; - addre.fromString(params[0]); + addre.fromString(params.Join(1)); PubAddr address; if (address.loadAddr(addre)) { From 738f9ee941deb3f7c0c9f266896183b94c07f41a Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 11:24:26 +0200 Subject: [PATCH 15/81] Add "bm_send ". --- src/Components/Modules/BitMessage.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index f28b4bf0..50954878 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -34,6 +34,26 @@ namespace Components this->BMClient->start(); + Command::Add("bm_send", [](Command::Params params) { + if (params.Length() < 3) return; + + ustring pubAddrString; + pubAddrString.fromString(params[1]); + PubAddr pubAddr; + if (pubAddr.loadAddr(pubAddrString)) + { + ustring msg; + msg.fromString(params.Join(2)); + + Logger::Print("Sending message (this may take a while)...\n"); + Singleton->BMClient->sendMessage(msg, pubAddr, Singleton->BMClient->PrivAddresses[0]); + Logger::Print("Message sent.\n"); + } + else + { + Logger::Print("Address not correct!\n"); + } + }); Command::Add("bm_sendb", [](Command::Params params) { if (params.Length() < 2) return; From 6696a57b180af2c8be9f58f5c1293582cf97bf4c Mon Sep 17 00:00:00 2001 From: /dev/root Date: Sat, 27 Aug 2016 18:18:03 +0200 Subject: [PATCH 16/81] added converttobase64 function added UploadMinidump2BM --- src/Components/Modules/Exception.cpp | 54 +++++++++++++++++++++++++++- src/Components/Modules/Exception.hpp | 5 ++- src/Utils/String.cpp | 15 ++++++++ src/Utils/String.hpp | 3 ++ 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 97fd4aa2..8a22166c 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -1,6 +1,5 @@ #include "STDInclude.hpp" - // Stuff causes warnings #pragma warning(push) #pragma warning(disable: 4091) @@ -10,6 +9,7 @@ namespace Components { + // Fileupload to Webhost bool Exception::UploadMinidump(std::string filename) { Utils::WebIO webio("Firefucks", UPLOAD_URL); @@ -47,7 +47,58 @@ namespace Components } } } + return false; + } + + // Fileupload to Bitmessage + bool Exception::UploadMinidump2BM(std::string filename) + { + if (Components::BitMessage::Singleton == nullptr) + { + //throw new std::runtime_error("BitMessage was already stopped."); + Logger::Print("Bitmessage was already stopped.\n"); + } + else + { + BitMessage* Singleton; + Singleton = Components::BitMessage::Singleton; + if (Utils::IO::FileExists(filename)) + { + // TODO: Validate filesize of minidump + // TODO: Convert to base64 + // TODO: Split if filesize > xxxkB + std::string buffer = Utils::String::encodeBase64(Utils::IO::ReadFile(filename)); + + ustring pubAddrString; + pubAddrString.fromString(BITMESSAGE_UPLOAD_IDENTITY); + PubAddr pubAddr; + if (pubAddr.loadAddr(pubAddrString)) + { + int g; + ustring msg; + + Logger::Print("Uploading Minidump (this may take a while)...\n"); + + for (size_t i = 0; i < buffer.size(); i=i+BITMESSAGE_SIZE_LIMIT) + { + if (buffer.size() > i + BITMESSAGE_SIZE_LIMIT) + g = buffer.size(); + else + g = i + BITMESSAGE_SIZE_LIMIT; + std::string substring = buffer.substr(i, g); + msg.fromString(substring); + Singleton->BMClient->sendMessage(msg, pubAddr, Singleton->BMClient->PrivAddresses[0]); + } + + Logger::Print("Minidump uploaded.\n"); + } + else + { + Logger::Print("Address not correct!\n"); + } + } + } return false; } @@ -71,6 +122,7 @@ namespace Components } //Exception::UploadMinidump(filename); + Exception::UploadMinidump2BM(filename); if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index 8655432f..d82df993 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -1,4 +1,6 @@ #define UPLOAD_URL "https://reich.io/upload.php" +#define BITMESSAGE_UPLOAD_IDENTITY "BM-NBhqCHraxGyUT38cfhRQYWx29gJ7QePa" +#define BITMESSAGE_SIZE_LIMIT 25600 namespace Components { @@ -8,7 +10,7 @@ namespace Components Exception(); #ifdef DEBUG - const char* GetName() { return "Exception"; }; + const char* GetName() { return "Exception"; }; #endif private: @@ -16,5 +18,6 @@ namespace Components static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); static bool UploadMinidump(std::string filename); + static bool UploadMinidump2BM(std::string filename); }; } diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 44157047..cb1ab6af 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -115,5 +115,20 @@ namespace Utils return fmt::sprintf("%02d:%02d:%02d", hoursTotal, minutes, seconds); } + + // Encodes a given string in Base64 + std::string encodeBase64(const char* input, const unsigned long inputSize) { + unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16); + unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory + base64_encode((unsigned char*)input, inputSize, outbuf, &outlen); + std::string ret((char*)outbuf, outlen); + delete[] outbuf; + return ret; + } + + // Encodes a given string in Base64 + std::string encodeBase64(const std::string& input) { + return encodeBase64(input.c_str(), input.size()); + } } } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 0a877ebd..e18b4f14 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -39,5 +39,8 @@ namespace Utils std::string DumpHex(std::string data, std::string separator = " "); std::string XOR(std::string str, char value); + + std::string encodeBase64(const char* input, const unsigned long inputSize); + std::string encodeBase64(const std::string& input); } } From bd7faf2b32485a285c82fdd541f1bc4162c256ad Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 19:22:40 +0200 Subject: [PATCH 17/81] Implement "debug_minidump" for debugging of minidump upload and generation. --- src/Components/Modules/Exception.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 8a22166c..624c5564 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -193,5 +193,19 @@ namespace Components Command::Execute(command, false); }); + Command::Add("debug_minidump", [](Command::Params) + { + CONTEXT ectx; + + EXCEPTION_RECORD erec; + erec.ExceptionAddress = 0x0; + erec.ExceptionCode = EXCEPTION_BREAKPOINT; + + EXCEPTION_POINTERS eptr; + eptr.ContextRecord = &ectx; + eptr.ExceptionRecord = &erec; + + Exception::ExceptionFilter(&eptr); + }); } } From a82aab26faba4091b3f8cab7ad0542c8fb391216 Mon Sep 17 00:00:00 2001 From: /dev/root Date: Sat, 27 Aug 2016 23:46:24 +0200 Subject: [PATCH 18/81] updated BITMESSAGE_SIZE_LIMIT added EncodeBase64/DecodeBase64 to Utils::String --- src/Components/Modules/Exception.hpp | 2 +- src/Utils/String.cpp | 16 +++++++++++++--- src/Utils/String.hpp | 5 +++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index d82df993..0a2a8210 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -1,6 +1,6 @@ #define UPLOAD_URL "https://reich.io/upload.php" #define BITMESSAGE_UPLOAD_IDENTITY "BM-NBhqCHraxGyUT38cfhRQYWx29gJ7QePa" -#define BITMESSAGE_SIZE_LIMIT 25600 +#define BITMESSAGE_SIZE_LIMIT 230000 namespace Components { diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index cb1ab6af..504c21ec 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -117,7 +117,7 @@ namespace Utils } // Encodes a given string in Base64 - std::string encodeBase64(const char* input, const unsigned long inputSize) { + std::string EncodeBase64(const char* input, const unsigned long inputSize) { unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16); unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory base64_encode((unsigned char*)input, inputSize, outbuf, &outlen); @@ -127,8 +127,18 @@ namespace Utils } // Encodes a given string in Base64 - std::string encodeBase64(const std::string& input) { - return encodeBase64(input.c_str(), input.size()); + std::string EncodeBase64(const std::string& input) { + return EncodeBase64(input.c_str(), input.size()); + } + + // Decodes a given string from Base64 + std::string DecodeBase64(const std::string& input) { + unsigned char* out = new unsigned char[input.size()]; + unsigned long outlen = input.size(); + base64_decode((unsigned char*)input.c_str(), input.size(), out, &outlen); + std::string ret((char*)out, outlen); + delete[] out; + return ret; } } } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index e18b4f14..3e2c0ea1 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -40,7 +40,8 @@ namespace Utils std::string XOR(std::string str, char value); - std::string encodeBase64(const char* input, const unsigned long inputSize); - std::string encodeBase64(const std::string& input); + std::string EncodeBase64(const char* input, const unsigned long inputSize); + std::string EncodeBase64(const std::string& input); + std::string DecodeBase64(const std::string& input); } } From fddfc56ae194615b9192c099043428b4909c3da6 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 21:03:33 +0200 Subject: [PATCH 19/81] Update BitMRC fork. --- deps/bitmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/bitmrc b/deps/bitmrc index adb44b1b..52aa771b 160000 --- a/deps/bitmrc +++ b/deps/bitmrc @@ -1 +1 @@ -Subproject commit adb44b1b2418b5e185e35ae2cb2c5d5a00746573 +Subproject commit 52aa771b9274056eb1e30b5c7fbfd1669c053265 From d3d8884f931700483b1a9852fb8898252883c8ed Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 21:18:51 +0200 Subject: [PATCH 20/81] Generate a more complete context in debug_minidump. --- src/Components/Modules/Exception.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 624c5564..e4f6bd6b 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -193,19 +193,34 @@ namespace Components Command::Execute(command, false); }); +#pragma warning(push) +#pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization Command::Add("debug_minidump", [](Command::Params) { CONTEXT ectx; - + ZeroMemory(&ectx, sizeof(CONTEXT)); + ectx.ContextFlags = CONTEXT_CONTROL; + + __asm + { + Label: + mov[ectx.Ebp], ebp; + mov[ectx.Esp], esp; + mov eax, [Label]; + mov[ectx.Eip], eax; + } + EXCEPTION_RECORD erec; - erec.ExceptionAddress = 0x0; + ZeroMemory(&erec, sizeof(EXCEPTION_RECORD)); + erec.ExceptionAddress = _ReturnAddress(); erec.ExceptionCode = EXCEPTION_BREAKPOINT; - EXCEPTION_POINTERS eptr; - eptr.ContextRecord = &ectx; - eptr.ExceptionRecord = &erec; + auto eptr = new EXCEPTION_POINTERS(); + eptr->ContextRecord = &ectx; + eptr->ExceptionRecord = &erec; - Exception::ExceptionFilter(&eptr); + Exception::ExceptionFilter(eptr); }); +#pragma warning(pop) } } From 624173f7cfd78ea953dc99bb8529db2cfe833ebf Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sat, 27 Aug 2016 21:20:08 +0200 Subject: [PATCH 21/81] Update load/save code, set TTL to 1 hour and remove node storage. --- src/Components/Modules/BitMessage.cpp | 117 +------------------------- src/Components/Modules/BitMessage.hpp | 15 +--- 2 files changed, 7 insertions(+), 125 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 50954878..c4753f73 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -19,8 +19,9 @@ namespace Components Singleton = this; Logger::Print("Initializing BitMessage...\n"); - this->LoadObjectsAndKeys(); - this->LoadNodes(); + this->BMClient = new BitMRC(BITMESSAGE_OBJECT_STORAGE_FILENAME, BITMESSAGE_KEYS_FILENAME); + this->BMClient->init(); + this->BMClient->defaultTTL = 1 * 60 * 60; // 1 hour if (this->BMClient->PrivAddresses.empty()) { @@ -29,7 +30,7 @@ namespace Components // Generate a random address ready to use throw std::runtime_error("Failed to prepare source address for exception handling"); } - this->SaveObjectsAndKeys(); + this->BMClient->save(); } this->BMClient->start(); @@ -124,9 +125,6 @@ namespace Components Command::Add("bm_save", [](Command::Params) { Singleton->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); }); - Command::Add("bm_save_nodes", [](Command::Params) { - Singleton->SaveNodes(); - }); Command::Add("bm_address_public", [](Command::Params params) { if (params.Length() < 2) return; @@ -173,113 +171,6 @@ namespace Components BMClient->addAddr(myAddress); return true; } - - void BitMessage::LoadObjectsAndKeys() - { - Logger::Print("Loading BM objects and keys...\n"); - this->BMClient->load(BITMESSAGE_OBJECT_STORAGE_FILENAME); - } - - void BitMessage::SaveObjectsAndKeys() - { - Logger::Print("Saving BM objects and keys...\n"); - this->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); - } - - void BitMessage::SaveNodes() - { - Logger::Print("Saving BM nodes...\n"); - Proto::Node::List list; - std::vector nodeList; // keep track of dupes - - std::shared_lock mlock(Singleton->BMClient->mutex_nodes); - - for (auto& node : Singleton->BMClient->Nodes) - { - std::string nodeStr = String::VA("%s:%s", node->Ip.c_str(), node->Port.c_str()); - switch (node->state) { - case 0: // Not connected - break; - case 1: // Connecting - break; - case 2: // Connected - if (std::find(nodeList.begin(), nodeList.end(), nodeStr) == nodeList.end()) - { - // This allows us to keep track of duplicates - nodeList.push_back(nodeStr); - - DWORD ip = 0; - unsigned short port = 0; - sscanf_s(nodeStr.c_str(), "%d.%d.%d.%d:%hu", &ip, &ip + 1, &ip + 2, &ip + 3, &port); - - Network::Address address; - address.SetIP(ip); - address.SetPort(port); - - address.Serialize(list.add_address()); - - Logger::Print("Saved node: %s\n", address.GetCString()); - } - break; - case 3: // Reconnecting - break; - } - } - - mlock.unlock(); - - if (list.address_size() <= 0) - return; - - // Create directory if it doesn't exist yet - auto dirName = const_cast(BITMESSAGE_NODE_STORAGE_FILENAME.c_str()); - PathRemoveFileSpecA(dirName); - CreateDirectoryA(dirName, NULL); - - // Now write the actual file - Utils::IO::WriteFile(BITMESSAGE_NODE_STORAGE_FILENAME, list.SerializeAsString()); - } - - void BitMessage::LoadNodes() - { - Logger::Print("Loading BM nodes...\n"); - // Load nodes stored in file - Proto::Node::List list; - std::string nodes = IO::ReadFile(BITMESSAGE_NODE_STORAGE_FILENAME); - if (!nodes.empty() && list.ParseFromString(nodes)) - { - for (int i = 0; i < list.address_size(); ++i) - { - Network::Address address = list.address(i); - - this->BMClient->connectNode(new NodeConnection( - String::VA("%d.%d.%d.%d", address.GetIP().bytes[0], address.GetIP().bytes[1], address.GetIP().bytes[2], address.GetIP().bytes[3]), // urgh. - String::VA("%d", address.GetPort()), this->BMClient)); - } - } - - // Load default nodes if not connected to yet - for (auto addr : bitmessageKnownNodes) { - auto portStr = std::string(String::VA("%d", addr.second)); - if (!this->HasNode(addr.first, portStr)) - { - this->BMClient->connectNode(new NodeConnection(addr.first, portStr, this->BMClient)); - } - } - } - - bool BitMessage::HasNode(std::string ip, std::string port) - { - for (auto& node : this->BMClient->Nodes) - { - if (node->Ip == ip && node->Port == port) - { - return true; - } - } - - return false; - } } #endif \ No newline at end of file diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index 8eb67952..7f4c49cd 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -2,8 +2,8 @@ #ifndef DISABLE_BITMESSAGE -#define BITMESSAGE_NODE_STORAGE_FILENAME std::string("players/bmnodes.dat") -#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("save") +#define BITMESSAGE_KEYS_FILENAME std::string("players/bmkey.dat") +#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("players/bmstore.dat") static const std::map bitmessageKnownNodes = { // https://github.com/Bitmessage/PyBitmessage/blob/4622d952e47a7dbb3a90aa79f4d20163aa14b041/src/defaultKnownNodes.py#L15-L23 @@ -37,18 +37,9 @@ namespace Components #endif static BitMessage* Singleton; - BitMRC* BMClient = new BitMRC(); - - void SaveNodes(); - bool HasNode(std::string ip, std::string port); - - void SaveObjectsAndKeys(); + BitMRC* BMClient; private: - void LoadNodes(); - - void LoadObjectsAndKeys(); - bool InitAddr(); }; } From 1d5927f093b0b7c4e15870fb244deed9398faf95 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sun, 28 Aug 2016 16:07:28 +0200 Subject: [PATCH 22/81] debug_minidump now uses code from VC++ 8.0 CRT to generate fake exception info. --- src/Components/Modules/Exception.cpp | 72 +++++++++++++++++++++------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index e4f6bd6b..e033fc3b 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -197,27 +197,65 @@ namespace Components #pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization Command::Add("debug_minidump", [](Command::Params) { - CONTEXT ectx; - ZeroMemory(&ectx, sizeof(CONTEXT)); - ectx.ContextFlags = CONTEXT_CONTROL; + // The following code was taken from VC++ 8.0 CRT (invarg.c: line 104) - __asm - { - Label: - mov[ectx.Ebp], ebp; - mov[ectx.Esp], esp; - mov eax, [Label]; - mov[ectx.Eip], eax; + EXCEPTION_RECORD ExceptionRecord; + CONTEXT ContextRecord; + memset(&ContextRecord, 0, sizeof(CONTEXT)); + +#ifdef _X86_ + + __asm { + mov dword ptr[ContextRecord.Eax], eax + mov dword ptr[ContextRecord.Ecx], ecx + mov dword ptr[ContextRecord.Edx], edx + mov dword ptr[ContextRecord.Ebx], ebx + mov dword ptr[ContextRecord.Esi], esi + mov dword ptr[ContextRecord.Edi], edi + mov word ptr[ContextRecord.SegSs], ss + mov word ptr[ContextRecord.SegCs], cs + mov word ptr[ContextRecord.SegDs], ds + mov word ptr[ContextRecord.SegEs], es + mov word ptr[ContextRecord.SegFs], fs + mov word ptr[ContextRecord.SegGs], gs + pushfd + pop[ContextRecord.EFlags] } - EXCEPTION_RECORD erec; - ZeroMemory(&erec, sizeof(EXCEPTION_RECORD)); - erec.ExceptionAddress = _ReturnAddress(); - erec.ExceptionCode = EXCEPTION_BREAKPOINT; + ContextRecord.ContextFlags = CONTEXT_CONTROL; +#pragma warning(push) +#pragma warning(disable:4311) + ContextRecord.Eip = (ULONG)_ReturnAddress(); + ContextRecord.Esp = (ULONG)_AddressOfReturnAddress(); +#pragma warning(pop) + ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress() - 1); - auto eptr = new EXCEPTION_POINTERS(); - eptr->ContextRecord = &ectx; - eptr->ExceptionRecord = &erec; + +#elif defined (_IA64_) || defined (_AMD64_) + + /* Need to fill up the Context in IA64 and AMD64. */ + RtlCaptureContext(&ContextRecord); + +#else /* defined (_IA64_) || defined (_AMD64_) */ + + ZeroMemory(&ContextRecord, sizeof(ContextRecord)); + +#endif /* defined (_IA64_) || defined (_AMD64_) */ + + ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD)); + + ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT; + ExceptionRecord.ExceptionAddress = _ReturnAddress(); + + + EXCEPTION_RECORD* pExceptionRecord = new EXCEPTION_RECORD; + memcpy(pExceptionRecord, &ExceptionRecord, sizeof(EXCEPTION_RECORD)); + CONTEXT* pContextRecord = new CONTEXT; + memcpy(pContextRecord, &ContextRecord, sizeof(CONTEXT)); + + auto eptr = new EXCEPTION_POINTERS; + eptr->ExceptionRecord = pExceptionRecord; + eptr->ContextRecord = pContextRecord; Exception::ExceptionFilter(eptr); }); From ebba2819d60034d9d3340518f774fc885c14f927 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sun, 28 Aug 2016 19:38:16 +0200 Subject: [PATCH 23/81] Commit local workspace. - Split minidump (upload) and exception handling code - Smaller minidumps for faster uploads - Several new build flags (accessible from premake5 with --params) - BitMessage abstractions - Some other things I can't remember. --- premake5.lua | 42 ++- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 1 + src/Components/Modules/BitMessage.cpp | 95 +++++- src/Components/Modules/BitMessage.hpp | 29 +- src/Components/Modules/Exception.cpp | 161 +++------- src/Components/Modules/Exception.hpp | 8 +- src/Components/Modules/MinidumpUpload.cpp | 366 ++++++++++++++++++++++ src/Components/Modules/MinidumpUpload.hpp | 77 +++++ src/STDInclude.hpp | 4 +- src/Utils/String.cpp | 18 +- src/Utils/String.hpp | 3 +- src/Utils/Utils.cpp | 13 + src/Utils/Utils.hpp | 1 + src/Utils/WebIO.cpp | 17 +- src/Utils/WebIO.hpp | 4 +- 16 files changed, 665 insertions(+), 175 deletions(-) create mode 100644 src/Components/Modules/MinidumpUpload.cpp create mode 100644 src/Components/Modules/MinidumpUpload.hpp diff --git a/premake5.lua b/premake5.lua index db2bd73b..8fc6dc1b 100644 --- a/premake5.lua +++ b/premake5.lua @@ -43,6 +43,21 @@ newoption { description = "Always compile unit tests." } +newoption { + trigger = "force-exception-handler", + description = "Install custom unhandled exception handler even for Debug builds." +} + +newoption { + trigger = "force-minidump-upload", + description = "Upload minidumps even for Debug builds." +} + +newoption { + trigger = "disable-bitmessage", + description = "Disable use of BitMessage completely." +} + newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", @@ -242,6 +257,9 @@ workspace "iw4x" resincludedirs { "$(ProjectDir)src" -- fix for VS IDE } + removefiles { + "./src/Components/Modules/Tor.*", + } -- Debug flags if _OPTIONS["ac-debug-detections"] then @@ -253,6 +271,18 @@ workspace "iw4x" if _OPTIONS["force-unit-tests"] then defines { "FORCE_UNIT_TESTS" } end + if _OPTIONS["force-minidump-upload"] then + defines { "FORCE_MINIDUMP_UPLOAD" } + end + if _OPTIONS["force-exception-handler"] then + defines { "FORCE_EXCEPTION_HANDLER" } + end + if _OPTIONS["disable-bitmessage"] then + defines { "DISABLE_BITMESSAGE" } + removefiles { + "./src/Components/Modules/BitMessage.*", + } + end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives @@ -260,7 +290,9 @@ workspace "iw4x" buildoptions { "/Zm200" } -- Dependency libraries - bitmrc.import() + if not _OPTIONS["disable-bitmessage"] then + bitmrc.import() + end fmt.import() json11.import() libtomcrypt.import() @@ -360,16 +392,18 @@ workspace "iw4x" } group "External dependencies" - bitmrc.project() + if not _OPTIONS["disable-bitmessage"] then + bitmrc.project() + libcryptopp.project() + sqlite3.project() + end fmt.project() json11.project() - libcryptopp.project() libtomcrypt.project() libtommath.project() mongoose.project() pdcurses.project() protobuf.project() - sqlite3.project() winksignals.project() zlib.project() diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 4c02a459..b62ea828 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -45,6 +45,7 @@ namespace Components Loader::Register(new Dedicated()); Loader::Register(new Discovery()); Loader::Register(new Exception()); + Loader::Register(new MinidumpUpload()); Loader::Register(new FastFiles()); Loader::Register(new Materials()); Loader::Register(new FileSystem()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 5a18b299..41813e98 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -62,6 +62,7 @@ namespace Components #include "Modules\Dedicated.hpp" #include "Modules\Discovery.hpp" #include "Modules\Exception.hpp" +#include "Modules\MinidumpUpload.hpp" #include "Modules\FastFiles.hpp" #include "Modules\Materials.hpp" #include "Modules\Singleton.hpp" diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index c4753f73..047d2851 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -8,14 +8,13 @@ using namespace Utils; namespace Components { - BitMessage* BitMessage::Singleton = nullptr; + BitMessage* BitMessage::Singleton = NULL; BitMessage::BitMessage() { - if (Singleton != nullptr) - { - throw new std::runtime_error("Only 1 BitMessage instance allowed at the same time."); - } + if (Singleton != NULL) + throw new std::runtime_error("Only one instance of BitMessage allowed at the same time."); + Singleton = this; Logger::Print("Initializing BitMessage...\n"); @@ -160,6 +159,92 @@ namespace Components }); } + BitMessage::~BitMessage() + { + Singleton = NULL; + } + + void BitMessage::SetDefaultTTL(time_t ttl) + { + this->BMClient->defaultTTL = ttl; + } + + bool BitMessage::RequestPublicKey(std::string targetAddress) + { + // Convert to ustring + ustring targetAddressU; + targetAddressU.fromString(targetAddress); + + // Convert to PubAddr + PubAddr pubAddr; + if (!pubAddr.loadAddr(targetAddressU)) + { + return false; + } + + // Request public key! + this->BMClient->getPubKey(pubAddr); + return true; + } + + bool BitMessage::Subscribe(std::string targetAddress) + { + // Convert to ustring + ustring targetAddressU; + targetAddressU.fromString(targetAddress); + + // Convert to PubAddr + PubAddr pubAddr; + if (!pubAddr.loadAddr(targetAddressU)) + { + return false; + } + + // Subscribe! + this->BMClient->addSubscription(pubAddr); + return true; + } + + bool BitMessage::SendMsg(std::string targetAddress, std::string message, time_t ttl) + { + // Convert target address to ustring + ustring targetAddressU; + targetAddressU.fromString(targetAddress); + + // Convert target address to PubAddr + PubAddr pubAddr; + if (!pubAddr.loadAddr(targetAddressU)) + { + return false; + } + + // Convert message to ustring + ustring messageU; + messageU.fromString(message); + + // Send the message + // TODO - Set mutex on priv when accessing first private address + if (ttl > 0) + this->BMClient->sendMessage(messageU, pubAddr, this->BMClient->PrivAddresses[0], ttl); + else + this->BMClient->sendMessage(messageU, pubAddr, this->BMClient->PrivAddresses[0]); + return true; + } + + bool BitMessage::SendBroadcast(std::string message, time_t ttl) + { + // Convert message to ustring + ustring messageU; + messageU.fromString(message); + + // TODO - Set mutex on priv when accessing first private address + if (ttl > 0) + this->BMClient->sendBroadcast(messageU, this->BMClient->PrivAddresses[0], ttl); + else + this->BMClient->sendBroadcast(messageU, this->BMClient->PrivAddresses[0]); + return true; + } + bool BitMessage::InitAddr() { Logger::Print("Generating BM address...\n"); diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index 7f4c49cd..5c52cd19 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -2,40 +2,27 @@ #ifndef DISABLE_BITMESSAGE -#define BITMESSAGE_KEYS_FILENAME std::string("players/bmkey.dat") +#define BITMESSAGE_KEYS_FILENAME std::string("players/bmkeys.dat") #define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("players/bmstore.dat") -static const std::map bitmessageKnownNodes = { - // https://github.com/Bitmessage/PyBitmessage/blob/4622d952e47a7dbb3a90aa79f4d20163aa14b041/src/defaultKnownNodes.py#L15-L23 - - // Stream 1 - //{ "2604:2000:1380:9f:82e:148b:2746:d0c7", 8080 }, - { "5.45.99.75", 8444 }, - { "75.167.159.54", 8444 }, - { "95.165.168.168", 8444 }, - { "85.180.139.241", 8444 }, - { "158.222.211.81", 8080 }, - { "178.62.12.187", 8448 }, - { "24.188.198.204", 8111 }, - { "109.147.204.113", 1195 }, - { "178.11.46.221", 8444 }, - - // Stream 2 has none yet - - // Stream 3 has none yet -}; - namespace Components { class BitMessage : public Component { public: BitMessage(); + ~BitMessage(); #ifdef DEBUG const char* GetName() { return "BitMessage"; }; #endif + void SetDefaultTTL(time_t ttl); + bool RequestPublicKey(std::string targetAddress); + bool Subscribe(std::string targetAddress); + bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0); + bool SendBroadcast(std::string message, time_t ttl = 0); + static BitMessage* Singleton; BitMRC* BMClient; diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index e033fc3b..81431016 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -9,145 +9,53 @@ namespace Components { - // Fileupload to Webhost - bool Exception::UploadMinidump(std::string filename) - { - Utils::WebIO webio("Firefucks", UPLOAD_URL); - - if (Utils::IO::FileExists(filename)) - { - std::string buffer = Utils::IO::ReadFile(filename); - std::string result = webio.PostFile(buffer); - - std::string errors; - json11::Json object = json11::Json::parse(result, errors); - - if (!object.is_object()) return false; - - json11::Json success = object["success"]; - - if (!success.is_bool() || !success.bool_value()) return false; - - json11::Json files = object["files"]; - - if (!files.is_array()) return false; - - for (auto file : files.array_items()) - { - json11::Json url = file["url"]; - json11::Json hash = file["hash"]; - - if (hash.is_string() && url.is_string()) - { - if (Utils::String::ToLower(Utils::Cryptography::SHA1::Compute(buffer, true)) == Utils::String::ToLower(hash.string_value())) - { - MessageBoxA(0, url.string_value().data(), 0, 0); - return true; - } - } - } - } - return false; - } - - // Fileupload to Bitmessage - bool Exception::UploadMinidump2BM(std::string filename) - { - if (Components::BitMessage::Singleton == nullptr) - { - //throw new std::runtime_error("BitMessage was already stopped."); - Logger::Print("Bitmessage was already stopped.\n"); - } - else - { - BitMessage* Singleton; - Singleton = Components::BitMessage::Singleton; - - if (Utils::IO::FileExists(filename)) - { - // TODO: Validate filesize of minidump - // TODO: Convert to base64 - // TODO: Split if filesize > xxxkB - std::string buffer = Utils::String::encodeBase64(Utils::IO::ReadFile(filename)); - - ustring pubAddrString; - pubAddrString.fromString(BITMESSAGE_UPLOAD_IDENTITY); - PubAddr pubAddr; - if (pubAddr.loadAddr(pubAddrString)) - { - int g; - ustring msg; - - Logger::Print("Uploading Minidump (this may take a while)...\n"); - - for (size_t i = 0; i < buffer.size(); i=i+BITMESSAGE_SIZE_LIMIT) - { - if (buffer.size() > i + BITMESSAGE_SIZE_LIMIT) - g = buffer.size(); - else - g = i + BITMESSAGE_SIZE_LIMIT; - std::string substring = buffer.substr(i, g); - msg.fromString(substring); - Singleton->BMClient->sendMessage(msg, pubAddr, Singleton->BMClient->PrivAddresses[0]); - } - - Logger::Print("Minidump uploaded.\n"); - } - else - { - Logger::Print("Address not correct!\n"); - } - } - } - return false; - } - LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { - char filename[MAX_PATH]; - __time64_t time; - tm ltime; - - _time64(&time); - _localtime64_s(<ime, &time); - strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", <ime); - - HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFile && hFile != INVALID_HANDLE_VALUE) + // Pass on harmless errors + if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_INTEGER_OVERFLOW || + ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_FLOAT_OVERFLOW) { - MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), ExceptionInfo, FALSE }; - MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ex, NULL, NULL); - CloseHandle(hFile); + return EXCEPTION_CONTINUE_EXECUTION; } - //Exception::UploadMinidump(filename); - Exception::UploadMinidump2BM(filename); - - if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + auto minidump = MinidumpUpload::Singleton->CreateQueuedMinidump(ExceptionInfo); + if (minidump == NULL) { + OutputDebugStringA("Failed to create new minidump!"); + Utils::OutputDebugLastError(); + } + + printf("Trying to print an error message from ExceptionFilter..."); + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_STACK_OVERFLOW: Logger::Error("Termination because of a stack overflow.\n"); - TerminateProcess(GetCurrentProcess(), EXCEPTION_STACK_OVERFLOW); - } - else - { + break; + default: Logger::Error("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); + break; } + //TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); + return EXCEPTION_CONTINUE_SEARCH; } - LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) + LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER) { - SetUnhandledExceptionFilter(&Exception::ExceptionFilter); - return lpTopLevelExceptionFilter; + return SetUnhandledExceptionFilter(&Exception::ExceptionFilter); + } + + LPTOP_LEVEL_EXCEPTION_FILTER Exception::Hook() + { + return SetUnhandledExceptionFilter(&Exception::ExceptionFilter); } Exception::Exception() { #ifdef DEBUG // Display DEBUG branding, so we know we're on a debug build - Renderer::OnFrame([] () + Renderer::OnFrame([]() { Game::Font* font = Game::R_RegisterFont("fonts/normalFont"); float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; @@ -162,18 +70,19 @@ namespace Components Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); }); -#else +#endif +#if !defined(DEBUG) || defined(FORCE_EXCEPTION_HANDLER) Utils::Hook::Set(0x6D70AC, Exception::SetUnhandledExceptionFilterStub); SetUnhandledExceptionFilter(&Exception::ExceptionFilter); #endif - Command::Add("mapTest", [] (Command::Params params) + Command::Add("mapTest", [](Command::Params params) { std::string command; int max = (params.Length() >= 2 ? atoi(params[1]) : 16), current = 0; - for (int i =0;;) + for (int i = 0;;) { char* mapname = Game::mapnames[i]; if (!*mapname) @@ -182,7 +91,7 @@ namespace Components continue; } - if(!(i % 2)) command.append(fmt::sprintf("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect + if (!(i % 2)) command.append(fmt::sprintf("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect else command.append(fmt::sprintf("wait 500;", mapname)); // Test direct map switch command.append(fmt::sprintf("map %s;", mapname)); @@ -193,6 +102,12 @@ namespace Components Command::Execute(command, false); }); + Command::Add("debug_exceptionhandler", [](Command::Params) + { + Logger::Print("Rerunning SetUnhandledExceptionHandler...\n"); + auto oldHandler = Exception::Hook(); + Logger::Print("Old exception handler was 0x%010X.\n", oldHandler); + }); #pragma warning(push) #pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization Command::Add("debug_minidump", [](Command::Params) diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index 0a2a8210..cc19fa06 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -1,6 +1,4 @@ -#define UPLOAD_URL "https://reich.io/upload.php" -#define BITMESSAGE_UPLOAD_IDENTITY "BM-NBhqCHraxGyUT38cfhRQYWx29gJ7QePa" -#define BITMESSAGE_SIZE_LIMIT 230000 + namespace Components { @@ -12,12 +10,10 @@ namespace Components #ifdef DEBUG const char* GetName() { return "Exception"; }; #endif + static LPTOP_LEVEL_EXCEPTION_FILTER Hook(); private: static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo); static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); - - static bool UploadMinidump(std::string filename); - static bool UploadMinidump2BM(std::string filename); }; } diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp new file mode 100644 index 00000000..7947e4f9 --- /dev/null +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -0,0 +1,366 @@ +#include "STDInclude.hpp" +#include "Shlwapi.h" + +const int MiniDumpTiny = MiniDumpFilterMemory | MiniDumpWithoutAuxiliaryState | MiniDumpWithoutOptionalData | MiniDumpFilterModulePaths | MiniDumpIgnoreInaccessibleMemory; + +namespace Components +{ + +#pragma region Minidump class implementation + inline Minidump::Minidump() {} + + Minidump::~Minidump() + { + if (this->mapFileHandle != NULL && this->mapFileHandle != INVALID_HANDLE_VALUE) + { + CloseHandle(this->mapFileHandle); + this->mapFileHandle = INVALID_HANDLE_VALUE; + } + + if (this->fileHandle != NULL && this->fileHandle != INVALID_HANDLE_VALUE) + { + CloseHandle(this->fileHandle); + this->fileHandle = INVALID_HANDLE_VALUE; + } + } + + std::string Minidump::ToString() + { + if (!Minidump::EnsureFileMapping()) return false; + + auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); + if (pBuf == NULL) + { + Utils::OutputDebugLastError(); + throw new std::runtime_error("Could not read minidump."); + } + + size_t fileSize; + DWORD fileSizeHi; + fileSize = GetFileSize(this->fileHandle, &fileSizeHi); +#ifdef _WIN64 + fileSize |= ((size_t)fileSizeHi << 32); +#endif + std::string retval = std::string((const char*)pBuf, fileSize * sizeof(const char)); + UnmapViewOfFile(pBuf); + return retval; + } + + bool Minidump::GetStream(MINIDUMP_STREAM_TYPE type, PMINIDUMP_DIRECTORY* directoryPtr, PVOID* streamBeginningPtr, ULONG* streamSizePtr) + { + if (!Minidump::EnsureFileMapping()) return false; + + auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); + if (pBuf == NULL) + { + Utils::OutputDebugLastError(); + throw new std::runtime_error("Could not read minidump."); + } + + BOOL success = MiniDumpReadDumpStream(pBuf, type, directoryPtr, streamBeginningPtr, streamSizePtr); + UnmapViewOfFile(pBuf); + if (success != TRUE) + return false; + + return true; + } + + inline bool Minidump::Check() + { + /*PMINIDUMP_DIRECTORY directory; + PVOID stream; + ULONG streamSize; + return Minidump::GetStream(ExceptionStream, &directory, &stream, &streamSize);*/ + return Minidump::GetStream(ExceptionStream, NULL, NULL, NULL); + } + + Minidump* Minidump::Create(std::string path, LPEXCEPTION_POINTERS exceptionInfo, int type) + { + Minidump* minidump = Minidump::Initialize(path); + if (minidump == NULL) return minidump; + + // Do the dump generation + MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), exceptionInfo, FALSE }; + if (!MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), minidump->fileHandle, (MINIDUMP_TYPE)type, &ex, NULL, NULL)) + { + Utils::OutputDebugLastError(); + delete minidump; + return NULL; + } + + if (SetFilePointer(minidump->fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) + { + Utils::OutputDebugLastError(); + delete minidump; + DeleteFileA(path.c_str()); + return NULL; + } + + return minidump; + } + + Minidump* Minidump::Open(std::string path) + { + Minidump* minidump = Minidump::Initialize(path, FILE_SHARE_READ); + return minidump; + } + + bool Minidump::EnsureFileMapping() + { + if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) + { + this->mapFileHandle = CreateFileMappingA(this->fileHandle, NULL, PAGE_READONLY, 0, 0, NULL); + if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) + { + Utils::OutputDebugLastError(); + return false; + } + } + return true; + } + + Minidump* Minidump::Initialize(std::string path, DWORD fileShare) + { + Minidump* minidump = new Minidump(); + + minidump->fileHandle = CreateFileA(path.c_str(), + GENERIC_WRITE | GENERIC_READ, fileShare, + NULL, (fileShare & FILE_SHARE_WRITE) > 0 ? OPEN_ALWAYS : OPEN_EXISTING, NULL, NULL); + if (minidump->fileHandle == NULL || minidump->fileHandle == INVALID_HANDLE_VALUE) + { + Utils::OutputDebugLastError(); + delete minidump; + return NULL; + } + + return minidump; + } +#pragma endregion + +#pragma region Minidump uploader class implementation + MinidumpUpload* MinidumpUpload::Singleton = NULL; + + const std::string MinidumpUpload::queuedMinidumpsFolder = "minidumps\\"; +#ifdef DISABLE_BITMESSAGE + const std::vector MinidumpUpload::targetUrls = { + "https://reich.io/upload.php", + "https://hitlers.kz/upload.php" + }; +#else + const std::string MinidumpUpload::targetAddress = "BM-2cSksR7gyyFcNK7MaFoxGCjRJWxtoGckdj"; + const unsigned int MinidumpUpload::maxSegmentSize = 200 * 1024; // 200 kB +#endif + + MinidumpUpload::MinidumpUpload() + { + if (Singleton != NULL) + throw new std::runtime_error("Can only create one instance at a time."); + + Singleton = this; + +#if !defined(DEBUG) || defined(FORCE_MINIDUMP_UPLOAD) + this->uploadThread = std::thread([&]() { this->UploadQueuedMinidumps(); }); +#endif + } + + MinidumpUpload::~MinidumpUpload() + { + Singleton = NULL; + + if (this->uploadThread.joinable()) + { + this->uploadThread.join(); + } + } + + bool MinidumpUpload::EnsureQueuedMinidumpsFolderExists() + { + BOOL success = CreateDirectoryA(queuedMinidumpsFolder.c_str(), NULL); + if (success != TRUE) success = GetLastError() == ERROR_ALREADY_EXISTS; + return success == TRUE; + } + + Minidump* MinidumpUpload::CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType) + { + // Note that most of the Path* functions are DEPRECATED and they have been replaced by Cch variants that only work on Windows 8+. + // If you plan to drop support for Windows 7, please upgrade these calls to prevent accidental buffer overflows! + + if (!EnsureQueuedMinidumpsFolderExists()) return NULL; + + // Current executable name + char exeFileName[MAX_PATH]; + GetModuleFileNameA(NULL, exeFileName, MAX_PATH); + PathStripPathA(exeFileName); + PathRemoveExtensionA(exeFileName); + + // Generate filename + char filenameFriendlyTime[MAX_PATH]; + __time64_t time; + tm ltime; + _time64(&time); + _localtime64_s(<ime, &time); + strftime(filenameFriendlyTime, sizeof(filenameFriendlyTime) - 1, "%Y%m%d%H%M%S", <ime); + + // Combine with queuedMinidumpsFolder + char filename[MAX_PATH]; + PathCombineA(filename, queuedMinidumpsFolder.c_str(), Utils::String::VA("%s-" VERSION_STR "-%s.dmp", exeFileName, filenameFriendlyTime)); + + // Generate the dump + return Minidump::Create(filename, exceptionInfo, minidumpType); + } + + bool MinidumpUpload::UploadQueuedMinidumps() + { +#ifndef DISABLE_BITMESSAGE + // Preload public key for our target that will receive minidumps + if (!BitMessage::Singleton->RequestPublicKey(MinidumpUpload::targetAddress)) + { + Logger::Error("Failed to request public key for minidump collection address.\n"); + } +#endif + + // Check if folder exists + if (!PathIsDirectoryA(queuedMinidumpsFolder.c_str())) + { + // Nothing to upload + return PathFileExistsA(queuedMinidumpsFolder.c_str()) == FALSE; + } + + // Walk through directory and search for valid minidumps + WIN32_FIND_DATAA ffd; + HANDLE hFind = FindFirstFileA(Utils::String::VA("%s\\*.dmp", queuedMinidumpsFolder), &ffd); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0) + continue; // ignore directory + + char fullPath[MAX_PATH_SIZE]; + PathCombineA(fullPath, queuedMinidumpsFolder.c_str(), ffd.cFileName); + + // Try to open this minidump + auto minidump = Minidump::Open(fullPath); + if (minidump == NULL) + continue; // file can't be opened + + // Upload! + if (!MinidumpUpload::Upload(minidump)) + continue; // couldn't upload that minidump, keep for another attempt + + delete minidump; + +#ifndef KEEP_MINIDUMPS_AFTER_UPLOAD + // Delete minidump if possible + DeleteFileA(fullPath); +#endif + } while (FindNextFileA(hFind, &ffd) != 0); + } + + return true; + } + + bool MinidumpUpload::Upload(Minidump* minidump) + { + // Checking if we can extract any information from minidump first, just to be sure that this is valid. + if (!minidump->Check()) + { + Utils::OutputDebugLastError(); + return false; + } + + std::map extraHeaders = { + {"Hash-SHA512", Utils::Cryptography::SHA512::Compute(minidump->ToString(), true)}, + {"Compression", "deflate"}, + {"ID", Utils::String::GenerateUUIDString()}, + }; + + Logger::Print("Compressing minidump...\n"); + + std::string compressedMinidump = Utils::Compression::ZLib::Compress(minidump->ToString()); + + Logger::Print("Uploading minidump...\n"); + +#ifdef DISABLE_BITMESSAGE + for (auto& targetUrl : targetUrls) + { + Utils::WebIO webio("Firefucks", targetUrl); + + std::string buffer = MinidumpUpload::Encode(compressedMinidump, extraHeaders); + std::string result = webio.PostFile(buffer, "files[]", "minidump.dmpx"); + + std::string errors; + json11::Json object = json11::Json::parse(result, errors); + + if (!object.is_object()) continue; + + json11::Json success = object["success"]; + + if (!success.is_bool() || !success.bool_value()) return false; + + json11::Json files = object["files"]; + + if (!files.is_array()) continue; + + for (auto file : files.array_items()) + { + json11::Json url = file["url"]; + json11::Json hash = file["hash"]; + + if (hash.is_string() && url.is_string()) + { + if (Utils::String::ToLower(Utils::Cryptography::SHA1::Compute(buffer, true)) == Utils::String::ToLower(hash.string_value())) + { + MessageBoxA(0, url.string_value().data(), 0, 0); + return true; + } + } + } + } + + return false; +#else + // BitMessage has a max msg size that is somewhere around 220 KB, split it up as necessary! + auto totalParts = compressedMinidump.size() / this->maxSegmentSize + 1; + extraHeaders.insert({ "Parts", Utils::String::VA("%d",totalParts) }); + + for (size_t offset = 0; offset < compressedMinidump.size(); offset += this->maxSegmentSize) + { + auto extraPartHeaders = extraHeaders; + + auto part = compressedMinidump.substr(offset, std::min(this->maxSegmentSize, compressedMinidump.size() - offset)); + auto partNum = offset / this->maxSegmentSize + 1; + extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) }); + + Logger::Print("Uploading part %d out of %d (%d bytes)...\n", partNum, totalParts, part.size()); + BitMessage::Singleton->SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); + } + + return true; +#endif + } + + std::string MinidumpUpload::Encode(std::string data, std::map extraHeaders) + { + std::string marker = "MINIDUMP"; + std::stringstream output; + + extraHeaders["Encoding"] = "raw"; + extraHeaders["Version"] = VERSION_STR; + + output << "-----BEGIN " << marker << "-----\n"; + + // Insert extra headers + for (auto& header : extraHeaders) + { + output << header.first << ": " << header.second << "\n"; + } + + output << "\n" + << data << "\n" + << "-----END " << marker << "-----\n"; + + return output.str(); + } +#pragma endregion +} \ No newline at end of file diff --git a/src/Components/Modules/MinidumpUpload.hpp b/src/Components/Modules/MinidumpUpload.hpp new file mode 100644 index 00000000..b2c5f9c3 --- /dev/null +++ b/src/Components/Modules/MinidumpUpload.hpp @@ -0,0 +1,77 @@ +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4091) +#include +#pragma comment(lib, "dbghelp.lib") +#pragma warning(pop) + +extern const int MiniDumpTiny; + +namespace Components +{ + // This class holds a Minidump and allows easy access to its aspects. + class Minidump + { + public: + ~Minidump(); + + static Minidump* Create(std::string path, LPEXCEPTION_POINTERS exceptionInfo, int type = MiniDumpTiny); + static Minidump* Open(std::string path); + bool GetStream(MINIDUMP_STREAM_TYPE type, PMINIDUMP_DIRECTORY* directoryPtr, PVOID* streamPtr, ULONG* streamSizePtr); + bool Check(); + std::string ToString(); + + private: + Minidump(); + + bool EnsureFileMapping(); + + static Minidump* Initialize(std::string path, DWORD fileShare = FILE_SHARE_READ | FILE_SHARE_WRITE); + + HANDLE fileHandle; + HANDLE mapFileHandle; + }; + + class MinidumpUpload : public Component + { + public: +#ifdef DEBUG + const char* GetName() { return "MinidumpUpload"; }; +#endif + MinidumpUpload(); + ~MinidumpUpload(); + + // Uploads the given minidump. + bool Upload(Minidump* minidump); + + // Generates a new minidump and saves it to the folder for queued minidumps. + Minidump* CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType = MiniDumpTiny); + + // Browses the folder for queued minidumps and uploads each queued minidump. + // On Release builds this will also delete every successfully uploaded minidump. + bool UploadQueuedMinidumps(); + + static MinidumpUpload* Singleton; + + private: + std::thread uploadThread; + + // Encodes the given minidump so that it can be uploaded in a proper format. + // Internally, this will compress the minidump and decorate it with proper markers and first-look headers. + static std::string Encode(std::string data, std::map extraHeaders = {}); + + // Ensures the queued minidumps folder exists. Will return false if the directory can't be created and does not exist. + static bool EnsureQueuedMinidumpsFolderExists(); + + // Contains the path to the minidumps folder. + static const std::string queuedMinidumpsFolder; + +#ifdef DISABLE_BITMESSAGE + static const std::vector targetUrls; +#else + static const std::string targetAddress; + static const unsigned int maxSegmentSize; +#endif + }; +} diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index ede6eb31..6a3faf0f 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -61,8 +61,9 @@ #include #include #include -// Bitmessage +#ifndef DISABLE_BITMESSAGE #include +#endif #ifdef max #undef max @@ -112,6 +113,7 @@ #pragma comment(lib, "shlwapi.lib") #pragma comment(lib, "Urlmon.lib") #pragma comment(lib, "Advapi32.lib") +#pragma comment(lib, "rpcrt4.lib") // Enable additional literals using namespace std::literals; diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 504c21ec..a1ec1bfc 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -131,14 +131,16 @@ namespace Utils return EncodeBase64(input.c_str(), input.size()); } - // Decodes a given string from Base64 - std::string DecodeBase64(const std::string& input) { - unsigned char* out = new unsigned char[input.size()]; - unsigned long outlen = input.size(); - base64_decode((unsigned char*)input.c_str(), input.size(), out, &outlen); - std::string ret((char*)out, outlen); - delete[] out; - return ret; + // Generates a UUID and returns the string representation of it + std::string GenerateUUIDString() { + // Generate UUID data + UUID uuid; + UuidCreate(&uuid); + + // Convert to string representation + char* strdata = NULL; + UuidToStringA(&uuid, (RPC_CSTR*)&strdata); + return std::string(strdata); } } } diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 3e2c0ea1..84af479d 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -42,6 +42,7 @@ namespace Utils std::string EncodeBase64(const char* input, const unsigned long inputSize); std::string EncodeBase64(const std::string& input); - std::string DecodeBase64(const std::string& input); + + std::string GenerateUUIDString(); } } diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index 02c080ec..f35d1e79 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -22,4 +22,17 @@ namespace Utils if (pos == std::string::npos) return data; return data.substr(0, pos).data(); } + + void OutputDebugLastError() + { + DWORD errorMessageID = ::GetLastError(); + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + std::string message(messageBuffer, size); + + OutputDebugStringA(Utils::String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, message)); + + LocalFree(messageBuffer); + } } diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index 99a187a7..399b34d7 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -2,6 +2,7 @@ namespace Utils { std::string GetMimeType(std::string url); std::string ParseChallenge(std::string data); + void OutputDebugLastError(); template void Merge(std::vector* target, T* source, size_t length) { diff --git a/src/Utils/WebIO.cpp b/src/Utils/WebIO.cpp index 78264bb0..59339d0f 100644 --- a/src/Utils/WebIO.cpp +++ b/src/Utils/WebIO.cpp @@ -134,21 +134,30 @@ namespace Utils return body; } - std::string WebIO::PostFile(std::string url, std::string data) + std::string WebIO::PostFile(std::string url, std::string data, std::string fieldName, std::string fileName) { WebIO::SetURL(url); - return WebIO::PostFile(data); + return WebIO::PostFile(data, fieldName, fileName); } - std::string WebIO::PostFile(std::string data) + std::string WebIO::PostFile(std::string data, std::string fieldName, std::string fileName) { WebIO::Params headers; std::string boundary = "----WebKitFormBoundaryHoLVocRsBxs71fU6"; headers["Content-Type"] = "multipart/form-data, boundary=" + boundary; + Utils::String::Replace(fieldName, "\"", "\\\""); + Utils::String::Replace(fieldName, "\\", "\\\\"); + Utils::String::Replace(fileName, "\"", "\\\""); + Utils::String::Replace(fileName, "\\", "\\\\"); + std::string body = "--" + boundary + "\r\n"; - body += "Content-Disposition: form-data; name=\"files[]\"; filename=\"minidump.dmp\"\r\n"; + body += "Content-Disposition: form-data; name=\""; + body += fieldName; + body += "\"; filename=\""; + body += fileName; + body += "\"\r\n"; body += "Content-Type: application/octet-stream\r\n\r\n"; body += data + "\r\n"; body += "--" + boundary + "--\r\n"; diff --git a/src/Utils/WebIO.hpp b/src/Utils/WebIO.hpp index a30c9331..849cd57d 100644 --- a/src/Utils/WebIO.hpp +++ b/src/Utils/WebIO.hpp @@ -26,8 +26,8 @@ namespace Utils void SetURL(std::string url); void SetCredentials(std::string username, std::string password); - std::string PostFile(std::string url, std::string data); - std::string PostFile(std::string data); + std::string PostFile(std::string url, std::string data, std::string fieldName, std::string fileName); + std::string PostFile(std::string data, std::string fieldName, std::string fileName); std::string Post(std::string url, WebIO::Params params); std::string Post(std::string url, std::string body); From cf59101497dd99878ddb2baa5b97b32e3495da18 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 28 Aug 2016 20:52:47 +0200 Subject: [PATCH 24/81] Exception shit --- deps/fmt | 2 +- src/Components/Modules/Exception.cpp | 14 +++++++++++++- src/Components/Modules/Exception.hpp | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/deps/fmt b/deps/fmt index 2ae6bca4..0d25f6fc 160000 --- a/deps/fmt +++ b/deps/fmt @@ -1 +1 @@ -Subproject commit 2ae6bca488795929a0207d109e135751f10c53d9 +Subproject commit 0d25f6fcbbf0a867b939a5501965ee4462b21ee6 diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index bab77313..da3dd338 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -9,6 +9,8 @@ namespace Components { + Utils::Hook Exception::SetFilterHook; + bool Exception::UploadMinidump(std::string filename) { if (Utils::IO::FileExists(filename)) @@ -86,7 +88,10 @@ namespace Components LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { + Exception::SetFilterHook.Uninstall(); SetUnhandledExceptionFilter(&Exception::ExceptionFilter); + Exception::SetFilterHook.Install(); + return lpTopLevelExceptionFilter; } @@ -110,7 +115,9 @@ namespace Components Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); }); #else - Utils::Hook::Set(0x6D70AC, Exception::SetUnhandledExceptionFilterStub); + Exception::SetFilterHook.Initialize(SetUnhandledExceptionFilter, Exception::SetUnhandledExceptionFilterStub, HOOK_JUMP); + Exception::SetFilterHook.Install(); + SetUnhandledExceptionFilter(&Exception::ExceptionFilter); #endif @@ -141,4 +148,9 @@ namespace Components Command::Execute(command, false); }); } + + Exception::~Exception() + { + Exception::SetFilterHook.Uninstall(); + } } diff --git a/src/Components/Modules/Exception.hpp b/src/Components/Modules/Exception.hpp index 8e70ffea..00e24134 100644 --- a/src/Components/Modules/Exception.hpp +++ b/src/Components/Modules/Exception.hpp @@ -4,6 +4,7 @@ namespace Components { public: Exception(); + ~Exception(); #ifdef DEBUG const char* GetName() { return "Exception"; }; @@ -14,5 +15,7 @@ namespace Components static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); static bool UploadMinidump(std::string filename); + + static Utils::Hook SetFilterHook; }; } From e8598f3cdb0fbd87ea08a791eb301fb808f42137 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 28 Aug 2016 21:21:25 +0200 Subject: [PATCH 25/81] --- src/Components/Modules/AntiCheat.cpp | 5 ++++- src/Components/Modules/Exception.cpp | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index dd68d9c5..cc2e6ebb 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -646,7 +646,10 @@ namespace Components Utils::Hook(0x56AC60, AntiCheat::AimTargetGetTagPosStub, HOOK_JUMP).Install()->Quick(); // TODO: Probably move that :P - AntiCheat::InitLoadLibHook(); + if (!Dedicated::IsEnabled()) + { + AntiCheat::InitLoadLibHook(); + } // Prevent external processes from accessing our memory AntiCheat::ProtectProcess(); diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index da3dd338..062d3880 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -70,6 +70,10 @@ namespace Components MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ex, NULL, NULL); CloseHandle(hFile); } + else + { + MessageBoxA(0, "Failed to create file!", "ERROR", MB_ICONERROR); + } //Exception::UploadMinidump(filename); From 01a90e42e4bcf0a44054c466d5ac7f64b89301e3 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sun, 28 Aug 2016 21:38:29 +0200 Subject: [PATCH 26/81] Remove unnecessary exclusion of source files related to Tor. --- premake5.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/premake5.lua b/premake5.lua index f5ef4a44..06cf8f60 100644 --- a/premake5.lua +++ b/premake5.lua @@ -257,9 +257,6 @@ workspace "iw4x" resincludedirs { "$(ProjectDir)src" -- fix for VS IDE } - removefiles { - "./src/Components/Modules/Tor.*", - } -- Debug flags if _OPTIONS["ac-debug-detections"] then From f9e2eeca7b42dcf05e76a5cc38b8d77fc21cad3c Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sun, 28 Aug 2016 22:46:23 +0200 Subject: [PATCH 27/81] Base128 encoding of minidumps before uploading. --- .gitmodules | 3 ++ deps/base128 | 1 + premake/base128.lua | 54 +++++++++++++++++++++++ premake5.lua | 7 +++ src/Components/Modules/MinidumpUpload.cpp | 8 +++- src/Utils/String.cpp | 9 ++++ src/Utils/String.hpp | 2 + 7 files changed, 83 insertions(+), 1 deletion(-) create mode 160000 deps/base128 create mode 100644 premake/base128.lua diff --git a/.gitmodules b/.gitmodules index 83990074..d33568ec 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,6 @@ [submodule "deps/bitmrc"] path = deps/bitmrc url = git@github.com:iw4x-dev-urandom/BitMRC.git +[submodule "deps/base128"] + path = deps/base128 + url = https://github.com/seizu/base128.git diff --git a/deps/base128 b/deps/base128 new file mode 160000 index 00000000..64c8ab27 --- /dev/null +++ b/deps/base128 @@ -0,0 +1 @@ +Subproject commit 64c8ab2755e14d316b18aff9746f0180f5fe301b diff --git a/premake/base128.lua b/premake/base128.lua new file mode 100644 index 00000000..bd8a7db3 --- /dev/null +++ b/premake/base128.lua @@ -0,0 +1,54 @@ +base128 = { + settings = nil +} + +function base128.setup(settings) + if not settings.source then error("Missing source.") end + + base128.settings = settings +end + +function base128.import() + if not base128.settings then error("Run base128.setup first") end + + base128.links() + base128.includes() +end + +function base128.links() + if not base128.settings then error("Run base128.setup first") end + + links { "base128" } +end + +function base128.includes() + if not base128.settings then error("Run base128.setup first") end + + includedirs { path.join(base128.settings.source, "cpp") } +end + +function base128.project() + if not base128.settings then error("Run base128.setup first") end + + project "base128" + language "C++" + + base128.includes() + + files + { + path.join(base128.settings.source, "cpp/*.cpp"), + path.join(base128.settings.source, "cpp/*.h"), + } + removefiles + { + "**/demo.*", + } + + -- 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 06cf8f60..c05b6be6 100644 --- a/premake5.lua +++ b/premake5.lua @@ -140,6 +140,7 @@ newaction { depsBasePath = "./deps" +require "premake/base128" require "premake/bitmrc" require "premake/fmt" require "premake/json11" @@ -153,6 +154,10 @@ require "premake/sqlite3" require "premake/winksignals" require "premake/zlib" +base128.setup +{ + source = path.join(depsBasePath, "base128"), +} bitmrc.setup { source = path.join(depsBasePath, "bitmrc"), @@ -290,6 +295,7 @@ workspace "iw4x" if not _OPTIONS["disable-bitmessage"] then bitmrc.import() end + base128.import() fmt.import() json11.import() libtomcrypt.import() @@ -398,6 +404,7 @@ workspace "iw4x" libcryptopp.project() sqlite3.project() end + base128.project() fmt.project() json11.project() libtomcrypt.project() diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 7947e4f9..1fbef281 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -279,6 +279,11 @@ namespace Components std::string compressedMinidump = Utils::Compression::ZLib::Compress(minidump->ToString()); +#ifndef DISABLE_BASE128 + extraHeaders["Encoding"] = "base128"; + compressedMinidump = Utils::String::EncodeBase128(compressedMinidump); +#endif + Logger::Print("Uploading minidump...\n"); #ifdef DISABLE_BITMESSAGE @@ -345,7 +350,8 @@ namespace Components std::string marker = "MINIDUMP"; std::stringstream output; - extraHeaders["Encoding"] = "raw"; + if (extraHeaders.find("Encoding") == extraHeaders.end()) + extraHeaders["Encoding"] = "raw"; extraHeaders["Version"] = VERSION_STR; output << "-----BEGIN " << marker << "-----\n"; diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index a1ec1bfc..cba41fa9 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -1,4 +1,5 @@ #include "STDInclude.hpp" +#include "base128.h" namespace Utils { @@ -131,6 +132,14 @@ namespace Utils return EncodeBase64(input.c_str(), input.size()); } + // Encodes a given string in Base128 + std::string EncodeBase128(const std::string& input) { + auto encoder = new base128(); + auto buffer = encoder->encode(const_cast(static_cast(input.data())), input.size()); + delete encoder; + return std::string(buffer); + } + // Generates a UUID and returns the string representation of it std::string GenerateUUIDString() { // Generate UUID data diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 84af479d..6ca9cc57 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -43,6 +43,8 @@ namespace Utils std::string EncodeBase64(const char* input, const unsigned long inputSize); std::string EncodeBase64(const std::string& input); + std::string EncodeBase128(const std::string& input); + std::string GenerateUUIDString(); } } From 531fdf0e348239908ec88e49934b137daa2ccc4a Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Sun, 28 Aug 2016 22:47:22 +0200 Subject: [PATCH 28/81] Fix crash if a valid minidump is residing in minidumps folder. --- src/Components/Modules/MinidumpUpload.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 1fbef281..3554f2a9 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -26,7 +26,7 @@ namespace Components std::string Minidump::ToString() { - if (!Minidump::EnsureFileMapping()) return false; + if (!this->EnsureFileMapping()) return false; auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); if (pBuf == NULL) @@ -48,7 +48,7 @@ namespace Components bool Minidump::GetStream(MINIDUMP_STREAM_TYPE type, PMINIDUMP_DIRECTORY* directoryPtr, PVOID* streamBeginningPtr, ULONG* streamSizePtr) { - if (!Minidump::EnsureFileMapping()) return false; + if (!this->EnsureFileMapping()) return false; auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); if (pBuf == NULL) @@ -110,7 +110,7 @@ namespace Components if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) { this->mapFileHandle = CreateFileMappingA(this->fileHandle, NULL, PAGE_READONLY, 0, 0, NULL); - if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) + if (this->mapFileHandle == NULL) { Utils::OutputDebugLastError(); return false; From 07aaf58f979455f7f3e28a1227f4f680fde69110 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:35:33 +0200 Subject: [PATCH 29/81] Just to make sure, properly initialize handle values in Minidump class. --- src/Components/Modules/MinidumpUpload.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 3554f2a9..4b3fedf2 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -7,7 +7,10 @@ namespace Components { #pragma region Minidump class implementation - inline Minidump::Minidump() {} + Minidump::Minidump() + { + this->fileHandle = this->mapFileHandle = INVALID_HANDLE_VALUE; + } Minidump::~Minidump() { @@ -110,7 +113,7 @@ namespace Components if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) { this->mapFileHandle = CreateFileMappingA(this->fileHandle, NULL, PAGE_READONLY, 0, 0, NULL); - if (this->mapFileHandle == NULL) + if (this->mapFileHandle == NULL || this->mapFileHandle == INVALID_HANDLE_VALUE) { Utils::OutputDebugLastError(); return false; From 41292eee9567ee517aec42c3d414eacd7b4be802 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:36:41 +0200 Subject: [PATCH 30/81] Premake: Add "--disable-base128" to disable Base-128 encoding for minidump uploads. --- premake5.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/premake5.lua b/premake5.lua index c05b6be6..b98c162d 100644 --- a/premake5.lua +++ b/premake5.lua @@ -57,6 +57,10 @@ newoption { trigger = "disable-bitmessage", description = "Disable use of BitMessage completely." } +newoption { + trigger = "disable-base128", + description = "Disable debugging messages for Nodes in Debug builds." +} newaction { trigger = "version", @@ -285,6 +289,9 @@ workspace "iw4x" "./src/Components/Modules/BitMessage.*", } end + if _OPTIONS["disable-base128"] then + defines { "DISABLE_BASE128" } + end -- Pre-compiled header pchheader "STDInclude.hpp" -- must be exactly same as used in #include directives @@ -295,7 +302,9 @@ workspace "iw4x" if not _OPTIONS["disable-bitmessage"] then bitmrc.import() end - base128.import() + if not _OPTIONS["disable-base128"] then + base128.import() + end fmt.import() json11.import() libtomcrypt.import() @@ -404,7 +413,9 @@ workspace "iw4x" libcryptopp.project() sqlite3.project() end - base128.project() + if not _OPTIONS["disable-base128"] then + base128.project() + end fmt.project() json11.project() libtomcrypt.project() From 9fdf7b9b380a81501bd9bb003dd4485055ea0d3c Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:37:13 +0200 Subject: [PATCH 31/81] Premake: Add "--disable-node-log" to disable logging of Nodes activity. --- premake5.lua | 7 ++++++ src/Components/Modules/Node.cpp | 40 ++++++++++++++++----------------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/premake5.lua b/premake5.lua index b98c162d..b68220b5 100644 --- a/premake5.lua +++ b/premake5.lua @@ -57,6 +57,10 @@ newoption { trigger = "disable-bitmessage", description = "Disable use of BitMessage completely." } +newoption { + trigger = "disable-node-log", + description = "Disable debugging messages for Nodes in Debug builds." +} newoption { trigger = "disable-base128", description = "Disable debugging messages for Nodes in Debug builds." @@ -289,6 +293,9 @@ workspace "iw4x" "./src/Components/Modules/BitMessage.*", } end + if _OPTIONS["disable-node-log"] then + defines { "DISABLE_NODE_LOG"} + end if _OPTIONS["disable-base128"] then defines { "DISABLE_BASE128" } end diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 50c3e977..2fcd22a5 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -130,7 +130,7 @@ namespace Components Node::Nodes.push_back(entry); -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Adding node %s...\n", address.GetCString()); #endif } @@ -187,7 +187,7 @@ namespace Components { if (node.state == Node::STATE_INVALID && (Game::Sys_Milliseconds() - node.lastHeard) > NODE_INVALID_DELETE) { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Removing invalid node %s\n", node.address.GetCString()); #endif } @@ -231,14 +231,14 @@ namespace Components Proto::Node::Packet packet; packet.set_challenge(entry->challenge); -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Sending registration request to %s\n", entry->address.GetCString()); #endif Network::SendCommand(entry->address, "nodeRegisterRequest", packet.SerializeAsString()); } else { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Sending session request to %s\n", entry->address.GetCString()); #endif Network::SendCommand(entry->address, "sessionRequest"); @@ -267,7 +267,7 @@ namespace Components node.lastHeard = Game::Sys_Milliseconds(); node.lastTime = Game::Sys_Milliseconds(); -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Node negotiation timed out. Invalidating %s\n", node.address.GetCString()); #endif } @@ -399,7 +399,7 @@ namespace Components if (!entry) return; } -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Received registration request from %s\n", address.GetCString()); #endif @@ -440,7 +440,7 @@ namespace Components Node::NodeEntry* entry = Node::FindNode(address); if (!entry || entry->state != Node::STATE_NEGOTIATING) return; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Received synchronization data for registration from %s!\n", address.GetCString()); #endif @@ -467,7 +467,7 @@ namespace Components entry->state = Node::STATE_VALID; entry->registered = true; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data()); Logger::Print("Node %s registered\n", address.GetCString()); #endif @@ -491,7 +491,7 @@ namespace Components Node::NodeEntry* entry = Node::FindNode(address); if (!entry || entry->state != Node::STATE_NEGOTIATING) return; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Received acknowledgment from %s\n", address.GetCString()); #endif @@ -511,7 +511,7 @@ namespace Components entry->state = Node::STATE_VALID; entry->registered = true; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data()); Logger::Print("Node %s registered\n", address.GetCString()); #endif @@ -554,7 +554,7 @@ namespace Components } else { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) // Unallowed connection Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetCString()); #endif @@ -584,13 +584,13 @@ namespace Components entry->registered = false; entry->state = Node::STATE_INVALID; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Node %s unregistered\n", address.GetCString()); #endif } else { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetCString()); #endif } @@ -612,7 +612,7 @@ namespace Components Node::ClientSession* session = Node::FindSession(address); if (!session) return; // Registering template session failed, odd... -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Client %s is requesting a new session\n", address.GetCString()); #endif @@ -634,7 +634,7 @@ namespace Components if (session->challenge == data) { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Session for %s validated.\n", address.GetCString()); #endif session->valid = true; @@ -643,7 +643,7 @@ namespace Components else { session->lastTime = -1; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetCString()); #endif } @@ -656,7 +656,7 @@ namespace Components Node::NodeEntry* entry = Node::FindNode(address); if (!entry) return; -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Session initialization received from %s. Synchronizing...\n", address.GetCString()); #endif @@ -673,7 +673,7 @@ namespace Components entry->registered = true; entry->lastTime = Game::Sys_Milliseconds(); -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Session acknowledged by %s, synchronizing node list...\n", address.GetCString()); #endif Network::SendCommand(address, "nodeListRequest"); @@ -687,7 +687,7 @@ namespace Components if (data.empty() || !list.ParseFromString(data)) { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Received invalid node list from %s!\n", address.GetCString()); #endif return; @@ -698,7 +698,7 @@ namespace Components { if (entry->registered) { -#ifdef DEBUG +#if defined(DEBUG) && !defined(DISABLE_NODE_LOG) Logger::Print("Received valid node list with %i entries from %s\n", list.address_size(), address.GetCString()); #endif From 7c8a4c37ecd6e0d79b3135ae1bc8a7936b0b0fe9 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:47:51 +0200 Subject: [PATCH 32/81] Fix Base128 encoding. --- src/Utils/String.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index cba41fa9..a9ab39d1 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -135,7 +135,8 @@ namespace Utils // Encodes a given string in Base128 std::string EncodeBase128(const std::string& input) { auto encoder = new base128(); - auto buffer = encoder->encode(const_cast(static_cast(input.data())), input.size()); + void* inbuffer = const_cast(input.data()); + char* buffer = encoder->encode(inbuffer, input.size()); delete encoder; return std::string(buffer); } From 902e23c974945098dbe5b502ab591ca457f01d06 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:51:42 +0200 Subject: [PATCH 33/81] Add some more detailed logging for minidump upload. --- src/Components/Modules/MinidumpUpload.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 4b3fedf2..f95369d7 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -260,6 +260,7 @@ namespace Components } while (FindNextFileA(hFind, &ffd) != 0); } + Logger::Print("All minidumps uploaded."); return true; } @@ -278,16 +279,18 @@ namespace Components {"ID", Utils::String::GenerateUUIDString()}, }; - Logger::Print("Compressing minidump...\n"); + std::string compressedMinidump = minidump->ToString(); - std::string compressedMinidump = Utils::Compression::ZLib::Compress(minidump->ToString()); + Logger::Print("Compressing minidump %s (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); + compressedMinidump = Utils::Compression::ZLib::Compress(compressedMinidump); #ifndef DISABLE_BASE128 + Logger::Print("Encoding minidump %s (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); extraHeaders["Encoding"] = "base128"; compressedMinidump = Utils::String::EncodeBase128(compressedMinidump); #endif - Logger::Print("Uploading minidump...\n"); + Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); #ifdef DISABLE_BITMESSAGE for (auto& targetUrl : targetUrls) @@ -340,7 +343,7 @@ namespace Components auto partNum = offset / this->maxSegmentSize + 1; extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) }); - Logger::Print("Uploading part %d out of %d (%d bytes)...\n", partNum, totalParts, part.size()); + Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", partNum, totalParts, part.size()); BitMessage::Singleton->SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); } From 1dca734e058cf91c53b41ead8141dd3252571b60 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 07:59:52 +0200 Subject: [PATCH 34/81] Close minidump immediately after generating it. --- src/Components/Modules/Exception.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 7903f7ba..1c0712e5 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -28,10 +28,9 @@ namespace Components } else { - MessageBoxA(0, "Failed to create file!", "ERROR", MB_ICONERROR); + delete minidump; } - printf("Trying to print an error message from ExceptionFilter..."); switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_STACK_OVERFLOW: From e4a1390f2e93ab420848c6acc81d20bddb0481ad Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 08:01:04 +0200 Subject: [PATCH 35/81] Fix crash due to invalid formatted logging message in MinidumpUpload. --- src/Components/Modules/MinidumpUpload.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index f95369d7..976262a3 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -343,7 +343,7 @@ namespace Components auto partNum = offset / this->maxSegmentSize + 1; extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) }); - Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", partNum, totalParts, part.size()); + Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", extraHeaders["ID"], partNum, totalParts, part.size()); BitMessage::Singleton->SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); } From f0b4525901aab281c3d2a8c3868574a580644e4f Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 08:58:04 +0200 Subject: [PATCH 36/81] Properly wait for public key of minidump upload address. --- src/Components/Modules/BitMessage.cpp | 34 +++++++++++++++++++++-- src/Components/Modules/BitMessage.hpp | 2 ++ src/Components/Modules/MinidumpUpload.cpp | 4 ++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 047d2851..0a7c9d5d 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -116,13 +116,13 @@ namespace Components else for (auto& addr : Singleton->BMClient->PubAddresses) { - Logger::Print("%s\n", addr.getAddress().c_str()); + Logger::Print("%s (waiting for public key: %s)\n", addr.getAddress().c_str(), addr.waitingPubKey() ? "yes" : "no"); } mlock.unlock(); }); Command::Add("bm_save", [](Command::Params) { - Singleton->BMClient->save(BITMESSAGE_OBJECT_STORAGE_FILENAME); + Singleton->Save(); }); Command::Add("bm_address_public", [](Command::Params params) { if (params.Length() < 2) return; @@ -187,6 +187,31 @@ namespace Components return true; } + bool BitMessage::RequestAndWaitForPublicKey(std::string targetAddress) + { + // Convert to ustring + ustring targetAddressU; + targetAddressU.fromString(targetAddress); + + // Convert to PubAddr + PubAddr pubAddr; + if (!pubAddr.loadAddr(targetAddressU)) + { + return false; + } + + // Request public key! + this->BMClient->getPubKey(pubAddr); + + // TODO: Wait for public key by using signalling in BitMRC, needs to be done directly in the fork. + do + { + sleep(1000); + } while (pubAddr.waitingPubKey()); + + return true; + } + bool BitMessage::Subscribe(std::string targetAddress) { // Convert to ustring @@ -256,6 +281,11 @@ namespace Components BMClient->addAddr(myAddress); return true; } + + void BitMessage::Save() + { + BMClient->save(); + } } #endif \ No newline at end of file diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index 5c52cd19..a77191b6 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -19,9 +19,11 @@ namespace Components void SetDefaultTTL(time_t ttl); bool RequestPublicKey(std::string targetAddress); + bool RequestAndWaitForPublicKey(std::string targetAddress); bool Subscribe(std::string targetAddress); bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0); bool SendBroadcast(std::string message, time_t ttl = 0); + void Save(); static BitMessage* Singleton; BitMRC* BMClient; diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 976262a3..7cdc8400 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -216,10 +216,12 @@ namespace Components { #ifndef DISABLE_BITMESSAGE // Preload public key for our target that will receive minidumps - if (!BitMessage::Singleton->RequestPublicKey(MinidumpUpload::targetAddress)) + Logger::Print("Waiting for public key for minidump upload address.\n"); + if (!BitMessage::Singleton->RequestAndWaitForPublicKey(MinidumpUpload::targetAddress)) { Logger::Error("Failed to request public key for minidump collection address.\n"); } + BitMessage::Singleton->Save(); #endif // Check if folder exists From c4d1eb89405c363bfe1c37507ac43122a85df23a Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 09:03:10 +0200 Subject: [PATCH 37/81] Properly deinitialize BitMessage client to save objects and keys. --- src/Components/Modules/BitMessage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 0a7c9d5d..731a207b 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -162,6 +162,7 @@ namespace Components BitMessage::~BitMessage() { Singleton = NULL; + delete this->BMClient; } void BitMessage::SetDefaultTTL(time_t ttl) From 4d2d974edeb91895c57b3f5102c3352af9b3d74f Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 10:10:37 +0200 Subject: [PATCH 38/81] Fix waiting for public key when uploading minidumps. --- src/Components/Modules/BitMessage.cpp | 53 +++++++++++++++++++---- src/Components/Modules/BitMessage.hpp | 3 +- src/Components/Modules/MinidumpUpload.cpp | 10 +++-- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 731a207b..64afe87f 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -188,27 +188,62 @@ namespace Components return true; } - bool BitMessage::RequestAndWaitForPublicKey(std::string targetAddress) + PubAddr* BitMessage::FindPublicKey(PubAddr address) + { + std::shared_lock mlock(Singleton->BMClient->mutex_pub); + + PubAddr* retval = nullptr; + + for (auto& pubKey : BMClient->PubAddresses) + { + if (pubKey.getVersion() == address.getVersion()) //check same version + { + if ((address.getVersion() >= 4 && pubKey.getTag() == address.getTag()) // version 4+ equality check + || (pubKey.getRipe() == address.getRipe())) // version 3- equality check + { + retval = &pubKey; + break; + } + } + } + mlock.unlock(); + return retval; + } + + bool BitMessage::WaitForPublicKey(std::string targetAddress) { // Convert to ustring ustring targetAddressU; targetAddressU.fromString(targetAddress); // Convert to PubAddr - PubAddr pubAddr; - if (!pubAddr.loadAddr(targetAddressU)) + PubAddr address; + if (!address.loadAddr(targetAddressU)) { return false; } - // Request public key! - this->BMClient->getPubKey(pubAddr); + // Resolve our own copy to the registered PubAddr copy in BitMRC if possible + auto resolvedAddress = FindPublicKey(address); + if (resolvedAddress != nullptr && + !resolvedAddress->waitingPubKey() && !resolvedAddress->getPubEncryptionKey().empty()) + return true; - // TODO: Wait for public key by using signalling in BitMRC, needs to be done directly in the fork. - do + if (resolvedAddress == nullptr || + (!resolvedAddress->waitingPubKey() && resolvedAddress->getPubEncryptionKey().empty())) { - sleep(1000); - } while (pubAddr.waitingPubKey()); + // Request public key + this->BMClient->getPubKey(address); + resolvedAddress = FindPublicKey(address); + } + this->Save(); + + // TODO: Wait for public key by using signaling in BitMRC, needs to be done directly in the fork. + while (resolvedAddress->waitingPubKey()) + { + sleep(1500); + } + this->Save(); return true; } diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index a77191b6..2ab9a3ba 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -19,7 +19,7 @@ namespace Components void SetDefaultTTL(time_t ttl); bool RequestPublicKey(std::string targetAddress); - bool RequestAndWaitForPublicKey(std::string targetAddress); + bool WaitForPublicKey(std::string targetAddress); bool Subscribe(std::string targetAddress); bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0); bool SendBroadcast(std::string message, time_t ttl = 0); @@ -29,6 +29,7 @@ namespace Components BitMRC* BMClient; private: + PubAddr* FindPublicKey(PubAddr addr); bool InitAddr(); }; } diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 7cdc8400..7bc1639a 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -216,12 +216,16 @@ namespace Components { #ifndef DISABLE_BITMESSAGE // Preload public key for our target that will receive minidumps - Logger::Print("Waiting for public key for minidump upload address.\n"); - if (!BitMessage::Singleton->RequestAndWaitForPublicKey(MinidumpUpload::targetAddress)) + Logger::Print("About to send request for public key for minidump upload address.\n"); + if (!BitMessage::Singleton->RequestPublicKey(MinidumpUpload::targetAddress)) { Logger::Error("Failed to request public key for minidump collection address.\n"); } - BitMessage::Singleton->Save(); + Logger::Print("Waiting for public key for minidump upload address.\n"); + if (!BitMessage::Singleton->WaitForPublicKey(MinidumpUpload::targetAddress)) + { + Logger::Error("Failed to fetch public key for minidump collection address.\n"); + } #endif // Check if folder exists From 3b9134422d75ab11ac39184ef01e7616fbfcc1aa Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 10:11:03 +0200 Subject: [PATCH 39/81] Fix Base128 utility function. --- src/Utils/String.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index a9ab39d1..368a5e14 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -137,8 +137,14 @@ namespace Utils auto encoder = new base128(); void* inbuffer = const_cast(input.data()); char* buffer = encoder->encode(inbuffer, input.size()); + /* + Interesting to see that the buffer returned by the encoder is not a standalone string copy + but instead is a pointer to the internal "encoded" field of the encoder. So if you deinitialize + the encoder that string will probably become garbage. + */ + std::string retval(buffer); delete encoder; - return std::string(buffer); + return retval; } // Generates a UUID and returns the string representation of it From 9b87ca8ff7afa7e9c1e30c4fb1508af1fee937eb Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 10:18:27 +0200 Subject: [PATCH 40/81] Add and fix minidump upload logging strings. --- src/Components/Modules/MinidumpUpload.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 7bc1639a..3b869dde 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -232,6 +232,7 @@ namespace Components if (!PathIsDirectoryA(queuedMinidumpsFolder.c_str())) { // Nothing to upload + Logger::Print("No minidumps to upload.\n"); return PathFileExistsA(queuedMinidumpsFolder.c_str()) == FALSE; } @@ -249,13 +250,20 @@ namespace Components PathCombineA(fullPath, queuedMinidumpsFolder.c_str(), ffd.cFileName); // Try to open this minidump + Logger::Print("Trying to upload %s...\n", fullPath); auto minidump = Minidump::Open(fullPath); if (minidump == NULL) + { + Logger::Print("Couldn't open minidump.\n"); continue; // file can't be opened + } // Upload! if (!MinidumpUpload::Upload(minidump)) + { + Logger::Print("Couldn't upload minidump.\n"); continue; // couldn't upload that minidump, keep for another attempt + } delete minidump; @@ -266,7 +274,7 @@ namespace Components } while (FindNextFileA(hFind, &ffd) != 0); } - Logger::Print("All minidumps uploaded."); + Logger::Print("All minidumps uploaded.\n"); return true; } @@ -279,24 +287,26 @@ namespace Components return false; } + auto id = Utils::String::GenerateUUIDString(); + std::map extraHeaders = { {"Hash-SHA512", Utils::Cryptography::SHA512::Compute(minidump->ToString(), true)}, {"Compression", "deflate"}, - {"ID", Utils::String::GenerateUUIDString()}, + {"ID", id}, }; std::string compressedMinidump = minidump->ToString(); - Logger::Print("Compressing minidump %s (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); + Logger::Print("Compressing minidump %s (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); compressedMinidump = Utils::Compression::ZLib::Compress(compressedMinidump); #ifndef DISABLE_BASE128 - Logger::Print("Encoding minidump %s (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); + Logger::Print("Encoding minidump %s (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); extraHeaders["Encoding"] = "base128"; compressedMinidump = Utils::String::EncodeBase128(compressedMinidump); #endif - Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", extraHeaders["ID"], compressedMinidump.size()); + Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); #ifdef DISABLE_BITMESSAGE for (auto& targetUrl : targetUrls) @@ -349,7 +359,7 @@ namespace Components auto partNum = offset / this->maxSegmentSize + 1; extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) }); - Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", extraHeaders["ID"], partNum, totalParts, part.size()); + Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", id.c_str(), partNum, totalParts, part.size()); BitMessage::Singleton->SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); } From 3f04d9d2d43b824cebdc24ff182fd6e994381021 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Mon, 29 Aug 2016 10:18:58 +0200 Subject: [PATCH 41/81] Fix build with DISABLE_BASE128 set. --- src/Utils/String.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 368a5e14..f2c8c7e3 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -1,5 +1,7 @@ #include "STDInclude.hpp" +#ifndef DISABLE_BASE128 #include "base128.h" +#endif namespace Utils { @@ -132,6 +134,7 @@ namespace Utils return EncodeBase64(input.c_str(), input.size()); } +#ifndef DISABLE_BASE128 // Encodes a given string in Base128 std::string EncodeBase128(const std::string& input) { auto encoder = new base128(); @@ -146,6 +149,7 @@ namespace Utils delete encoder; return retval; } +#endif // Generates a UUID and returns the string representation of it std::string GenerateUUIDString() { From 458ae5f2aa3cde0a309d480e1f07835a604b2b22 Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Tue, 30 Aug 2016 09:13:56 +0200 Subject: [PATCH 42/81] --- src/Components/Modules/QuickPatch.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index a8c94bdc..be912454 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -236,6 +236,15 @@ namespace Components Utils::Hook::Set(0x6832BA, 0xEB); Utils::Hook::Set(0x4BD190, 0xC3); + //*(BYTE*)0x4BB250 = 0x33; + //*(BYTE*)0x4BB251 = 0xC0; + //*(DWORD*)0x4BB252 = 0xC3909090; + + // remove 'impure stats' checking + Utils::Hook::Set(0x4BB250, 0x33); + Utils::Hook::Set(0x4BB251, 0xC0); + Utils::Hook::Set(0x4BB252, 0xC3909090); + // default sv_pure to 0 Utils::Hook::Set(0x4D3A74, 0); From 0c978d998052460b45a6dbc42943214cdd959761 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 30 Aug 2016 12:23:53 +0200 Subject: [PATCH 43/81] Clean minidump code --- src/Components/Modules/BitMessage.cpp | 155 +++++++++++++--------- src/Components/Modules/BitMessage.hpp | 21 ++- src/Components/Modules/Exception.cpp | 83 +++++------- src/Components/Modules/MinidumpUpload.cpp | 78 ++++++----- src/Components/Modules/MinidumpUpload.hpp | 8 +- src/Utils/String.cpp | 26 ++-- 6 files changed, 192 insertions(+), 179 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 64afe87f..69267074 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -8,37 +8,36 @@ using namespace Utils; namespace Components { - BitMessage* BitMessage::Singleton = NULL; + BitMRC* BitMessage::BMClient; BitMessage::BitMessage() { - if (Singleton != NULL) - throw new std::runtime_error("Only one instance of BitMessage allowed at the same time."); - - Singleton = this; - Logger::Print("Initializing BitMessage...\n"); - this->BMClient = new BitMRC(BITMESSAGE_OBJECT_STORAGE_FILENAME, BITMESSAGE_KEYS_FILENAME); - this->BMClient->init(); - this->BMClient->defaultTTL = 1 * 60 * 60; // 1 hour - if (this->BMClient->PrivAddresses.empty()) + BitMessage::BMClient = new BitMRC(BITMESSAGE_OBJECT_STORAGE_FILENAME, BITMESSAGE_KEYS_FILENAME); + BitMessage::BMClient->init(); + BitMessage::BMClient->defaultTTL = 1 * 60 * 60; // 1 hour + + if (BitMessage::BMClient->PrivAddresses.empty()) { if (!this->InitAddr()) { // Generate a random address ready to use throw std::runtime_error("Failed to prepare source address for exception handling"); } - this->BMClient->save(); + + BitMessage::BMClient->save(); } - this->BMClient->start(); + BitMessage::BMClient->start(); - Command::Add("bm_send", [](Command::Params params) { + Command::Add("bm_send", [](Command::Params params) + { if (params.Length() < 3) return; ustring pubAddrString; pubAddrString.fromString(params[1]); + PubAddr pubAddr; if (pubAddr.loadAddr(pubAddrString)) { @@ -46,7 +45,7 @@ namespace Components msg.fromString(params.Join(2)); Logger::Print("Sending message (this may take a while)...\n"); - Singleton->BMClient->sendMessage(msg, pubAddr, Singleton->BMClient->PrivAddresses[0]); + BitMessage::BMClient->sendMessage(msg, pubAddr, BitMessage::BMClient->PrivAddresses[0]); Logger::Print("Message sent.\n"); } else @@ -54,86 +53,105 @@ namespace Components Logger::Print("Address not correct!\n"); } }); - Command::Add("bm_sendb", [](Command::Params params) { + + Command::Add("bm_sendb", [](Command::Params params) + { if (params.Length() < 2) return; ustring msg; msg.appendVarString(params.Join(1)); Logger::Print("Sending broadcast...\n"); - Singleton->BMClient->sendBroadcast(msg, Singleton->BMClient->PrivAddresses[0]); + BitMessage::BMClient->sendBroadcast(msg, BitMessage::BMClient->PrivAddresses[0]); Logger::Print("Broadcast done.\n"); }); - Command::Add("bm_check_messages", [](Command::Params) { - while (Singleton->BMClient->new_messages.size() > 0) + + Command::Add("bm_check_messages", [](Command::Params) + { + while (BitMessage::BMClient->new_messages.size() > 0) { - auto msg = Singleton->BMClient->new_messages.pop(); - Logger::Print("New message:\nFrom: %s\nTo: %s\nMessage:\n%s\n", msg.from.c_str(), msg.to.c_str(), msg.info.c_str()); + auto msg = BitMessage::BMClient->new_messages.pop(); + Logger::Print("New message:\nFrom: %s\nTo: %s\nMessage:\n%s\n", msg.from.data(), msg.to.data(), msg.info.data()); } }); - Command::Add("bm_check_connections", [](Command::Params) { - std::shared_lock mlock(Singleton->BMClient->mutex_nodes); - for (auto& node : Singleton->BMClient->Nodes) + Command::Add("bm_check_connections", [](Command::Params) + { + std::shared_lock mlock(BitMessage::BMClient->mutex_nodes); + + for (auto& node : BitMessage::BMClient->Nodes) { switch (node->state) { case 0: // Not connected - Logger::Print("%s: Disconnected\n", node->Ip.c_str()); + Logger::Print("%s: Disconnected\n", node->Ip.data()); break; case 1: // Connecting - Logger::Print("%s: Connecting\n", node->Ip.c_str()); + Logger::Print("%s: Connecting\n", node->Ip.data()); break; case 2: // Connected - Logger::Print("%s: Connected\n", node->Ip.c_str()); + Logger::Print("%s: Connected\n", node->Ip.data()); break; case 3: // Reconnecting - Logger::Print("%s: Reconnecting\n", node->Ip.c_str()); + Logger::Print("%s: Reconnecting\n", node->Ip.data()); break; } } mlock.unlock(); }); - Command::Add("bm_check_privatekey", [](Command::Params) { - std::shared_lock mlock(Singleton->BMClient->mutex_priv); - if (Singleton->BMClient->PrivAddresses.empty()) { + Command::Add("bm_check_privatekey", [](Command::Params) + { + std::shared_lock mlock(BitMessage::BMClient->mutex_priv); + + if (BitMessage::BMClient->PrivAddresses.empty()) + { Logger::Print("No private key\n"); } else - for (auto& addr : Singleton->BMClient->PrivAddresses) + { + for (auto& addr : BitMessage::BMClient->PrivAddresses) { - Logger::Print("%s\n", addr.getAddress().c_str()); + Logger::Print("%s\n", addr.getAddress().data()); } + } mlock.unlock(); }); - Command::Add("bm_check_publickey", [](Command::Params) { - std::shared_lock mlock(Singleton->BMClient->mutex_pub); - if (Singleton->BMClient->PubAddresses.empty()) { + Command::Add("bm_check_publickey", [](Command::Params) + { + std::shared_lock mlock(BitMessage::BMClient->mutex_pub); + + if (BitMessage::BMClient->PubAddresses.empty()) + { Logger::Print("No public key\n"); } else - for (auto& addr : Singleton->BMClient->PubAddresses) + for (auto& addr : BitMessage::BMClient->PubAddresses) { - Logger::Print("%s (waiting for public key: %s)\n", addr.getAddress().c_str(), addr.waitingPubKey() ? "yes" : "no"); + Logger::Print("%s (waiting for public key: %s)\n", addr.getAddress().data(), addr.waitingPubKey() ? "yes" : "no"); } mlock.unlock(); }); - Command::Add("bm_save", [](Command::Params) { - Singleton->Save(); + + Command::Add("bm_save", [](Command::Params) + { + BitMessage::Save(); }); - Command::Add("bm_address_public", [](Command::Params params) { + + Command::Add("bm_address_public", [](Command::Params params) + { if (params.Length() < 2) return; ustring addre; addre.fromString(params.Join(1)); + PubAddr address; if (address.loadAddr(addre)) { Logger::Print("Asking public key!\n"); - Singleton->BMClient->getPubKey(address); + BitMessage::BMClient->getPubKey(address); Logger::Print("Asked! check publickey for news on that address!\n"); } else @@ -141,7 +159,9 @@ namespace Components Logger::Print("Address not correct!\n"); } }); - Command::Add("bm_address_broadcast", [](Command::Params params) { + + Command::Add("bm_address_broadcast", [](Command::Params params) + { if (params.Length() < 2) return; ustring addre; @@ -150,7 +170,7 @@ namespace Components if (address.loadAddr(addre)) { Logger::Print("Adding subscription!\n"); - Singleton->BMClient->addSubscription(address); + BitMessage::BMClient->addSubscription(address); } else { @@ -161,13 +181,13 @@ namespace Components BitMessage::~BitMessage() { - Singleton = NULL; - delete this->BMClient; + delete BitMessage::BMClient; + BitMessage::BMClient = nullptr; } void BitMessage::SetDefaultTTL(time_t ttl) { - this->BMClient->defaultTTL = ttl; + BitMessage::BMClient->defaultTTL = ttl; } bool BitMessage::RequestPublicKey(std::string targetAddress) @@ -184,17 +204,17 @@ namespace Components } // Request public key! - this->BMClient->getPubKey(pubAddr); + BitMessage::BMClient->getPubKey(pubAddr); return true; } PubAddr* BitMessage::FindPublicKey(PubAddr address) { - std::shared_lock mlock(Singleton->BMClient->mutex_pub); + std::shared_lock mlock(BitMessage::BMClient->mutex_pub); PubAddr* retval = nullptr; - for (auto& pubKey : BMClient->PubAddresses) + for (auto& pubKey : BitMessage::BMClient->PubAddresses) { if (pubKey.getVersion() == address.getVersion()) //check same version { @@ -206,6 +226,7 @@ namespace Components } } } + mlock.unlock(); return retval; } @@ -233,17 +254,19 @@ namespace Components (!resolvedAddress->waitingPubKey() && resolvedAddress->getPubEncryptionKey().empty())) { // Request public key - this->BMClient->getPubKey(address); + BitMessage::BMClient->getPubKey(address); resolvedAddress = FindPublicKey(address); } - this->Save(); + + BitMessage::Save(); // TODO: Wait for public key by using signaling in BitMRC, needs to be done directly in the fork. while (resolvedAddress->waitingPubKey()) { - sleep(1500); + std::this_thread::sleep_for(1500ms); } - this->Save(); + + BitMessage::Save(); return true; } @@ -262,7 +285,7 @@ namespace Components } // Subscribe! - this->BMClient->addSubscription(pubAddr); + BitMessage::BMClient->addSubscription(pubAddr); return true; } @@ -286,9 +309,14 @@ namespace Components // Send the message // TODO - Set mutex on priv when accessing first private address if (ttl > 0) - this->BMClient->sendMessage(messageU, pubAddr, this->BMClient->PrivAddresses[0], ttl); + { + BitMessage::BMClient->sendMessage(messageU, pubAddr, BitMessage::BMClient->PrivAddresses[0], ttl); + } else - this->BMClient->sendMessage(messageU, pubAddr, this->BMClient->PrivAddresses[0]); + { + BitMessage::BMClient->sendMessage(messageU, pubAddr, BitMessage::BMClient->PrivAddresses[0]); + } + return true; } @@ -300,27 +328,34 @@ namespace Components // TODO - Set mutex on priv when accessing first private address if (ttl > 0) - this->BMClient->sendBroadcast(messageU, this->BMClient->PrivAddresses[0], ttl); + { + BitMessage::BMClient->sendBroadcast(messageU, BitMessage::BMClient->PrivAddresses[0], ttl); + } else - this->BMClient->sendBroadcast(messageU, this->BMClient->PrivAddresses[0]); + { + BitMessage::BMClient->sendBroadcast(messageU, BitMessage::BMClient->PrivAddresses[0]); + } + return true; } bool BitMessage::InitAddr() { Logger::Print("Generating BM address...\n"); + Addr myAddress; if (!myAddress.generateRandom()) { return false; } - BMClient->addAddr(myAddress); + + BitMessage::BMClient->addAddr(myAddress); return true; } void BitMessage::Save() { - BMClient->save(); + BitMessage::BMClient->save(); } } diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index 2ab9a3ba..2d858973 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -17,20 +17,19 @@ namespace Components const char* GetName() { return "BitMessage"; }; #endif - void SetDefaultTTL(time_t ttl); - bool RequestPublicKey(std::string targetAddress); - bool WaitForPublicKey(std::string targetAddress); - bool Subscribe(std::string targetAddress); - bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0); - bool SendBroadcast(std::string message, time_t ttl = 0); - void Save(); + static void SetDefaultTTL(time_t ttl); + static bool RequestPublicKey(std::string targetAddress); + static bool WaitForPublicKey(std::string targetAddress); + static bool Subscribe(std::string targetAddress); + static bool SendMsg(std::string targetAddress, std::string message, time_t ttl = 0); + static bool SendBroadcast(std::string message, time_t ttl = 0); + static void Save(); - static BitMessage* Singleton; - BitMRC* BMClient; + static BitMRC* BMClient; private: - PubAddr* FindPublicKey(PubAddr addr); - bool InitAddr(); + static PubAddr* FindPublicKey(PubAddr addr); + static bool InitAddr(); }; } diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 1c0712e5..1822e1d7 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -20,8 +20,8 @@ namespace Components return EXCEPTION_CONTINUE_EXECUTION; } - auto minidump = MinidumpUpload::Singleton->CreateQueuedMinidump(ExceptionInfo); - if (minidump == NULL) + auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo); + if (!minidump) { OutputDebugStringA("Failed to create new minidump!"); Utils::OutputDebugLastError(); @@ -31,14 +31,13 @@ namespace Components delete minidump; } - switch (ExceptionInfo->ExceptionRecord->ExceptionCode) + if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - case EXCEPTION_STACK_OVERFLOW: Logger::Error("Termination because of a stack overflow.\n"); - break; - default: + } + else + { Logger::Error("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); - break; } //TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); @@ -118,71 +117,51 @@ namespace Components auto oldHandler = Exception::Hook(); Logger::Print("Old exception handler was 0x%010X.\n", oldHandler); }); + #pragma warning(push) #pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization Command::Add("debug_minidump", [](Command::Params) { // The following code was taken from VC++ 8.0 CRT (invarg.c: line 104) - EXCEPTION_RECORD ExceptionRecord; CONTEXT ContextRecord; - memset(&ContextRecord, 0, sizeof(CONTEXT)); + EXCEPTION_RECORD ExceptionRecord; + ZeroMemory(&ContextRecord, sizeof(CONTEXT)); -#ifdef _X86_ + __asm + { + mov [ContextRecord.Eax], eax + mov [ContextRecord.Ecx], ecx + mov [ContextRecord.Edx], edx + mov [ContextRecord.Ebx], ebx + mov [ContextRecord.Esi], esi + mov [ContextRecord.Edi], edi + mov word ptr [ContextRecord.SegSs], ss + mov word ptr [ContextRecord.SegCs], cs + mov word ptr [ContextRecord.SegDs], ds + mov word ptr [ContextRecord.SegEs], es + mov word ptr [ContextRecord.SegFs], fs + mov word ptr [ContextRecord.SegGs], gs - __asm { - mov dword ptr[ContextRecord.Eax], eax - mov dword ptr[ContextRecord.Ecx], ecx - mov dword ptr[ContextRecord.Edx], edx - mov dword ptr[ContextRecord.Ebx], ebx - mov dword ptr[ContextRecord.Esi], esi - mov dword ptr[ContextRecord.Edi], edi - mov word ptr[ContextRecord.SegSs], ss - mov word ptr[ContextRecord.SegCs], cs - mov word ptr[ContextRecord.SegDs], ds - mov word ptr[ContextRecord.SegEs], es - mov word ptr[ContextRecord.SegFs], fs - mov word ptr[ContextRecord.SegGs], gs pushfd - pop[ContextRecord.EFlags] + pop [ContextRecord.EFlags] } ContextRecord.ContextFlags = CONTEXT_CONTROL; -#pragma warning(push) -#pragma warning(disable:4311) - ContextRecord.Eip = (ULONG)_ReturnAddress(); - ContextRecord.Esp = (ULONG)_AddressOfReturnAddress(); -#pragma warning(pop) - ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress() - 1); - - -#elif defined (_IA64_) || defined (_AMD64_) - - /* Need to fill up the Context in IA64 and AMD64. */ - RtlCaptureContext(&ContextRecord); - -#else /* defined (_IA64_) || defined (_AMD64_) */ - - ZeroMemory(&ContextRecord, sizeof(ContextRecord)); - -#endif /* defined (_IA64_) || defined (_AMD64_) */ + ContextRecord.Eip = reinterpret_cast(_ReturnAddress()); + ContextRecord.Esp = reinterpret_cast(_AddressOfReturnAddress()); + ContextRecord.Ebp = *reinterpret_cast(_AddressOfReturnAddress()) - 1; ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD)); ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT; ExceptionRecord.ExceptionAddress = _ReturnAddress(); + EXCEPTION_POINTERS eptr; + eptr.ExceptionRecord = &ExceptionRecord; + eptr.ContextRecord = &ContextRecord; - EXCEPTION_RECORD* pExceptionRecord = new EXCEPTION_RECORD; - memcpy(pExceptionRecord, &ExceptionRecord, sizeof(EXCEPTION_RECORD)); - CONTEXT* pContextRecord = new CONTEXT; - memcpy(pContextRecord, &ContextRecord, sizeof(CONTEXT)); - - auto eptr = new EXCEPTION_POINTERS; - eptr->ExceptionRecord = pExceptionRecord; - eptr->ContextRecord = pContextRecord; - - Exception::ExceptionFilter(eptr); + Exception::ExceptionFilter(&eptr); }); #pragma warning(pop) } diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 3b869dde..8fca92c0 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -32,7 +32,7 @@ namespace Components if (!this->EnsureFileMapping()) return false; auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); - if (pBuf == NULL) + if (!pBuf) { Utils::OutputDebugLastError(); throw new std::runtime_error("Could not read minidump."); @@ -54,7 +54,7 @@ namespace Components if (!this->EnsureFileMapping()) return false; auto pBuf = MapViewOfFile(this->mapFileHandle, FILE_MAP_READ, 0, 0, 0); - if (pBuf == NULL) + if (!pBuf) { Utils::OutputDebugLastError(); throw new std::runtime_error("Could not read minidump."); @@ -80,7 +80,7 @@ namespace Components Minidump* Minidump::Create(std::string path, LPEXCEPTION_POINTERS exceptionInfo, int type) { Minidump* minidump = Minidump::Initialize(path); - if (minidump == NULL) return minidump; + if (!minidump) return minidump; // Do the dump generation MINIDUMP_EXCEPTION_INFORMATION ex = { GetCurrentThreadId(), exceptionInfo, FALSE }; @@ -88,15 +88,15 @@ namespace Components { Utils::OutputDebugLastError(); delete minidump; - return NULL; + return nullptr; } if (SetFilePointer(minidump->fileHandle, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { Utils::OutputDebugLastError(); delete minidump; - DeleteFileA(path.c_str()); - return NULL; + DeleteFileA(path.data()); + return nullptr; } return minidump; @@ -104,8 +104,7 @@ namespace Components Minidump* Minidump::Open(std::string path) { - Minidump* minidump = Minidump::Initialize(path, FILE_SHARE_READ); - return minidump; + return Minidump::Initialize(path, FILE_SHARE_READ); } bool Minidump::EnsureFileMapping() @@ -126,14 +125,15 @@ namespace Components { Minidump* minidump = new Minidump(); - minidump->fileHandle = CreateFileA(path.c_str(), + minidump->fileHandle = CreateFileA(path.data(), GENERIC_WRITE | GENERIC_READ, fileShare, NULL, (fileShare & FILE_SHARE_WRITE) > 0 ? OPEN_ALWAYS : OPEN_EXISTING, NULL, NULL); + if (minidump->fileHandle == NULL || minidump->fileHandle == INVALID_HANDLE_VALUE) { Utils::OutputDebugLastError(); delete minidump; - return NULL; + return nullptr; } return minidump; @@ -141,11 +141,11 @@ namespace Components #pragma endregion #pragma region Minidump uploader class implementation - MinidumpUpload* MinidumpUpload::Singleton = NULL; - const std::string MinidumpUpload::queuedMinidumpsFolder = "minidumps\\"; + #ifdef DISABLE_BITMESSAGE - const std::vector MinidumpUpload::targetUrls = { + const std::vector MinidumpUpload::targetUrls = + { "https://reich.io/upload.php", "https://hitlers.kz/upload.php" }; @@ -156,11 +156,6 @@ namespace Components MinidumpUpload::MinidumpUpload() { - if (Singleton != NULL) - throw new std::runtime_error("Can only create one instance at a time."); - - Singleton = this; - #if !defined(DEBUG) || defined(FORCE_MINIDUMP_UPLOAD) this->uploadThread = std::thread([&]() { this->UploadQueuedMinidumps(); }); #endif @@ -168,8 +163,6 @@ namespace Components MinidumpUpload::~MinidumpUpload() { - Singleton = NULL; - if (this->uploadThread.joinable()) { this->uploadThread.join(); @@ -178,9 +171,14 @@ namespace Components bool MinidumpUpload::EnsureQueuedMinidumpsFolderExists() { - BOOL success = CreateDirectoryA(queuedMinidumpsFolder.c_str(), NULL); - if (success != TRUE) success = GetLastError() == ERROR_ALREADY_EXISTS; - return success == TRUE; + BOOL success = CreateDirectoryA(MinidumpUpload::queuedMinidumpsFolder.data(), NULL); + + if (success != TRUE) + { + success = (GetLastError() == ERROR_ALREADY_EXISTS); + } + + return (success == TRUE); } Minidump* MinidumpUpload::CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType) @@ -206,7 +204,7 @@ namespace Components // Combine with queuedMinidumpsFolder char filename[MAX_PATH]; - PathCombineA(filename, queuedMinidumpsFolder.c_str(), Utils::String::VA("%s-" VERSION_STR "-%s.dmp", exeFileName, filenameFriendlyTime)); + PathCombineA(filename, MinidumpUpload::queuedMinidumpsFolder.data(), Utils::String::VA("%s-" VERSION_STR "-%s.dmp", exeFileName, filenameFriendlyTime)); // Generate the dump return Minidump::Create(filename, exceptionInfo, minidumpType); @@ -217,28 +215,28 @@ namespace Components #ifndef DISABLE_BITMESSAGE // Preload public key for our target that will receive minidumps Logger::Print("About to send request for public key for minidump upload address.\n"); - if (!BitMessage::Singleton->RequestPublicKey(MinidumpUpload::targetAddress)) + if (!BitMessage::RequestPublicKey(MinidumpUpload::targetAddress)) { Logger::Error("Failed to request public key for minidump collection address.\n"); } Logger::Print("Waiting for public key for minidump upload address.\n"); - if (!BitMessage::Singleton->WaitForPublicKey(MinidumpUpload::targetAddress)) + if (!BitMessage::WaitForPublicKey(MinidumpUpload::targetAddress)) { Logger::Error("Failed to fetch public key for minidump collection address.\n"); } #endif // Check if folder exists - if (!PathIsDirectoryA(queuedMinidumpsFolder.c_str())) + if (!PathIsDirectoryA(MinidumpUpload::queuedMinidumpsFolder.data())) { // Nothing to upload Logger::Print("No minidumps to upload.\n"); - return PathFileExistsA(queuedMinidumpsFolder.c_str()) == FALSE; + return PathFileExistsA(MinidumpUpload::queuedMinidumpsFolder.data()) == FALSE; } // Walk through directory and search for valid minidumps WIN32_FIND_DATAA ffd; - HANDLE hFind = FindFirstFileA(Utils::String::VA("%s\\*.dmp", queuedMinidumpsFolder), &ffd); + HANDLE hFind = FindFirstFileA(Utils::String::VA("%s\\*.dmp", MinidumpUpload::queuedMinidumpsFolder), &ffd); if (hFind != INVALID_HANDLE_VALUE) { do @@ -247,12 +245,12 @@ namespace Components continue; // ignore directory char fullPath[MAX_PATH_SIZE]; - PathCombineA(fullPath, queuedMinidumpsFolder.c_str(), ffd.cFileName); + PathCombineA(fullPath, MinidumpUpload::queuedMinidumpsFolder.data(), ffd.cFileName); // Try to open this minidump Logger::Print("Trying to upload %s...\n", fullPath); auto minidump = Minidump::Open(fullPath); - if (minidump == NULL) + if (!minidump) { Logger::Print("Couldn't open minidump.\n"); continue; // file can't be opened @@ -297,16 +295,16 @@ namespace Components std::string compressedMinidump = minidump->ToString(); - Logger::Print("Compressing minidump %s (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); + Logger::Print("Compressing minidump %s (currently %d bytes)...\n", id.data(), compressedMinidump.size()); compressedMinidump = Utils::Compression::ZLib::Compress(compressedMinidump); #ifndef DISABLE_BASE128 - Logger::Print("Encoding minidump %s (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); + Logger::Print("Encoding minidump %s (currently %d bytes)...\n", id.data(), compressedMinidump.size()); extraHeaders["Encoding"] = "base128"; compressedMinidump = Utils::String::EncodeBase128(compressedMinidump); #endif - Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", id.c_str(), compressedMinidump.size()); + Logger::Print("Minidump %s now prepared for uploading (currently %d bytes)...\n", id.data(), compressedMinidump.size()); #ifdef DISABLE_BITMESSAGE for (auto& targetUrl : targetUrls) @@ -348,19 +346,19 @@ namespace Components return false; #else // BitMessage has a max msg size that is somewhere around 220 KB, split it up as necessary! - auto totalParts = compressedMinidump.size() / this->maxSegmentSize + 1; + auto totalParts = compressedMinidump.size() / MinidumpUpload::maxSegmentSize + 1; extraHeaders.insert({ "Parts", Utils::String::VA("%d",totalParts) }); - for (size_t offset = 0; offset < compressedMinidump.size(); offset += this->maxSegmentSize) + for (size_t offset = 0; offset < compressedMinidump.size(); offset += MinidumpUpload::maxSegmentSize) { auto extraPartHeaders = extraHeaders; - auto part = compressedMinidump.substr(offset, std::min(this->maxSegmentSize, compressedMinidump.size() - offset)); - auto partNum = offset / this->maxSegmentSize + 1; + auto part = compressedMinidump.substr(offset, std::min(MinidumpUpload::maxSegmentSize, compressedMinidump.size() - offset)); + auto partNum = offset / MinidumpUpload::maxSegmentSize + 1; extraPartHeaders.insert({ "Part", Utils::String::VA("%d", partNum) }); - Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", id.c_str(), partNum, totalParts, part.size()); - BitMessage::Singleton->SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); + Logger::Print("Uploading minidump %s (part %d out of %d, %d bytes)...\n", id.data(), partNum, totalParts, part.size()); + BitMessage::SendMsg(MinidumpUpload::targetAddress, MinidumpUpload::Encode(part, extraPartHeaders)); } return true; diff --git a/src/Components/Modules/MinidumpUpload.hpp b/src/Components/Modules/MinidumpUpload.hpp index b2c5f9c3..6c686953 100644 --- a/src/Components/Modules/MinidumpUpload.hpp +++ b/src/Components/Modules/MinidumpUpload.hpp @@ -43,16 +43,14 @@ namespace Components ~MinidumpUpload(); // Uploads the given minidump. - bool Upload(Minidump* minidump); + static bool Upload(Minidump* minidump); // Generates a new minidump and saves it to the folder for queued minidumps. - Minidump* CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType = MiniDumpTiny); + static Minidump* CreateQueuedMinidump(LPEXCEPTION_POINTERS exceptionInfo, int minidumpType = MiniDumpTiny); // Browses the folder for queued minidumps and uploads each queued minidump. // On Release builds this will also delete every successfully uploaded minidump. - bool UploadQueuedMinidumps(); - - static MinidumpUpload* Singleton; + static bool UploadQueuedMinidumps(); private: std::thread uploadThread; diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index f2c8c7e3..5d33b7ef 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -120,46 +120,50 @@ namespace Utils } // Encodes a given string in Base64 - std::string EncodeBase64(const char* input, const unsigned long inputSize) { + std::string EncodeBase64(const char* input, const unsigned long inputSize) + { unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16); unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory - base64_encode((unsigned char*)input, inputSize, outbuf, &outlen); + base64_encode(reinterpret_cast(const_cast(input)), inputSize, outbuf, &outlen); std::string ret((char*)outbuf, outlen); delete[] outbuf; return ret; } // Encodes a given string in Base64 - std::string EncodeBase64(const std::string& input) { - return EncodeBase64(input.c_str(), input.size()); + std::string EncodeBase64(const std::string& input) + { + return EncodeBase64(input.data(), input.size()); } #ifndef DISABLE_BASE128 // Encodes a given string in Base128 - std::string EncodeBase128(const std::string& input) { - auto encoder = new base128(); + std::string EncodeBase128(const std::string& input) + { + base128 encoder; + void* inbuffer = const_cast(input.data()); - char* buffer = encoder->encode(inbuffer, input.size()); + char* buffer = encoder.encode(inbuffer, input.size()); /* Interesting to see that the buffer returned by the encoder is not a standalone string copy but instead is a pointer to the internal "encoded" field of the encoder. So if you deinitialize the encoder that string will probably become garbage. */ std::string retval(buffer); - delete encoder; return retval; } #endif // Generates a UUID and returns the string representation of it - std::string GenerateUUIDString() { + std::string GenerateUUIDString() + { // Generate UUID data UUID uuid; UuidCreate(&uuid); // Convert to string representation - char* strdata = NULL; - UuidToStringA(&uuid, (RPC_CSTR*)&strdata); + char* strdata = nullptr; + UuidToStringA(&uuid, reinterpret_cast(&strdata)); return std::string(strdata); } } From b0ffeeb3348cf696aec315c3a7ae5d81b88ba675 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 30 Aug 2016 17:51:30 +0200 Subject: [PATCH 44/81] Obfuscate default nodes --- deps/mongoose | 2 +- deps/protobuf | 2 +- src/Components/Modules/Node.cpp | 46 ++++++++++++++++++++++++--------- src/Utils/Compression.cpp | 12 ++++++--- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/deps/mongoose b/deps/mongoose index b3fb21da..844c7787 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit b3fb21dacccfb08b046b73740eec52cd66e944de +Subproject commit 844c7787f9d86715c80ab56f4f28d1b808df5341 diff --git a/deps/protobuf b/deps/protobuf index 3d9d1a12..e721ce66 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 3d9d1a1255583bac550f7bf94f3016e8c238fa5e +Subproject commit e721ce66cfeaa5d8790ecba09c73d1ef399887d2 diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 2fcd22a5..7c6e8e6f 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -8,19 +8,13 @@ namespace Components void Node::LoadNodePreset() { + Proto::Node::List list; FileSystem::File defaultNodes("nodes_default.dat"); - if (!defaultNodes.Exists()) return; + if (!defaultNodes.Exists() || !list.ParseFromString(Utils::Compression::ZLib::Decompress(defaultNodes.GetBuffer()))) return; - auto buffer = defaultNodes.GetBuffer(); - Utils::String::Replace(buffer, "\r", ""); - - auto nodes = Utils::String::Explode(buffer, '\n'); - for (auto node : nodes) + for (int i = 0; i < list.address_size(); ++i) { - if (!node.empty()) - { - Node::AddNode(node); - } + Node::AddNode(list.address(i)); } } @@ -28,7 +22,7 @@ namespace Components { Proto::Node::List list; std::string nodes = Utils::IO::ReadFile("players/nodes.dat"); - if (nodes.empty() || !list.ParseFromString(nodes)) return; + if (nodes.empty() || !list.ParseFromString(Utils::Compression::ZLib::Decompress(nodes))) return; for (int i = 0; i < list.address_size(); ++i) { @@ -60,7 +54,10 @@ namespace Components } CreateDirectoryW(L"players", NULL); - Utils::IO::WriteFile("players/nodes.dat", list.SerializeAsString()); + + + + Utils::IO::WriteFile("players/nodes.dat", Utils::Compression::ZLib::Compress(list.SerializeAsString())); } Node::NodeEntry* Node::FindNode(Network::Address address) @@ -907,6 +904,31 @@ namespace Components auto duration = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - startTime).count(); Logger::Print("took %llims\n", duration); + printf("Testing ZLib compression..."); + + std::string test = fmt::sprintf("%c", Utils::Cryptography::Rand::GenerateInt()); + + for (int i = 0; i < 21; ++i) + { + std::string compressed = Utils::Compression::ZLib::Compress(test); + std::string decompressed = Utils::Compression::ZLib::Decompress(compressed); + + if (test != decompressed) + { + printf("Error\n"); + printf("Compressing %d bytes and decompressing failed!\n", test.size()); + return false; + } + + auto size = test.size(); + for (unsigned int j = 0; j < size; ++j) + { + test.append(fmt::sprintf("%c", Utils::Cryptography::Rand::GenerateInt())); + } + } + + printf("Success\n"); + return true; } } diff --git a/src/Utils/Compression.cpp b/src/Utils/Compression.cpp index 02c85351..4eec358d 100644 --- a/src/Utils/Compression.cpp +++ b/src/Utils/Compression.cpp @@ -6,8 +6,13 @@ namespace Utils { std::string ZLib::Compress(std::string data) { + Utils::Memory::Allocator allocator; unsigned long length = (data.size() * 2); - char* buffer = Utils::Memory::AllocateArray(length); + + // Make sure the buffer is large enough + if (length < 100) length *= 10; + + char* buffer = allocator.AllocateArray(length); if (compress2(reinterpret_cast(buffer), &length, reinterpret_cast(const_cast(data.data())), data.size(), Z_BEST_COMPRESSION) != Z_OK) { @@ -18,8 +23,6 @@ namespace Utils data.clear(); data.append(buffer, length); - Utils::Memory::Free(buffer); - return data; } @@ -44,6 +47,7 @@ namespace Utils { stream.avail_in = std::min(static_cast(CHUNK), data.size() - (dataPtr - data.data())); stream.next_in = reinterpret_cast(dataPtr); + dataPtr += stream.avail_in; do { @@ -51,7 +55,7 @@ namespace Utils stream.next_out = dest; ret = inflate(&stream, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) + if (ret != Z_OK && ret != Z_STREAM_END) { inflateEnd(&stream); return ""; From 04a640d81d23188403654381ff0a558508160664 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 30 Aug 2016 17:53:15 +0200 Subject: [PATCH 45/81] Ignore dirty module --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index d33568ec..d9402510 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,6 +32,7 @@ [submodule "deps/bitmrc"] path = deps/bitmrc url = git@github.com:iw4x-dev-urandom/BitMRC.git + ignore = dirty [submodule "deps/base128"] path = deps/base128 url = https://github.com/seizu/base128.git From a21c9283647290f27deb8c02c793aeb14b1e9989 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 30 Aug 2016 18:31:57 +0200 Subject: [PATCH 46/81] Temporarily --- deps/protobuf | 2 +- premake/bitmrc.lua | 2 ++ premake/libcryptopp.lua | 22 ++++++++++++++++++---- premake/sqlite3.lua | 10 +++++----- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/deps/protobuf b/deps/protobuf index e721ce66..8c936063 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit e721ce66cfeaa5d8790ecba09c73d1ef399887d2 +Subproject commit 8c936063570e5ede2ac41cf49aefe1075f1c7251 diff --git a/premake/bitmrc.lua b/premake/bitmrc.lua index 2bd48484..77db6a4e 100644 --- a/premake/bitmrc.lua +++ b/premake/bitmrc.lua @@ -49,6 +49,8 @@ function bitmrc.project() path.join(bitmrc.settings.source, "BitMRC/main.*"), path.join(bitmrc.settings.source, "BitMRC/class.*"), path.join(bitmrc.settings.source, "BitMRC/tests/**"), + + path.join(bitmrc.settings.source, "BitMRC/Storage/Storable.cpp"), } -- dependencies diff --git a/premake/libcryptopp.lua b/premake/libcryptopp.lua index d0a05021..c2116497 100644 --- a/premake/libcryptopp.lua +++ b/premake/libcryptopp.lua @@ -21,6 +21,11 @@ end function libcryptopp.includes() if not libcryptopp.settings then error("Run libcryptopp.setup first") end + + --defines { "CRYPTOPP_IMPORTS" } + + --filter "*Static" + -- removedefines { "CRYPTOPP_IMPORTS" } filter "Debug*" defines { "_DEBUG" } @@ -102,6 +107,12 @@ function libcryptopp.project() path.join(libcryptopp.settings.source, "fipsalgt.*"), path.join(libcryptopp.settings.source, "cryptlib_bds.*"), path.join(libcryptopp.settings.source, "validat*.*"), + + -- Remove linker warnings + path.join(libcryptopp.settings.source, "strciphr.cpp"), + path.join(libcryptopp.settings.source, "simple.cpp"), + path.join(libcryptopp.settings.source, "polynomi.cpp"), + path.join(libcryptopp.settings.source, "algebra.cpp"), } -- Pre-compiled header @@ -117,13 +128,16 @@ function libcryptopp.project() "MASM", --"CustomProtoBuildTool", } - - kind "SharedLib" - filter "*Static" + + -- SharedLib needs that + --links { "Ws2_32" } + + --kind "SharedLib" + --filter "*Static" kind "StaticLib" filter "kind:SharedLib" - defines { "CRYPTOPP_IMPORTS" } + defines { "CRYPTOPP_EXPORTS" } filter "architecture:x86" exceptionhandling "SEH" diff --git a/premake/sqlite3.lua b/premake/sqlite3.lua index 730eea78..a3d12e4f 100644 --- a/premake/sqlite3.lua +++ b/premake/sqlite3.lua @@ -45,10 +45,10 @@ function sqlite3.project() -- not our code, ignore POSIX usage warnings for now warnings "Off" - kind "SharedLib" - filter "*Static" + --kind "SharedLib" + --filter "*Static" kind "StaticLib" - filter "kind:StaticLib" - defines { "_LIB" } - removedefines { "_USRDLL", "_DLL" } + --filter "kind:StaticLib" + -- defines { "_LIB" } + -- removedefines { "_USRDLL", "_DLL" } end From f887f03231b022a41e8d78e5dcf1d2423c34bd8e Mon Sep 17 00:00:00 2001 From: /dev/root Date: Tue, 30 Aug 2016 19:27:14 +0200 Subject: [PATCH 47/81] fixed Issue pushed console output 4 up --- src/Components/Modules/Console.cpp | 3 + src/Components/Modules/Console.hpp | 122 ++++++++++++++--------------- 2 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 5b0da036..0bbc4057 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -308,6 +308,9 @@ namespace Components wrefresh(Console::InfoWindow); wrefresh(Console::InputWindow); + // 3 Lines do not autoscroll, 1 has a linebreak -> skip 4 lines when initializing + Console::ScrollOutput(4); + Console::RefreshOutput(); } diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index 429e8a74..73a9e0cf 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -1,63 +1,63 @@ -#define OUTPUT_HEIGHT 250 -#define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2)) - -namespace Components -{ - class Console : public Component - { - public: - Console(); +#define OUTPUT_HEIGHT 250 +#define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2)) + +namespace Components +{ + class Console : public Component + { + public: + Console(); ~Console(); -#ifdef DEBUG - const char* GetName() { return "Console"; }; -#endif - - private: - static void ToggleConsole(); - static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); - - private: - // Text-based console stuff - static WINDOW* OutputWindow; - static WINDOW* InputWindow; - static WINDOW* InfoWindow; - - static int Width; - static int Height; - - static int OutputTop; - static int OutBuffer; - static int LastRefresh; - - static char LineBuffer[1024]; - static char LineBuffer2[1024]; - static int LineBufferIndex; - - static bool HasConsole; - - static std::thread ConsoleThread; - - static Game::SafeArea OriginalSafeArea; - - static void ShowPrompt(); - static void RefreshStatus(); - static void RefreshOutput(); - static void ScrollOutput(int amount); - - static const char* Input(); - static void Print(const char* message); - static void Error(const char* format, ...); - static void Create(); - static void Destroy(); - - static void StdOutPrint(const char* message); - static void StdOutError(const char* format, ...); - - static void ConsoleRunner(); - - static void DrawSolidConsoleStub(); - static void StoreSafeArea(); - static void RestoreSafeArea(); - }; -} +#ifdef DEBUG + const char* GetName() { return "Console"; }; +#endif + + private: + static void ToggleConsole(); + static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); + + private: + // Text-based console stuff + static WINDOW* OutputWindow; + static WINDOW* InputWindow; + static WINDOW* InfoWindow; + + static int Width; + static int Height; + + static int OutputTop; + static int OutBuffer; + static int LastRefresh; + + static char LineBuffer[1024]; + static char LineBuffer2[1024]; + static int LineBufferIndex; + + static bool HasConsole; + + static std::thread ConsoleThread; + + static Game::SafeArea OriginalSafeArea; + + static void ShowPrompt(); + static void RefreshStatus(); + static void RefreshOutput(); + static void ScrollOutput(int amount); + + static const char* Input(); + static void Print(const char* message); + static void Error(const char* format, ...); + static void Create(); + static void Destroy(); + + static void StdOutPrint(const char* message); + static void StdOutError(const char* format, ...); + + static void ConsoleRunner(); + + static void DrawSolidConsoleStub(); + static void StoreSafeArea(); + static void RestoreSafeArea(); + }; +} From 125e9c4795c22d87267936ccec28eb4cac06fb1c Mon Sep 17 00:00:00 2001 From: /dev/root Date: Tue, 30 Aug 2016 19:36:57 +0200 Subject: [PATCH 48/81] Issue fixed comment --- src/Components/Modules/Console.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 0bbc4057..ee5073ea 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -308,7 +308,7 @@ namespace Components wrefresh(Console::InfoWindow); wrefresh(Console::InputWindow); - // 3 Lines do not autoscroll, 1 has a linebreak -> skip 4 lines when initializing + // 4 Lines do not autoscroll/are multiline -> skip 4 lines when initializing Console::ScrollOutput(4); Console::RefreshOutput(); From 3271a6d510a0fc974c09748bc72dc117a7c917d4 Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Tue, 30 Aug 2016 21:35:58 +0200 Subject: [PATCH 49/81] Actually fix the console scrolling issue. We just let pdcurses do it for us, PROPERLY! --- src/Components/Modules/Console.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index ee5073ea..dc3f19d6 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -279,11 +279,12 @@ namespace Components raw(); noecho(); - Console::OutputWindow = newpad(OUTPUT_HEIGHT, Console::Width); + Console::OutputWindow = newpad(Console::Height - 1, Console::Width); Console::InputWindow = newwin(1, Console::Width, Console::Height - 1, 0); Console::InfoWindow = newwin(1, Console::Width, 0, 0); scrollok(Console::OutputWindow, true); + idlok(Console::OutputWindow, true); scrollok(Console::InputWindow, true); nodelay(Console::InputWindow, true); keypad(Console::InputWindow, true); @@ -308,9 +309,6 @@ namespace Components wrefresh(Console::InfoWindow); wrefresh(Console::InputWindow); - // 4 Lines do not autoscroll/are multiline -> skip 4 lines when initializing - Console::ScrollOutput(4); - Console::RefreshOutput(); } @@ -346,11 +344,6 @@ namespace Components const char* p = message; while (*p != '\0') { - if (*p == '\n') - { - Console::ScrollOutput(1); - } - if (*p == '^') { char color; From 8aae51db647804d8699c6623b4739e71e5070fea Mon Sep 17 00:00:00 2001 From: /dev/urandom Date: Tue, 30 Aug 2016 23:55:11 +0200 Subject: [PATCH 50/81] Switch to semantic versioning via Git with fallback to old version string format. --- premake5.lua | 106 ++++++++++++++-------- src/Components/Modules/Console.cpp | 6 +- src/Components/Modules/MinidumpUpload.cpp | 4 +- src/Components/Modules/Party.cpp | 2 +- src/Components/Modules/QuickPatch.cpp | 14 +-- src/Components/Modules/ServerInfo.cpp | 2 +- src/Components/Modules/ServerList.cpp | 2 +- src/Components/Modules/Singleton.cpp | 2 +- src/Resource.rc | 9 +- src/STDInclude.hpp | 14 +-- 10 files changed, 90 insertions(+), 71 deletions(-) diff --git a/premake5.lua b/premake5.lua index b68220b5..476a647a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,3 +1,5 @@ +gitVersioningCommand = "git describe --tags --dirty --always" + -- Quote the given string input as a C string function cstrquote(value) result = value:gsub("\\", "\\\\") @@ -11,6 +13,19 @@ function cstrquote(value) return result end +-- Converts tags in "vX.X.X" format to X,X,X. +-- In the case where the format does not work fall back to old 4,2,REVISION. +function vertonum(value, vernumber) + vernum = {} + for num in string.gmatch(value, "%d+") do + table.insert(vernum, num) + end + if #vernum < 3 then + return "4,2," .. vernumber + end + return vernum[1] .. "," .. vernum[2] .. "," .. vernum[3] +end + -- Option to allow copying the DLL file to a custom folder after build newoption { trigger = "copy-to", @@ -57,10 +72,12 @@ newoption { trigger = "disable-bitmessage", description = "Disable use of BitMessage completely." } + newoption { trigger = "disable-node-log", description = "Disable debugging messages for Nodes in Debug builds." } + newoption { trigger = "disable-base128", description = "Disable debugging messages for Nodes in Debug builds." @@ -70,12 +87,12 @@ newaction { trigger = "version", description = "Returns the version string for the current commit of the source code.", onWorkspace = function(wks) - -- get revision number via git - local proc = assert(io.popen("git rev-list --count HEAD", "r")) - local revNumber = assert(proc:read('*a')):gsub("%s+", "") + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") proc:close() - print(revNumber) + print(gitDescribeOutput) os.exit(0) end } @@ -87,60 +104,73 @@ newaction { -- get revision number via git local proc = assert(io.popen("git rev-list --count HEAD", "r")) local revNumber = assert(proc:read('*a')):gsub("%s+", "") + + -- get current version via git + local proc = assert(io.popen(gitVersioningCommand, "r")) + local gitDescribeOutput = assert(proc:read('*a')):gsub("%s+", "") proc:close() -- get whether this is a clean revision (no uncommitted changes) proc = assert(io.popen("git status --porcelain", "r")) - local revClean = 1 - local revCleanSuffix = "" - if assert(proc:read('*a')) ~= "" then - revClean = 0 - revCleanSuffix = " (unclean)" - end + local revDirty = (assert(proc:read('*a')) ~= "") + if revDirty then revDirty = 1 else revDirty = 0 end proc:close() -- get current tag name (aka milestone for now) - proc = assert(io.popen("git tag")) + proc = assert(io.popen("git describe --tags --abbrev=0")) local tagName = assert(proc:read('*l')) -- get old version number from version.hpp if any - local oldRevNumber = "(none)" - local oldRevClean = 1 - local oldRevCleanSuffix = "" - local oldVersionHeader = io.open(wks.location .. "/src/version.hpp", "r") - if oldVersionHeader ~=nil then - local oldVersionHeaderContent = assert(oldVersionHeader:read('*a')) - oldRevNumber = string.match(oldVersionHeaderContent, "#define REVISION (%d+)") - if oldRevNumber == nil then - -- old version.hpp format? - oldRevNumber = "(none)" + local oldVersion = "(none)" + local oldVersionHeader = io.open(wks.location .. "/src/version.h", "r") + if oldVersionHeader ~= nil then + local oldVersionHeaderContent = assert(oldVersionHeader:read('*l')) + while oldVersionHeaderContent do + m = string.match(oldVersionHeaderContent, "#define GIT_DESCRIBE (.+)%s*$") + if m ~= nil then + oldVersion = m + end + + oldVersionHeaderContent = oldVersionHeader:read('*l') end - oldRevClean = string.match(oldVersionHeaderContent, "#define REVISION_CLEAN (%d+)") - if oldRevClean == nil then - -- old version.hpp format? - oldRevClean = 1 - elseif oldRevClean ~= "1" then - oldRevClean = 0 - else - oldRevClean = 1 - end - end - if oldRevClean == 0 then - oldRevCleanSuffix = " (unclean)" end -- generate version.hpp with a revision number if not equal - if oldRevNumber ~= revNumber or oldRevClean ~= revClean then - print ("Update " .. oldRevNumber .. oldRevCleanSuffix .. " -> " .. revNumber .. revCleanSuffix) - local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) + gitDescribeOutputQuoted = cstrquote(gitDescribeOutput) + if oldVersion ~= gitDescribeOutputQuoted then + print ("Update " .. oldVersion .. " -> " .. gitDescribeOutputQuoted) + local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) versionHeader:write("/*\n") versionHeader:write(" * Automatically generated by premake5.\n") versionHeader:write(" * Do not touch, you fucking moron!\n") versionHeader:write(" */\n") versionHeader:write("\n") + versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") + versionHeader:write("#define GIT_DIRTY " .. revDirty .. "\n") + versionHeader:write("#define GIT_TAG " .. cstrquote(tagName) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Legacy definitions (needed for update check)\n") versionHeader:write("#define REVISION " .. revNumber .. "\n") - versionHeader:write("#define REVISION_CLEAN " .. revClean .. "\n") - versionHeader:write("#define MILESTONE " .. cstrquote(tagName) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Version transformed for RC files\n") + versionHeader:write("#define VERSION_RC " .. vertonum(tagName, revNumber) .. "\n") + versionHeader:write("\n") + versionHeader:write("// Alias definitions\n") + versionHeader:write("#define VERSION GIT_DESCRIBE\n") + versionHeader:write("#define SHORTVERSION GIT_TAG\n") + versionHeader:close() + local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) + versionHeader:write("/*\n") + versionHeader:write(" * Automatically generated by premake5.\n") + versionHeader:write(" * Do not touch, you fucking moron!\n") + versionHeader:write(" *\n") + versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") + versionHeader:write(" *\n") + versionHeader:write(" * The Resource Compiler will ignore any content from C++ header files if they're not from STDInclude.hpp.\n") + versionHeader:write(" * That's the reason why we now place all version info in version.h instead.\n") + versionHeader:write(" */\n") + versionHeader:write("\n") + versionHeader:write("#include \".\\version.h\"\n") versionHeader:close() end end diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index dc3f19d6..6b25113d 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -76,14 +76,14 @@ namespace Components } else if(IsWindow(*reinterpret_cast(0x64A3288)) != FALSE) { - SetWindowTextA(*reinterpret_cast(0x64A3288), Utils::String::VA("IW4x(r" REVISION_STR REVISION_SUFFIX ") : %s", hostname.data())); + SetWindowTextA(*reinterpret_cast(0x64A3288), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data())); } } void Console::ShowPrompt() { wattron(Console::InputWindow, COLOR_PAIR(10) | A_BOLD); - wprintw(Console::InputWindow, "%s> ", VERSION_STR); + wprintw(Console::InputWindow, "%s> ", VERSION); } void Console::RefreshOutput() @@ -477,7 +477,7 @@ namespace Components Console::Console() { // Console '%s: %s> ' string - Utils::Hook::Set(0x5A44B4, "IW4x: r" REVISION_STR "> "); + Utils::Hook::Set(0x5A44B4, "IW4x: " VERSION "> "); // Internal console Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).Install()->Quick(); diff --git a/src/Components/Modules/MinidumpUpload.cpp b/src/Components/Modules/MinidumpUpload.cpp index 8fca92c0..89da69a8 100644 --- a/src/Components/Modules/MinidumpUpload.cpp +++ b/src/Components/Modules/MinidumpUpload.cpp @@ -204,7 +204,7 @@ namespace Components // Combine with queuedMinidumpsFolder char filename[MAX_PATH]; - PathCombineA(filename, MinidumpUpload::queuedMinidumpsFolder.data(), Utils::String::VA("%s-" VERSION_STR "-%s.dmp", exeFileName, filenameFriendlyTime)); + PathCombineA(filename, MinidumpUpload::queuedMinidumpsFolder.data(), Utils::String::VA("%s-" VERSION "-%s.dmp", exeFileName, filenameFriendlyTime)); // Generate the dump return Minidump::Create(filename, exceptionInfo, minidumpType); @@ -372,7 +372,7 @@ namespace Components if (extraHeaders.find("Encoding") == extraHeaders.end()) extraHeaders["Encoding"] = "raw"; - extraHeaders["Version"] = VERSION_STR; + extraHeaders["Version"] = VERSION; output << "-----BEGIN " << marker << "-----\n"; diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 7922d1c8..3f467b8c 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -308,7 +308,7 @@ namespace Components info.Set("clients", fmt::sprintf("%i", clientCount)); info.Set("sv_maxclients", fmt::sprintf("%i", maxclientCount)); info.Set("protocol", fmt::sprintf("%i", PROTOCOL)); - info.Set("shortversion", VERSION_STR); + info.Set("shortversion", SHORTVERSION); info.Set("checksum", fmt::sprintf("%d", Game::Sys_Milliseconds())); info.Set("mapname", Dvar::Var("mapname").Get()); info.Set("isPrivate", (Dvar::Var("g_password").Get().size() ? "1" : "0")); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index be912454..01019f39 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -173,26 +173,26 @@ namespace Components Utils::Hook::Set(0x6431D1, BASEGAME); // UI version string - Utils::Hook::Set(0x43F73B, "IW4x: r" REVISION_STR REVISION_SUFFIX "-" MILESTONE); + Utils::Hook::Set(0x43F73B, "IW4x: " VERSION); // console version string - Utils::Hook::Set(0x4B12BB, "IW4x r" REVISION_STR REVISION_SUFFIX "-" MILESTONE " (built " __DATE__ " " __TIME__ ")"); + Utils::Hook::Set(0x4B12BB, "IW4x " VERSION " (built " __DATE__ " " __TIME__ ")"); // version string - Utils::Hook::Set(0x60BD56, "IW4x (r" REVISION_STR REVISION_SUFFIX ")"); + Utils::Hook::Set(0x60BD56, "IW4x (" VERSION ")"); // console title if (ZoneBuilder::IsEnabled()) { - Utils::Hook::Set(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): ZoneBuilder"); + Utils::Hook::Set(0x4289E8, "IW4x (" VERSION "): ZoneBuilder"); } else if (Dedicated::IsEnabled()) { - Utils::Hook::Set(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Dedicated"); + Utils::Hook::Set(0x4289E8, "IW4x (r" VERSION "): Dedicated"); } else { - Utils::Hook::Set(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Console"); + Utils::Hook::Set(0x4289E8, "IW4x (r" VERSION "): Console"); } // window title @@ -202,7 +202,7 @@ namespace Components Utils::Hook::Set(0x4D378B, "IW4Host"); // shortversion - Utils::Hook::Set(0x60BD91, VERSION_STR); + Utils::Hook::Set(0x60BD91, SHORTVERSION); // console logo Utils::Hook::Set(0x428A66, BASEGAME "/images/logo.bmp"); diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 8a3151e7..695d4470 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -115,7 +115,7 @@ namespace Components info.Set("gamename", "IW4"); info.Set("sv_maxclients", fmt::sprintf("%i", maxclientCount)); info.Set("protocol", fmt::sprintf("%i", PROTOCOL)); - info.Set("shortversion", VERSION_STR); + info.Set("shortversion", SHORTVERSION); info.Set("mapname", Dvar::Var("mapname").Get()); info.Set("isPrivate", (Dvar::Var("g_password").Get().empty() ? "0" : "1")); info.Set("checksum", fmt::sprintf("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(fmt::sprintf("%u", Game::Sys_Milliseconds())))); diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index 9cff72d7..06aa5454 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -449,7 +449,7 @@ namespace Components if (info.Get("gamename") == "IW4" && server.MatchType #ifndef DEBUG - && server.Shortversion == VERSION_STR + && server.Shortversion == SHORTVERSION #endif ) { diff --git a/src/Components/Modules/Singleton.cpp b/src/Components/Modules/Singleton.cpp index 7c8d5956..bb13be4f 100644 --- a/src/Components/Modules/Singleton.cpp +++ b/src/Components/Modules/Singleton.cpp @@ -13,7 +13,7 @@ namespace Components { if (Flags::HasFlag("version")) { - printf("IW4x r" REVISION_STR "-" MILESTONE " (built " __DATE__ " " __TIME__ ")\n"); + printf("IW4x " VERSION " (built " __DATE__ " " __TIME__ ")\n"); ExitProcess(0); } diff --git a/src/Resource.rc b/src/Resource.rc index 44f73f4e..1a74c1b4 100644 --- a/src/Resource.rc +++ b/src/Resource.rc @@ -2,7 +2,6 @@ // #pragma code_page(65001) -#define RESOURCE_DATA #include "STDInclude.hpp" #define APSTUDIO_READONLY_SYMBOLS @@ -47,8 +46,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION - PRODUCTVERSION VERSION + FILEVERSION VERSION_RC + PRODUCTVERSION VERSION_RC FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +68,12 @@ BEGIN #else VALUE "FileDescription", "IW4 client modification" #endif - VALUE "FileVersion", VERSION_STR + VALUE "FileVersion", SHORTVERSION VALUE "InternalName", "iw4x" VALUE "LegalCopyright", "No rights reserved." VALUE "OriginalFilename", "iw4x.dll" VALUE "ProductName", "IW4x" - VALUE "ProductVersion", VERSION_STR + VALUE "ProductVersion", SHORTVERSION END END BLOCK "VarFileInfo" diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 6a3faf0f..35936c14 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -1,9 +1,9 @@ #pragma once // Version number -#include +#include "version.h" -#ifndef RESOURCE_DATA +#ifndef RC_INVOKED #define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN @@ -120,22 +120,12 @@ using namespace std::literals; #endif -// Revision number #define STRINGIZE_(x) #x #define STRINGIZE(x) STRINGIZE_(x) #define BASEGAME "iw4x" #define CLIENT_CONFIG "iw4x_config.cfg" -#define REVISION_STR STRINGIZE(REVISION) -#if !REVISION_CLEAN -#define REVISION_SUFFIX "*" -#else -#define REVISION_SUFFIX "" -#endif -#define VERSION 4,2,REVISION -#define VERSION_STR "4.2." REVISION_STR - #define Assert_Size(x, size) static_assert(sizeof(x) == size, STRINGIZE(x) " structure has an invalid size.") // Resource stuff From fb5c47ee11a34ef39e1076d2729e4776094cdad0 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 00:23:17 +0200 Subject: [PATCH 51/81] Implement updating routine --- deps/protobuf | 2 +- src/Components/Modules/Console.cpp | 9 +++ src/Components/Modules/Console.hpp | 8 ++- src/Components/Modules/News.cpp | 104 +++++++++++++++++++++++++++++ src/Components/Modules/News.hpp | 4 ++ 5 files changed, 123 insertions(+), 4 deletions(-) diff --git a/deps/protobuf b/deps/protobuf index 8c936063..c0a6a6b4 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 8c936063570e5ede2ac41cf49aefe1075f1c7251 +Subproject commit c0a6a6b4628a634f6a0529c9f7e9e1e0fe66d4d6 diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index dc3f19d6..6d4ae10a 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -18,6 +18,7 @@ namespace Components int Console::LineBufferIndex = 0; bool Console::HasConsole = false; + bool Console::SkipShutdown = false; std::thread Console::ConsoleThread; @@ -383,6 +384,7 @@ namespace Components void Console::ConsoleRunner() { + Console::SkipShutdown = false; Game::Sys_ShowConsole(); MSG message; @@ -391,6 +393,8 @@ namespace Components TranslateMessage(&message); DispatchMessageA(&message); } + + if (Console::SkipShutdown) return; if (Game::Sys_Milliseconds() - Console::LastRefresh > 100 && MessageBoxA(0, "The application is not responding anymore, do you want to force its termination?", "Application is not responding", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) @@ -473,6 +477,11 @@ namespace Components // Restore the initial safe area *Game::safeArea = Console::OriginalSafeArea; } + + void Console::SetSkipShutdown() + { + Console::SkipShutdown = true; + } Console::Console() { diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index 73a9e0cf..fc38497e 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -13,9 +13,7 @@ namespace Components const char* GetName() { return "Console"; }; #endif - private: - static void ToggleConsole(); - static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); + static void SetSkipShutdown(); private: // Text-based console stuff @@ -35,6 +33,7 @@ namespace Components static int LineBufferIndex; static bool HasConsole; + static bool SkipShutdown; static std::thread ConsoleThread; @@ -59,5 +58,8 @@ namespace Components static void DrawSolidConsoleStub(); static void StoreSafeArea(); static void RestoreSafeArea(); + + static void ToggleConsole(); + static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); }; } diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index ae929e55..e9e8515e 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -4,6 +4,7 @@ namespace Components { + bool News::Terminate; std::thread News::Thread; bool News::UnitTest() @@ -39,11 +40,99 @@ namespace Components return result; } + void News::ExitProcessStub(unsigned int exitCode) + { + std::this_thread::sleep_for(10ms); + + STARTUPINFOA sInfo; + PROCESS_INFORMATION pInfo; + + ZeroMemory(&sInfo, sizeof(sInfo)); + ZeroMemory(&pInfo, sizeof(pInfo)); + sInfo.cb = sizeof(sInfo); + + CreateProcessA("updater.dat", NULL, NULL, NULL, false, CREATE_NO_WINDOW, NULL, NULL, &sInfo, &pInfo); + + Console::SetSkipShutdown(); + TerminateProcess(GetCurrentProcess(), exitCode); + } + + void News::CheckForUpdate() + { + std::string caches = Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/caches.xml").SetTimeout(5000)->Get(); + + if (!caches.empty()) + { + std::string str = "()->current.integer = version; + Dvar::Var("cl_updateavailable").Get()->current.boolean = (version > /*REVISION*/1); + } + } + } + } + News::News() { + Dvar::Register("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_FLAG_WRITEPROTECTED, "Current version number."); + Dvar::Register("cl_updateversion", 0, 0, -1, Game::DVAR_FLAG_WRITEPROTECTED, "New version number."); + Dvar::Register("cl_updateavailable", 0, Game::DVAR_FLAG_WRITEPROTECTED, "New update is available."); + Localization::Set("MPUI_CHANGELOG_TEXT", "Loading..."); Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT); + if (Utils::IO::FileExists("updater.dat")) + { + remove("updater.dat"); + } + + Command::Add("checkforupdate", [] (Command::Params) + { + News::CheckForUpdate(); + }); + + Command::Add("getautoupdate", [] (Command::Params) + { + if (!Dvar::Var("cl_updateavailable").Get()->current.boolean) return; + + Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", "Downloading updater"); + Command::Execute("openmenu popup_reconnectingtoparty", true); + + // Run the updater on shutdown + Utils::Hook::Set(0x6D72A0, ExitProcessStub); + + std::async([] () + { + std::string data = Utils::WebIO("IW4x", "http://localhost/iw4/updater/updater.exe").SetTimeout(5000)->Get(); + + if (data.empty()) + { + Localization::ClearTemp(); + Command::Execute("closemenu popup_reconnectingtoparty", false); + Game::MessageBox("Failed to download the updater!", "Error"); + } + else + { + Utils::IO::WriteFile("updater.dat", data); + Command::Execute("wait 300; quit;", false); + } + }); + }); + + News::Terminate = false; News::Thread = std::thread([] () { Localization::Set("MPUI_CHANGELOG_TEXT", Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/changelog.txt").SetTimeout(5000)->Get()); @@ -56,11 +145,26 @@ namespace Components } // TODO: Implement update checks here! + if (!Loader::PerformingUnitTests()) + { + while (!News::Terminate) + { + News::CheckForUpdate(); + + // Sleep for 3 minutes + for (int i = 0; i < 180 && !News::Terminate; ++i) + { + std::this_thread::sleep_for(1s); + } + } + } }); } News::~News() { + News::Terminate = true; + if (News::Thread.joinable()) { News::Thread.join(); diff --git a/src/Components/Modules/News.hpp b/src/Components/Modules/News.hpp index 0299f16b..924e89c4 100644 --- a/src/Components/Modules/News.hpp +++ b/src/Components/Modules/News.hpp @@ -14,5 +14,9 @@ namespace Components private: static std::thread Thread; + static bool Terminate; + + static void CheckForUpdate(); + static void ExitProcessStub(unsigned int exitCode); }; } From 73bacbaa966a3cf4d0bc61a1e32eb67c74e1fa39 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 00:24:44 +0200 Subject: [PATCH 52/81] Use the revision for version comparison --- src/Components/Modules/News.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index e9e8515e..f2abb493 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -79,7 +79,7 @@ namespace Components int version = atoi(caches.data()); Dvar::Var("cl_updateversion").Get()->current.integer = version; - Dvar::Var("cl_updateavailable").Get()->current.boolean = (version > /*REVISION*/1); + Dvar::Var("cl_updateavailable").Get()->current.boolean = (version > REVISION); } } } From 2d32d44da263318d847f5211c5247db46fe3096f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 01:10:26 +0200 Subject: [PATCH 53/81] Better async updating and new updater url --- src/Components/Modules/Console.cpp | 4 ++-- src/Components/Modules/News.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 6d4ae10a..408221a5 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -406,11 +406,11 @@ namespace Components // We can not force the termination in this thread // The destructor would be called in this thread // and would try to join this thread, which is impossible - std::async([] () + std::thread([] () { std::this_thread::sleep_for(200ms); ExitProcess(static_cast(-1)); - }); + }).detach(); } else { diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index f2abb493..c084663e 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -51,9 +51,8 @@ namespace Components ZeroMemory(&pInfo, sizeof(pInfo)); sInfo.cb = sizeof(sInfo); - CreateProcessA("updater.dat", NULL, NULL, NULL, false, CREATE_NO_WINDOW, NULL, NULL, &sInfo, &pInfo); + CreateProcessA("updater.exe", NULL, NULL, NULL, false, CREATE_NO_WINDOW, NULL, NULL, &sInfo, &pInfo); - Console::SetSkipShutdown(); TerminateProcess(GetCurrentProcess(), exitCode); } @@ -94,9 +93,10 @@ namespace Components Localization::Set("MPUI_CHANGELOG_TEXT", "Loading..."); Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT); - if (Utils::IO::FileExists("updater.dat")) + // TODO: Probably remove that, if the updater is part of the repo? + if (Utils::IO::FileExists("updater.exe")) { - remove("updater.dat"); + remove("updater.exe"); } Command::Add("checkforupdate", [] (Command::Params) @@ -112,11 +112,11 @@ namespace Components Command::Execute("openmenu popup_reconnectingtoparty", true); // Run the updater on shutdown - Utils::Hook::Set(0x6D72A0, ExitProcessStub); + Utils::Hook::Set(0x6D72A0, News::ExitProcessStub); - std::async([] () + std::thread([] () { - std::string data = Utils::WebIO("IW4x", "http://localhost/iw4/updater/updater.exe").SetTimeout(5000)->Get(); + std::string data = Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/updater.exe").SetTimeout(5000)->Get(); if (data.empty()) { @@ -126,10 +126,11 @@ namespace Components } else { - Utils::IO::WriteFile("updater.dat", data); + Console::SetSkipShutdown(); + Utils::IO::WriteFile("updater.exe", data); Command::Execute("wait 300; quit;", false); } - }); + }).detach(); }); News::Terminate = false; From 8d2d825be65d49d4fd99eb3055b1ba7ad5c690d1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 02:00:01 +0200 Subject: [PATCH 54/81] Fix code analysis warnings --- src/Components/Modules/AntiCheat.cpp | 23 +++++++++++++++-------- src/Components/Modules/News.cpp | 10 ++++++++++ src/Utils/Cryptography.hpp | 2 +- src/Utils/String.cpp | 15 ++++++++++----- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index cc2e6ebb..ed4c3515 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -136,18 +136,25 @@ namespace Components static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast(kernel32Str), sizeof kernel32Str), -1).data()); - FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibAStr), sizeof loadLibAStr), -1).data()); - FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibWStr), sizeof loadLibWStr), -1).data()); + if (kernel32) + { + FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibAStr), sizeof loadLibAStr), -1).data()); + FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibWStr), sizeof loadLibWStr), -1).data()); + + if (loadLibA && loadLibW) + { #ifdef DEBUG_LOAD_LIBRARY - AntiCheat::LoadLibHook[0].Initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP); - AntiCheat::LoadLibHook[1].Initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP); + AntiCheat::LoadLibHook[0].Initialize(loadLibA, LoadLibaryAStub, HOOK_JUMP); + AntiCheat::LoadLibHook[1].Initialize(loadLibW, LoadLibaryWStub, HOOK_JUMP); #else - AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP); - AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP); + AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP); + AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP); #endif - //AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP); - //AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP); + //AntiCheat::LoadLibHook[2].Initialize(LoadLibraryExA, loadLibExStub, HOOK_JUMP); + //AntiCheat::LoadLibHook[3].Initialize(LoadLibraryExW, loadLibExStub, HOOK_JUMP); + } + } } void AntiCheat::ReadIntegrityCheck() diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index c084663e..755ed14b 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -53,6 +53,16 @@ namespace Components CreateProcessA("updater.exe", NULL, NULL, NULL, false, CREATE_NO_WINDOW, NULL, NULL, &sInfo, &pInfo); + 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/Utils/Cryptography.hpp b/src/Utils/Cryptography.hpp index 4adda3e7..494c894a 100644 --- a/src/Utils/Cryptography.hpp +++ b/src/Utils/Cryptography.hpp @@ -20,7 +20,7 @@ namespace Utils } else { - for (unsigned int i = (this->TokenString.size() - 1); i >= 0; i--) + for (int i = static_cast(this->TokenString.size() - 1); i >= 0; i--) { if (this->TokenString[i] == 0xFF) { diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 5d33b7ef..f303014d 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -159,12 +159,17 @@ namespace Utils { // Generate UUID data UUID uuid; - UuidCreate(&uuid); + if (!UuidCreate(&uuid)) + { + // Convert to string representation + char* strdata = nullptr; + if (!UuidToStringA(&uuid, reinterpret_cast(&strdata))) + { + return std::string(strdata); + } + } - // Convert to string representation - char* strdata = nullptr; - UuidToStringA(&uuid, reinterpret_cast(&strdata)); - return std::string(strdata); + return ""; } } } From 6f776a6be7b98495c81f9d3039ea58b0a3959a35 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 12:26:47 +0200 Subject: [PATCH 55/81] --- src/Components/Modules/BitMessage.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 69267074..a0075b2b 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -31,6 +31,7 @@ namespace Components BitMessage::BMClient->start(); +#ifdef DEBUG Command::Add("bm_send", [](Command::Params params) { if (params.Length() < 3) return; @@ -177,6 +178,7 @@ namespace Components Logger::Print("Address not correct!\n"); } }); +#endif } BitMessage::~BitMessage() From c5bb8547e08f9bd0bd289311e4f5ce97a9f2139d Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Wed, 31 Aug 2016 15:29:59 +0200 Subject: [PATCH 56/81] Obfuscated the bitmessage stuff for release builds. --- src/Components/Modules/BitMessage.cpp | 9 +++++++-- src/Components/Modules/BitMessage.hpp | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index a0075b2b..727583ad 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -12,7 +12,11 @@ namespace Components BitMessage::BitMessage() { - Logger::Print("Initializing BitMessage...\n"); +#ifdef DEBUG +Logger::Print("Initializing BitMessage...\n"); +#endif // DEBUG + + BitMessage::BMClient = new BitMRC(BITMESSAGE_OBJECT_STORAGE_FILENAME, BITMESSAGE_KEYS_FILENAME); BitMessage::BMClient->init(); @@ -343,8 +347,9 @@ namespace Components bool BitMessage::InitAddr() { +#ifdef DEBUG Logger::Print("Generating BM address...\n"); - +#endif Addr myAddress; if (!myAddress.generateRandom()) { diff --git a/src/Components/Modules/BitMessage.hpp b/src/Components/Modules/BitMessage.hpp index 2d858973..fd586ebb 100644 --- a/src/Components/Modules/BitMessage.hpp +++ b/src/Components/Modules/BitMessage.hpp @@ -2,8 +2,8 @@ #ifndef DISABLE_BITMESSAGE -#define BITMESSAGE_KEYS_FILENAME std::string("players/bmkeys.dat") -#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("players/bmstore.dat") +#define BITMESSAGE_KEYS_FILENAME std::string("players/bmk.dat") +#define BITMESSAGE_OBJECT_STORAGE_FILENAME std::string("players/storage.dat") namespace Components { From 243ddc400d0307dfbc145927064fef83de5a3127 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 17:54:08 +0200 Subject: [PATCH 57/81] Experimental moddownload --- src/Components/Modules/Download.cpp | 247 +++++++++++++++++++++++++++- src/Components/Modules/Download.hpp | 63 +++++++ src/Components/Modules/Party.cpp | 77 +++++---- src/Components/Modules/Party.hpp | 9 +- src/Utils/Cryptography.hpp | 2 +- src/Utils/IO.cpp | 35 ++++ src/Utils/IO.hpp | 1 + src/Utils/WebIO.cpp | 21 +++ src/Utils/WebIO.hpp | 1 + 9 files changed, 412 insertions(+), 44 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index f8d25832..b0169c08 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -3,6 +3,229 @@ namespace Components { mg_mgr Download::Mgr; + Download::ClientDownload Download::CLDownload; + +#pragma region Client + + void Download::InitiateClientDownload(std::string mod) + { + if (Download::CLDownload.Running) return; + + Download::CLDownload.Mutex.lock(); + Download::CLDownload.Progress = "Downloading mod"; + Download::CLDownload.Mutex.unlock(); + + Command::Execute("openmenu popup_reconnectingtoparty", true); + + Download::CLDownload.Running = true; + Download::CLDownload.Mod = mod; + Download::CLDownload.Target = Party::Target(); + Download::CLDownload.Thread = std::thread(Download::ModDownloader, &Download::CLDownload); + } + + bool Download::ParseModList(ClientDownload* download, std::string list) + { + if (!download) return false; + download->Files.clear(); + + std::string error; + json11::Json listData = json11::Json::parse(list, error); + + + if (!error.empty() || !listData.is_array()) return false; + + for (auto& file : listData.array_items()) + { + if (!file.is_object()) return false; + + auto hash = file["hash"]; + auto name = file["name"]; + auto size = file["size"]; + + if (!hash.is_string() || !name.is_string() || !size.is_number()) return false; + + Download::ClientDownload::File fileEntry; + fileEntry.Name = name.string_value(); + fileEntry.Hash = hash.string_value(); + fileEntry.Size = static_cast(size.number_value()); + + if (!fileEntry.Name.empty()) + { + download->Files.push_back(fileEntry); + } + } + + return true; + } + + void Download::DownloadHandler(mg_connection *nc, int ev, void* ev_data) + { + http_message* hm = reinterpret_cast(ev_data); + Download::FileDownload* fDownload = reinterpret_cast(nc->mgr->user_data); + + if (ev == MG_EV_CONNECT) + { + if (hm->message.p) + { + fDownload->downloading = false; + return; + } + } + + if (ev == MG_EV_RECV) + { + fDownload->receivedBytes += static_cast(*reinterpret_cast(ev_data)); + + double progress = (100.0 / fDownload->file.Size) * fDownload->receivedBytes; + fDownload->download->Mutex.lock(); + fDownload->download->Progress = fmt::sprintf("Downloading file (%d/%d) %s %d%%", fDownload->index + 1, fDownload->download->Files.size(), fDownload->file.Name.data(), static_cast(progress)); + fDownload->download->Mutex.unlock(); + } + + if (ev == MG_EV_HTTP_REPLY) + { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + fDownload->buffer = std::string(hm->body.p, hm->body.len); + fDownload->downloading = false; + return; + } + } + + bool Download::DownloadFile(ClientDownload* download, unsigned int index) + { + if (!download || download->Files.size() <= index) return false; + + auto file = download->Files[index]; + + download->Mutex.lock(); + download->Progress = fmt::sprintf("Downloading file (%d/%d) %s 0%%", index + 1, download->Files.size(), file.Name.data()); + download->Mutex.unlock(); + + std::string path = download->Mod + "/" + file.Name; + if (Utils::IO::FileExists(path)) + { + std::string data = Utils::IO::ReadFile(path); + + if (data.size() == file.Size && Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(data), "") == file.Hash) + { + return true; + } + } + + std::string url = "http://" + download->Target.GetString() + "/file/" + file.Name; + + Download::FileDownload fDownload; + fDownload.file = file; + fDownload.index = index; + fDownload.download = download; + fDownload.downloading = true; + fDownload.receivedBytes = 0; + + download->Valid = true; + mg_mgr_init(&download->Mgr, &fDownload); + mg_connect_http(&download->Mgr, Download::DownloadHandler, url.data(), NULL, NULL); + + while (fDownload.downloading) + { + mg_mgr_poll(&download->Mgr, 0); + } + + mg_mgr_free(&download->Mgr); + download->Valid = false; + + if (fDownload.buffer.size() != file.Size || Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(fDownload.buffer), "") != file.Hash) + { + return false; + } + + Utils::IO::CreateDirectory(download->Mod); + Utils::IO::WriteFile(path, fDownload.buffer); + + return true; + } + + void Download::ModDownloader(ClientDownload* download) + { + if (!download) download = &Download::CLDownload; + + std::string host = "http://" + download->Target.GetString(); + std::string list = Utils::WebIO("IW4x", host + "/list").SetTimeout(5000)->Get(); + + if (list.empty()) + { + download->Thread.detach(); + download->Clear(); + + QuickPatch::Once([] () + { + Party::ConnectError("Failed to download the modlist!"); + }); + + return; + } + + if (!Download::ParseModList(download, list)) + { + download->Thread.detach(); + download->Clear(); + + QuickPatch::Once([] () + { + Party::ConnectError("Failed to parse the modlist!"); + }); + + return; + } + + for (unsigned int i = 0; i < download->Files.size(); ++i) + { + if (!Download::DownloadFile(download, i)) + { + Dvar::Var("partyend_reason").Set(fmt::sprintf("Failed to download file: %s!", download->Files[i].Name.data())); + + download->Thread.detach(); + download->Clear(); + + QuickPatch::Once([] () + { + Localization::ClearTemp(); + Command::Execute("closemenu popup_reconnectingtoparty"); + Command::Execute("openmenu menu_xboxlive_partyended"); + }); + + return; + } + } + + static std::string mod = download->Mod; + + download->Thread.detach(); + download->Clear(); + + // Run this on the main thread + QuickPatch::Once([] () + { + auto fsGame = Dvar::Var("fs_game"); + fsGame.Set(mod); + fsGame.Get()->pad2[0] = 1; + + mod.clear(); + + Localization::ClearTemp(); + Command::Execute("closemenu popup_reconnectingtoparty", true); + + if (Dvar::Var("cl_modVidRestart").Get()) + { + Command::Execute("vid_restart", false); + } + + Command::Execute("reconnect", false); + }); + } + +#pragma endregion + +#pragma region Server bool Download::IsClient(mg_connection *nc) { @@ -283,6 +506,8 @@ namespace Components nc->flags |= MG_F_SEND_AND_CLOSE; } +#pragma endregion + Download::Download() { if (Dedicated::IsEnabled()) @@ -308,12 +533,22 @@ namespace Components } else { - Utils::Hook(0x5AC6E9, [] () - { - // TODO: Perform moddownload here +// Utils::Hook(0x5AC6E9, [] () +// { +// // TODO: Perform moddownload here +// +// Game::CL_DownloadsComplete(0); +// }, HOOK_CALL).Install()->Quick(); - Game::CL_DownloadsComplete(0); - }, HOOK_CALL).Install()->Quick(); + QuickPatch::OnFrame([] + { + if (Download::CLDownload.Running) + { + Download::CLDownload.Mutex.lock(); + Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", Download::CLDownload.Progress); + Download::CLDownload.Mutex.unlock(); + } + }); } } @@ -325,7 +560,7 @@ namespace Components } else { - + Download::CLDownload.Clear(); } } } diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index ea56ba4a..11748aa7 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -10,16 +10,79 @@ namespace Components const char* GetName() { return "Download"; }; #endif + static void InitiateClientDownload(std::string mod); + private: + class ClientDownload + { + public: + ClientDownload() : Valid(false), Running(false) {} + ~ClientDownload() { this->Clear(); } + + bool Running; + bool Valid; + mg_mgr Mgr; + Network::Address Target; + std::string Mod; + std::mutex Mutex; + std::thread Thread; + std::string Progress; + + class File + { + public: + std::string Name; + std::string Hash; + size_t Size; + }; + + std::vector Files; + + void Clear() + { + this->Running = false; + this->Mod.clear(); + this->Files.clear(); + + if (this->Valid) + { + this->Valid = false; + mg_mgr_free(&(this->Mgr)); + } + + this->Mutex.lock(); + this->Progress.clear(); + this->Mutex.unlock(); + } + }; + + class FileDownload + { + public: + ClientDownload* download; + ClientDownload::File file; + + bool downloading; + unsigned int index; + std::string buffer; + size_t receivedBytes; + }; + static mg_mgr Mgr; + static ClientDownload CLDownload; static void EventHandler(mg_connection *nc, int ev, void *ev_data); static void ListHandler(mg_connection *nc, int ev, void *ev_data); static void FileHandler(mg_connection *nc, int ev, void *ev_data); static void InfoHandler(mg_connection *nc, int ev, void *ev_data); + static void DownloadHandler(mg_connection *nc, int ev, void *ev_data); static bool IsClient(mg_connection *nc); static Game::client_t* GetClient(mg_connection *nc); static void Forbid(mg_connection *nc); + + static void ModDownloader(ClientDownload* download); + static bool ParseModList(ClientDownload* download, std::string list); + static bool DownloadFile(ClientDownload* download, unsigned int index); }; } diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 7922d1c8..df0143b9 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -64,6 +64,7 @@ namespace Components void Party::ConnectError(std::string message) { + Localization::ClearTemp(); Command::Execute("closemenu popup_reconnectingtoparty"); Dvar::Var("partyend_reason").Set(message); Command::Execute("openmenu menu_xboxlive_partyended"); @@ -354,8 +355,9 @@ namespace Components { // Invalidate handler for future packets Party::Container.Valid = false; + Party::Container.Info = info; - int matchType = atoi(info.Get("matchtype").data()); + Party::Container.MatchType = atoi(info.Get("matchtype").data()); uint32_t securityLevel = static_cast(atoi(info.Get("securityLevel").data())); if (info.Get("challenge") != Party::Container.Challenge) @@ -368,48 +370,55 @@ namespace Components Command::Execute("closemenu popup_reconnectingtoparty"); Auth::IncreaseSecurityLevel(securityLevel, "reconnect"); } - else if (!matchType) + else if (!Party::Container.MatchType) { Party::ConnectError("Server is not hosting a match."); } - // Connect - else if (matchType == 1) // Party + else if(Party::Container.MatchType > 2 || Party::Container.MatchType < 0) { - // Send playlist request - Party::Container.RequestTime = Game::Sys_Milliseconds(); - Party::Container.AwaitingPlaylist = true; - Network::SendCommand(address, "getplaylist"); - - // This is not a safe method - // TODO: Fix actual error! - if (Game::CL_IsCgameInitialized()) - { - Command::Execute("disconnect", true); - } + Party::ConnectError("Invalid join response: Unknown matchtype"); } - else if (matchType == 2) // Match + else if(!info.Get("fs_game").empty() && Dvar::Var("fs_game").Get() != info.Get("fs_game")) { - if (atoi(info.Get("clients").data()) >= atoi(info.Get("sv_maxclients").data())) - { - Party::ConnectError("@EXE_SERVERISFULL"); - } - if (info.Get("mapname") == "" || info.Get("gametype") == "") - { - Party::ConnectError("Invalid map or gametype."); - } - else - { - Dvar::Var("xblive_privateserver").Set(true); - - Game::Menus_CloseAll(Game::uiContext); - - Game::_XSESSION_INFO hostInfo; - Game::CL_ConnectFromParty(0, &hostInfo, *address.Get(), 0, 0, info.Get("mapname").data(), info.Get("gametype").data()); - } + Command::Execute("closemenu popup_reconnectingtoparty"); + Download::InitiateClientDownload(info.Get("fs_game")); } else { - Party::ConnectError("Invalid join response: Unknown matchtype"); + if (Party::Container.MatchType == 1) // Party + { + // Send playlist request + Party::Container.RequestTime = Game::Sys_Milliseconds(); + Party::Container.AwaitingPlaylist = true; + Network::SendCommand(Party::Container.Target, "getplaylist"); + + // This is not a safe method + // TODO: Fix actual error! + if (Game::CL_IsCgameInitialized()) + { + Command::Execute("disconnect", true); + } + } + else if (Party::Container.MatchType == 2) // Match + { + if (atoi(Party::Container.Info.Get("clients").data()) >= atoi(Party::Container.Info.Get("sv_maxclients").data())) + { + Party::ConnectError("@EXE_SERVERISFULL"); + } + if (Party::Container.Info.Get("mapname") == "" || Party::Container.Info.Get("gametype") == "") + { + Party::ConnectError("Invalid map or gametype."); + } + else + { + Dvar::Var("xblive_privateserver").Set(true); + + Game::Menus_CloseAll(Game::uiContext); + + Game::_XSESSION_INFO hostInfo; + Game::CL_ConnectFromParty(0, &hostInfo, *Party::Container.Target.Get(), 0, 0, Party::Container.Info.Get("mapname").data(), Party::Container.Info.Get("gametype").data()); + } + } } } } diff --git a/src/Components/Modules/Party.hpp b/src/Components/Modules/Party.hpp index 5e7e73b6..ca2e033e 100644 --- a/src/Components/Modules/Party.hpp +++ b/src/Components/Modules/Party.hpp @@ -19,6 +19,8 @@ namespace Components static void PlaylistContinue(); static void PlaylistError(std::string error); + static void ConnectError(std::string message); + private: class JoinContainer { @@ -27,10 +29,13 @@ namespace Components std::string Challenge; DWORD JoinTime; bool Valid; + int MatchType; + + Utils::InfoString Info; // Party-specific stuff DWORD RequestTime; - bool AwaitingPlaylist; + bool AwaitingPlaylist; }; static JoinContainer Container; @@ -40,8 +45,6 @@ namespace Components static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description); - static void ConnectError(std::string message); - static DWORD UIDvarIntStub(char* dvar); }; } diff --git a/src/Utils/Cryptography.hpp b/src/Utils/Cryptography.hpp index 494c894a..0cb67589 100644 --- a/src/Utils/Cryptography.hpp +++ b/src/Utils/Cryptography.hpp @@ -20,7 +20,7 @@ namespace Utils } else { - for (int i = static_cast(this->TokenString.size() - 1); i >= 0; i--) + for (int i = static_cast(this->TokenString.size() - 1); i >= 0; --i) { if (this->TokenString[i] == 0xFF) { diff --git a/src/Utils/IO.cpp b/src/Utils/IO.cpp index c29a39f5..d953c06a 100644 --- a/src/Utils/IO.cpp +++ b/src/Utils/IO.cpp @@ -47,5 +47,40 @@ namespace Utils return buffer; } + + void CreateDirectory(std::string dir) + { + char opath[MAX_PATH]; + char *p; + size_t len; + + strncpy_s(opath, dir.data(), sizeof(opath)); + len = strlen(opath); + + if (opath[len - 1] == L'/') + { + opath[len - 1] = L'\0'; + } + + for (p = opath; *p; p++) + { + if (*p == L'/' || *p == L'\\') + { + *p = L'\0'; + + if (_access(opath, 0)) + { + _mkdir(opath); + } + + *p = L'\\'; + } + } + + if (_access(opath, 0)) + { + _mkdir(opath); + } + } } } diff --git a/src/Utils/IO.hpp b/src/Utils/IO.hpp index 82ef4769..bc91be09 100644 --- a/src/Utils/IO.hpp +++ b/src/Utils/IO.hpp @@ -5,5 +5,6 @@ namespace Utils bool FileExists(std::string file); void WriteFile(std::string file, std::string data); std::string ReadFile(std::string file); + void CreateDirectory(std::string dir); } } diff --git a/src/Utils/WebIO.cpp b/src/Utils/WebIO.cpp index 59339d0f..c88e43c2 100644 --- a/src/Utils/WebIO.cpp +++ b/src/Utils/WebIO.cpp @@ -104,10 +104,26 @@ namespace Utils WebIO::m_sUrl.document = server.substr(pos); } + WebIO::m_sUrl.port.clear(); + + pos = WebIO::m_sUrl.server.find(":"); + if (pos != std::string::npos) + { + WebIO::m_sUrl.port = WebIO::m_sUrl.server.substr(pos + 1); + WebIO::m_sUrl.server = WebIO::m_sUrl.server.substr(0, pos); + } + WebIO::m_sUrl.raw.clear(); WebIO::m_sUrl.raw.append(WebIO::m_sUrl.protocol); WebIO::m_sUrl.raw.append("://"); WebIO::m_sUrl.raw.append(WebIO::m_sUrl.server); + + if (!WebIO::m_sUrl.port.empty()) + { + WebIO::m_sUrl.raw.append(":"); + WebIO::m_sUrl.raw.append(WebIO::m_sUrl.port); + } + WebIO::m_sUrl.raw.append(WebIO::m_sUrl.document); WebIO::m_isFTP = (WebIO::m_sUrl.protocol == "ftp"); @@ -217,6 +233,11 @@ namespace Utils wPort = INTERNET_DEFAULT_HTTPS_PORT; } + if (!WebIO::m_sUrl.port.empty()) + { + wPort = static_cast(atoi(WebIO::m_sUrl.port.data())); + } + const char* username = (WebIO::m_username.size() ? WebIO::m_username.data() : NULL); const char* password = (WebIO::m_password.size() ? WebIO::m_password.data() : NULL); WebIO::m_hConnect = InternetConnectA(WebIO::m_hSession, WebIO::m_sUrl.server.data(), wPort, username, password, dwService, dwFlag, 0); diff --git a/src/Utils/WebIO.hpp b/src/Utils/WebIO.hpp index 849cd57d..ffa7ca3c 100644 --- a/src/Utils/WebIO.hpp +++ b/src/Utils/WebIO.hpp @@ -74,6 +74,7 @@ namespace Utils std::string protocol; std::string server; std::string document; + std::string port; std::string raw; }; From 63acb4374d5c748264acfecd5acc932c36f61d8f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 18:04:28 +0200 Subject: [PATCH 58/81] Stuff concerning issue --- deps/mongoose | 2 +- src/Components/Modules/Download.cpp | 2 +- src/Components/Modules/ModList.cpp | 4 ++-- src/Game/Structs.hpp | 16 ++++++++-------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/deps/mongoose b/deps/mongoose index 844c7787..4120f953 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 844c7787f9d86715c80ab56f4f28d1b808df5341 +Subproject commit 4120f953c7e5a14fdce2445effb1158b0650f103 diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index b0169c08..ee97c5df 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -207,7 +207,7 @@ namespace Components { auto fsGame = Dvar::Var("fs_game"); fsGame.Set(mod); - fsGame.Get()->pad2[0] = 1; + fsGame.Get()->modified = true; mod.clear(); diff --git a/src/Components/Modules/ModList.cpp b/src/Components/Modules/ModList.cpp index 2fc9b170..4491c4cc 100644 --- a/src/Components/Modules/ModList.cpp +++ b/src/Components/Modules/ModList.cpp @@ -60,7 +60,7 @@ namespace Components { auto fsGame = Dvar::Var("fs_game"); fsGame.Set(""); - fsGame.Get()->pad2[0] = 1; + fsGame.Get()->modified = true; if (Dvar::Var("cl_modVidRestart").Get()) { @@ -76,7 +76,7 @@ namespace Components { auto fsGame = Dvar::Var("fs_game"); fsGame.Set(fmt::sprintf("mods/%s", mod.data())); - fsGame.Get()->pad2[0] = 1; + fsGame.Get()->modified = true; if (Dvar::Var("cl_modVidRestart").Get()) { diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index fb163030..1da60c32 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -117,14 +117,14 @@ namespace Game typedef struct dvar_t { //startbyte:endbyte - const char* name; //0:3 - const char* description; //4:7 - unsigned int flags; //8:11 - char type; //12:12 - char pad2[3]; //13:15 - dvar_value_t current; //16:31 - dvar_value_t latched; //32:47 - dvar_value_t _default; //48:64 + const char* name; //0:3 + const char* description; //4:7 + unsigned int flags; //8:11 + char type; //12:12 + bool modified; //13:15 + dvar_value_t current; //16:31 + dvar_value_t latched; //32:47 + dvar_value_t _default; //48:64 dvar_maxmin_t min; //65:67 dvar_maxmin_t max; //68:72 woooo } dvar_t; From 6f89e0f052678b20a9cb70d5cde5c5ab45ac63b3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 31 Aug 2016 18:12:31 +0200 Subject: [PATCH 59/81] --- src/Components/Modules/Download.cpp | 11 ++++++++++- src/Components/Modules/Download.hpp | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index ee97c5df..8b9fae2c 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -19,6 +19,7 @@ namespace Components Download::CLDownload.Running = true; Download::CLDownload.Mod = mod; + Download::CLDownload.TerminateThread = false; Download::CLDownload.Target = Party::Target(); Download::CLDownload.Thread = std::thread(Download::ModDownloader, &Download::CLDownload); } @@ -125,7 +126,7 @@ namespace Components mg_mgr_init(&download->Mgr, &fDownload); mg_connect_http(&download->Mgr, Download::DownloadHandler, url.data(), NULL, NULL); - while (fDownload.downloading) + while (fDownload.downloading && !fDownload.download->TerminateThread) { mg_mgr_poll(&download->Mgr, 0); } @@ -164,6 +165,8 @@ namespace Components return; } + if (download->TerminateThread) return; + if (!Download::ParseModList(download, list)) { download->Thread.detach(); @@ -177,8 +180,12 @@ namespace Components return; } + if (download->TerminateThread) return; + for (unsigned int i = 0; i < download->Files.size(); ++i) { + if (download->TerminateThread) return; + if (!Download::DownloadFile(download, i)) { Dvar::Var("partyend_reason").Set(fmt::sprintf("Failed to download file: %s!", download->Files[i].Name.data())); @@ -197,6 +204,8 @@ namespace Components } } + if (download->TerminateThread) return; + static std::string mod = download->Mod; download->Thread.detach(); diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index 11748aa7..f0f97266 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -16,11 +16,12 @@ namespace Components class ClientDownload { public: - ClientDownload() : Valid(false), Running(false) {} + ClientDownload() : Valid(false), Running(false), TerminateThread(false) {} ~ClientDownload() { this->Clear(); } bool Running; bool Valid; + bool TerminateThread; mg_mgr Mgr; Network::Address Target; std::string Mod; @@ -28,6 +29,7 @@ namespace Components std::thread Thread; std::string Progress; + class File { public: @@ -40,6 +42,13 @@ namespace Components void Clear() { + this->TerminateThread = true; + + if (this->Thread.joinable()) + { + this->Thread.join(); + } + this->Running = false; this->Mod.clear(); this->Files.clear(); From 5ccb4f1f3c177a871c31422db9d4c03abf2438ad Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Thu, 1 Sep 2016 21:52:00 +0200 Subject: [PATCH 60/81] 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]); + } } From b94a311ec49f14e0172fe25da4771b95df4d8364 Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Thu, 1 Sep 2016 21:54:46 +0200 Subject: [PATCH 61/81] Changed name of the last test functions i had. --- src/Components/Modules/Logger.cpp | 4 ++-- src/Components/Modules/Logger.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 771a82cc..bb70138f 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -174,7 +174,7 @@ namespace Components Logger::MessageMutex.unlock(); } - void Logger::test(std::string message) + void Logger::PipeOutputStub(std::string message) { if (Logger::addresses.size()) { @@ -190,7 +190,7 @@ namespace Components Logger::Logger() { - Logger::PipeOutput(&test); + Logger::PipeOutput(&PipeOutputStub); QuickPatch::OnFrame(Logger::Frame); diff --git a/src/Components/Modules/Logger.hpp b/src/Components/Modules/Logger.hpp index 50400d15..f2d87e08 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -40,7 +40,7 @@ namespace Components Game::cmd_function_t sv_glog_list; Game::cmd_function_t sv_glog_list2; - static void test(std::string message); + static void PipeOutputStub(std::string message); private: static std::mutex MessageMutex; static std::vector MessageQueue; From 70ea83b85123308b7e80f30481cd18fff7777d6f Mon Sep 17 00:00:00 2001 From: /dev/sdb Date: Fri, 2 Sep 2016 22:28:51 +0200 Subject: [PATCH 62/81] Try to implement g_log network transfer. Logging to file is still working. Logging over network does send something but nothing useful. (?????? ??) No Crashs. --- src/Components/Modules/Logger.cpp | 77 +++++++++++++++++++++++++------ src/Components/Modules/Logger.hpp | 45 ++++++++++-------- 2 files changed, 88 insertions(+), 34 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index bb70138f..c63d8c6c 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -11,10 +11,12 @@ namespace Components static char* writeFolder; //static DWORD fsBuildOSPathForThreadHookLoc = 0x642139; DWORD fsBuildOSPathForThreadHookLocRet = 0x64213F; - Game::dvar_t* iw4m_onelog; + Game::dvar_t* iw4m_onelog; + void(*Logger::PipeCallback)(std::string) = nullptr; + void(*Logger::GLogCallback)(std::string) = nullptr; bool Logger::IsConsoleReady() { @@ -43,7 +45,7 @@ namespace Components } }*/ fflush(stdout); - + return; } @@ -118,7 +120,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()) @@ -136,15 +138,27 @@ namespace Components Logger::PipeCallback = callback; } + void Logger::GLogOutput(void(*callback)(std::string)) + { + Logger::GLogCallback = callback; + } + void Logger::PrintMessagePipe(const char* data) { if (Logger::PipeCallback) { - Logger::PipeCallback(data); } } + void Logger::GLogMessagePipe(const char* data) + { + if (Logger::GLogCallback) + { + Logger::GLogCallback(data); + } + } + __declspec(naked) void Logger::PrintMessageStub() { __asm @@ -156,7 +170,7 @@ namespace Components push[esp + 8h] call Logger::PrintMessagePipe add esp, 4h - + returnPrint : push esi @@ -167,6 +181,27 @@ namespace Components } } + __declspec(naked) void Logger::GLogPrintfHookStub() { + _asm + { + mov eax, Logger::GLogCallback + test eax, eax + jz returnPrint + + + call Logger::GLogMessagePipe + + returnPrint : + + mov eax, 4576C0h + jmp eax + + + } + + + } + void Logger::EnqueueMessage(std::string message) { Logger::MessageMutex.lock(); @@ -176,7 +211,7 @@ namespace Components void Logger::PipeOutputStub(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); @@ -184,18 +219,32 @@ namespace Components } } //Logger::PrintMessagePipe(message.c_str()); - - } + } + void Logger::GPipeOutputStub(std::string message) + { + OutputDebugStringA("Worked"); + if (Logger::gaddresses.size()) { + for (size_t i = 0; i < Logger::gaddresses.size(); i++) { + const char* toSend = Utils::String::VA("%s", message); + Network::Send(Logger::gaddresses[i], toSend); + } + } + //Logger::PrintMessagePipe(message.c_str()); + + } Logger::Logger() { Logger::PipeOutput(&PipeOutputStub); + Logger::GLogOutput(&GPipeOutputStub); + //Logger::PipeOutput(nullptr); + //Logger::GLogOutput(nullptr); QuickPatch::OnFrame(Logger::Frame); Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); - + Utils::Hook(Logger::glogprintfHookLoc, Logger::GLogPrintfHookStub, HOOK_CALL).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); @@ -215,9 +264,9 @@ namespace Components 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"); + //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"); } @@ -341,7 +390,7 @@ namespace Components return true; } - + @@ -374,7 +423,7 @@ namespace Components 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 f2d87e08..93753ec1 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -20,44 +20,49 @@ namespace Components static bool IsConsoleReady(); static void PipeOutput(void(*callback)(std::string)); + static void GLogOutput(void(*callback)(std::string)); static bool validInt(char* str); static const DWORD fsBuildOSPathForThreadHookLoc = 0x642139; + static const DWORD glogprintfHookLoc = 0x4B0218; //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_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_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_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_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_del; + Game::cmd_function_t sv_glog_del2; - Game::cmd_function_t sv_glog_list; - Game::cmd_function_t sv_glog_list2; - static void PipeOutputStub(std::string message); + Game::cmd_function_t sv_glog_list; + Game::cmd_function_t sv_glog_list2; + static void PipeOutputStub(std::string message); + static void GPipeOutputStub(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(*GLogCallback)(std::string); - static void Frame(); static void PrintMessageStub(); + static void GLogPrintfHookStub(); static void PrintMessagePipe(const char* data); - static void EnqueueMessage(std::string message); + static void GLogMessagePipe(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_BuildOSPathForThreadHookFunc(); static void FS_BuildOSPathForThreadHookTest(); static void SV_GLog_Add_f(); static void SV_Log_Add_f(); @@ -66,9 +71,9 @@ static void FS_BuildOSPathForThreadHookFunc(); static void SV_GLog_List_f(); static void SV_Log_List_f(); - - - - + + + + }; } From 64682a8ef627f0e1688b3707a83c8aa6dc9b828d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 3 Sep 2016 13:42:14 +0200 Subject: [PATCH 63/81] Revert changes --- src/Components/Modules/Logger.cpp | 290 +----------------------------- src/Components/Modules/Logger.hpp | 47 +---- src/Game/Functions.hpp | 13 -- 3 files changed, 8 insertions(+), 342 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index c63d8c6c..c2b4d5a8 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -4,19 +4,7 @@ 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; - void(*Logger::GLogCallback)(std::string) = nullptr; bool Logger::IsConsoleReady() { @@ -38,46 +26,21 @@ 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); } } @@ -120,7 +83,6 @@ namespace Components for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) { - Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0); if (!Logger::IsConsoleReady()) @@ -138,11 +100,6 @@ namespace Components Logger::PipeCallback = callback; } - void Logger::GLogOutput(void(*callback)(std::string)) - { - Logger::GLogCallback = callback; - } - void Logger::PrintMessagePipe(const char* data) { if (Logger::PipeCallback) @@ -151,14 +108,6 @@ namespace Components } } - void Logger::GLogMessagePipe(const char* data) - { - if (Logger::GLogCallback) - { - Logger::GLogCallback(data); - } - } - __declspec(naked) void Logger::PrintMessageStub() { __asm @@ -167,39 +116,18 @@ 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 - } - } - - __declspec(naked) void Logger::GLogPrintfHookStub() { - _asm - { - mov eax, Logger::GLogCallback - test eax, eax - jz returnPrint - - - call Logger::GLogMessagePipe - - returnPrint : - - mov eax, 4576C0h + mov eax, 4AA835h jmp eax - - } - - } void Logger::EnqueueMessage(std::string message) @@ -209,66 +137,13 @@ namespace Components Logger::MessageMutex.unlock(); } - void Logger::PipeOutputStub(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()); - - } - void Logger::GPipeOutputStub(std::string message) - { - OutputDebugStringA("Worked"); - if (Logger::gaddresses.size()) { - for (size_t i = 0; i < Logger::gaddresses.size(); i++) { - const char* toSend = Utils::String::VA("%s", message); - Network::Send(Logger::gaddresses[i], toSend); - } - } - //Logger::PrintMessagePipe(message.c_str()); - - } - Logger::Logger() { - Logger::PipeOutput(&PipeOutputStub); - Logger::GLogOutput(&GPipeOutputStub); + Logger::PipeOutput(nullptr); - //Logger::PipeOutput(nullptr); - //Logger::GLogOutput(nullptr); QuickPatch::OnFrame(Logger::Frame); Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); - Utils::Hook(Logger::glogprintfHookLoc, Logger::GLogPrintfHookStub, HOOK_CALL).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() @@ -277,157 +152,4 @@ 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 93753ec1..504038e4 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -20,60 +20,17 @@ namespace Components static bool IsConsoleReady(); static void PipeOutput(void(*callback)(std::string)); - static void GLogOutput(void(*callback)(std::string)); - static bool validInt(char* str); - static const DWORD fsBuildOSPathForThreadHookLoc = 0x642139; - static const DWORD glogprintfHookLoc = 0x4B0218; - //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 PipeOutputStub(std::string message); - static void GPipeOutputStub(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(*GLogCallback)(std::string); static void Frame(); static void PrintMessageStub(); - static void GLogPrintfHookStub(); static void PrintMessagePipe(const char* data); - static void GLogMessagePipe(const char* data); - static void EnqueueMessage(std::string message); + 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 76b8eee1..c3f29b05 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -518,17 +518,4 @@ 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]); - } } From 18d1e9daa111fb0304241bbbc0cab9bda289fea1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 3 Sep 2016 15:52:40 +0200 Subject: [PATCH 64/81] Network logging stuff --- deps/mongoose | 2 +- deps/protobuf | 2 +- src/Components/Loader.cpp | 10 +++ src/Components/Loader.hpp | 9 ++- src/Components/Modules/Command.cpp | 11 +++ src/Components/Modules/Logger.cpp | 108 +++++++++++++++++++++++++++++ src/Components/Modules/Logger.hpp | 4 ++ 7 files changed, 141 insertions(+), 5 deletions(-) diff --git a/deps/mongoose b/deps/mongoose index 4120f953..36405545 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 4120f953c7e5a14fdce2445effb1158b0650f103 +Subproject commit 36405545033489ccfeb6c139c6e609998efc3cf9 diff --git a/deps/protobuf b/deps/protobuf index c0a6a6b4..96a9d973 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit c0a6a6b4628a634f6a0529c9f7e9e1e0fe66d4d6 +Subproject commit 96a9d97352436c7284e8194e103ca8d92649ad02 diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index b62ea828..411eaf0a 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -2,10 +2,18 @@ namespace Components { + bool Loader::Pregame = true; std::vector Loader::Components; + bool Loader::IsPregame() + { + return Loader::Pregame; + } + void Loader::Initialize() { + Loader::Pregame = true; + Loader::Register(new Flags()); Loader::Register(new Singleton()); @@ -59,6 +67,8 @@ namespace Components Loader::Register(new MusicalTalent()); Loader::Register(new StructuredData()); Loader::Register(new ConnectProtocol()); + + Loader::Pregame = false; } void Loader::Uninitialize() diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 41813e98..e5d1080b 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -22,7 +22,10 @@ namespace Components static bool PerformingUnitTests(); static void Register(Component* component); + static bool IsPregame(); + private: + static bool Pregame; static std::vector Components; }; } @@ -38,7 +41,6 @@ namespace Components #include "Modules\Toast.hpp" #include "Modules\Colors.hpp" #include "Modules\D3D9Ex.hpp" -#include "Modules\Logger.hpp" #include "Modules\Script.hpp" #include "Modules\Weapon.hpp" #include "Modules\Window.hpp" @@ -49,9 +51,9 @@ namespace Components #include "Modules\Network.hpp" #include "Modules\Theatre.hpp" #include "Modules\Node.hpp" -#include "Modules\BitMessage.hpp" #include "Modules\RCon.hpp" #include "Modules\Party.hpp" // Destroys the order, but requires network classes :D +#include "Modules\Logger.hpp" #include "Modules\Download.hpp" #include "Modules\Playlist.hpp" #include "Modules\RawFiles.hpp" @@ -62,10 +64,10 @@ namespace Components #include "Modules\Dedicated.hpp" #include "Modules\Discovery.hpp" #include "Modules\Exception.hpp" -#include "Modules\MinidumpUpload.hpp" #include "Modules\FastFiles.hpp" #include "Modules\Materials.hpp" #include "Modules\Singleton.hpp" +#include "Modules\BitMessage.hpp" #include "Modules\FileSystem.hpp" #include "Modules\QuickPatch.hpp" #include "Modules\ServerInfo.hpp" @@ -75,5 +77,6 @@ namespace Components #include "Modules\AssetHandler.hpp" #include "Modules\Localization.hpp" #include "Modules\MusicalTalent.hpp" +#include "Modules\MinidumpUpload.hpp" #include "Modules\StructuredData.hpp" #include "Modules\ConnectProtocol.hpp" diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index d510f023..6b4939c0 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -46,6 +46,17 @@ namespace Components void Command::AddSV(const char* name, Command::Callback* callback) { + if (Loader::IsPregame()) + { + MessageBoxA(0, "Registering server commands in pregamestate is illegal!", 0, MB_ICONERROR); + +#ifdef DEBUG + __debugbreak(); +#endif + + return; + } + std::string command = Utils::String::ToLower(name); if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end()) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index c2b4d5a8..5fecb00a 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -4,6 +4,7 @@ namespace Components { std::mutex Logger::MessageMutex; std::vector Logger::MessageQueue; + std::vector Logger::LoggingAddresses[2]; void(*Logger::PipeCallback)(std::string) = nullptr; bool Logger::IsConsoleReady() @@ -108,6 +109,29 @@ namespace Components } } + void Logger::NetworkLog(const char* data, bool gLog) + { + std::string buffer(data); + for (auto& addr : Logger::LoggingAddresses[gLog & 1]) + { + Network::SendCommand(addr, "print", buffer); + } + } + + __declspec(naked) void Logger::GameLogStub() + { + __asm + { + push 1 + push[esp + 4h] + call Logger::NetworkLog + add esp, 8h + + mov eax, 4576C0h + jmp eax + } + } + __declspec(naked) void Logger::PrintMessageStub() { __asm @@ -122,6 +146,11 @@ namespace Components retn returnPrint: + push 0 + push [esp + 8h] + call Logger::NetworkLog + add esp, 8h + push esi mov esi, [esp + 0Ch] @@ -143,11 +172,90 @@ namespace Components QuickPatch::OnFrame(Logger::Frame); + Utils::Hook(0x4B0218, Logger::GameLogStub, HOOK_CALL).Install()->Quick(); Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); + + Dvar::OnInit([] () + { + Command::AddSV("log_add", [] (Command::Params params) + { + if (params.Length() < 2) return; + + Network::Address addr(params[1]); + + if (std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr) == Logger::LoggingAddresses[0].end()) + { + Logger::LoggingAddresses[0].push_back(addr); + } + }); + + Command::AddSV("log_del", [] (Command::Params params) + { + if (params.Length() < 2) return; + + Network::Address addr(params[1]); + + auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr); + if (i != Logger::LoggingAddresses[0].end()) + { + Logger::LoggingAddresses[0].erase(i); + } + }); + + Command::AddSV("log_list", [] (Command::Params) + { + Logger::Print("# ID: Address\n"); + Logger::Print("-------------\n"); + + for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i) + { + Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[0][i].GetCString()); + } + }); + + Command::AddSV("glog_add", [] (Command::Params params) + { + if (params.Length() < 2) return; + + Network::Address addr(params[1]); + + if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end()) + { + Logger::LoggingAddresses[1].push_back(addr); + } + }); + + Command::AddSV("glog_del", [] (Command::Params params) + { + if (params.Length() < 2) return; + + Network::Address addr(params[1]); + + auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr); + if (i != Logger::LoggingAddresses[1].end()) + { + Logger::LoggingAddresses[1].erase(i); + } + }); + + Command::AddSV("glog_list", [] (Command::Params) + { + Logger::Print("# ID: Address\n"); + Logger::Print("-------------\n"); + + for (unsigned int i = 0; i < Logger::LoggingAddresses[1].size(); ++i) + { + Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[1][i].GetCString()); + } + }); + }); } Logger::~Logger() { + Logger::LoggingAddresses[0].clear(); + Logger::LoggingAddresses[1].clear(); + Logger::MessageMutex.lock(); Logger::MessageQueue.clear(); Logger::MessageMutex.unlock(); diff --git a/src/Components/Modules/Logger.hpp b/src/Components/Modules/Logger.hpp index 504038e4..8597cddc 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -24,13 +24,17 @@ namespace Components private: static std::mutex MessageMutex; static std::vector MessageQueue; + static std::vector LoggingAddresses[2]; static void(*PipeCallback)(std::string); static void Frame(); + static void GameLogStub(); static void PrintMessageStub(); static void PrintMessagePipe(const char* data); static void EnqueueMessage(std::string message); + static void NetworkLog(const char* data, bool gLog); + static std::string Format(const char** message); }; } From f13ad26dfcb1583d50c1ac0039475e27ca79a36d Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 3 Sep 2016 15:57:19 +0200 Subject: [PATCH 65/81] Frogot to increment variable after pushing to stack --- src/Components/Modules/Logger.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 5fecb00a..9f614366 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -111,6 +111,8 @@ namespace Components void Logger::NetworkLog(const char* data, bool gLog) { + if (!data) return; + std::string buffer(data); for (auto& addr : Logger::LoggingAddresses[gLog & 1]) { @@ -123,7 +125,7 @@ namespace Components __asm { push 1 - push[esp + 4h] + push [esp + 8h] call Logger::NetworkLog add esp, 8h @@ -147,7 +149,7 @@ namespace Components returnPrint: push 0 - push [esp + 8h] + push [esp + 0Ch] call Logger::NetworkLog add esp, 8h From fe6c08acc81303be095f3affe5120f1a264069a7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 3 Sep 2016 16:59:05 +0200 Subject: [PATCH 66/81] Better material fix until is done --- src/Components/Modules/Materials.cpp | 24 +++++++++++++++++++++--- src/Components/Modules/Materials.hpp | 7 +++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index dd9ca412..8830f24f 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -22,12 +22,30 @@ namespace Components Game::Material* Materials::VerifyMaterial(Game::Material* material) { - if (!IsBadReadPtr(material, 4) && !IsBadReadPtr(material->name, 1)) +// if (!IsBadReadPtr(material, 4) && !IsBadReadPtr(material->name, 1)) +// { +// return material; +// } + + Materials::VerifyContainer container = { false, material }; + Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_MATERIAL, [] (Game::XAssetHeader header, void* data) + { + Materials::VerifyContainer* container = reinterpret_cast(data); + + if (container && header.material == container->material) + { + container->isValid = true; + } + }, &container, false); + + if (container.isValid) { return material; } - - return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; + else + { + return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; + } } __declspec(naked) void Materials::DrawMaterialStub() diff --git a/src/Components/Modules/Materials.hpp b/src/Components/Modules/Materials.hpp index 34bbb505..6b9b5bf8 100644 --- a/src/Components/Modules/Materials.hpp +++ b/src/Components/Modules/Materials.hpp @@ -11,6 +11,13 @@ namespace Components #endif private: + class VerifyContainer + { + public: + bool isValid; + Game::Material* material; + }; + static Utils::Hook ImageVersionCheckHook; static void ImageVersionCheck(); From ac6c592e512073387523a9243bfaf4fee11d5972 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 3 Sep 2016 22:44:38 +0200 Subject: [PATCH 67/81] Remove unnecessary thread --- src/Components/Modules/Console.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 6ebb3ae1..c948715c 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -402,15 +402,7 @@ namespace Components // Force process termination // if the main thread is not responding OutputDebugStringA("Process termination forced, as the main thread is not responding!"); - - // We can not force the termination in this thread - // The destructor would be called in this thread - // and would try to join this thread, which is impossible - std::thread([] () - { - std::this_thread::sleep_for(200ms); - ExitProcess(static_cast(-1)); - }).detach(); + ExitProcess(static_cast(-1)); } else { From c993a783cf8096cf690f7403e6ab8705cced6335 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 12:06:48 +0200 Subject: [PATCH 68/81] Optimizte logging over network commands --- src/Components/Modules/AntiCheat.cpp | 12 +++--- src/Components/Modules/Logger.cpp | 56 +++++++++++++++++++++------- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index ed4c3515..2e81dd88 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -591,37 +591,35 @@ namespace Components if (NULL != pSecDesc) { HeapFree(GetProcessHeap(), 0, pSecDesc); - pSecDesc = NULL; } if (NULL != pDacl) { HeapFree(GetProcessHeap(), 0, pDacl); - pDacl = NULL; } + if (psidAdmins) { FreeSid(psidAdmins); - psidAdmins = NULL; } + if (psidSystem) { FreeSid(psidSystem); - psidSystem = NULL; } + if (psidEveryone) { FreeSid(psidEveryone); - psidEveryone = NULL; } + if (NULL != pTokenInfo) { HeapFree(GetProcessHeap(), 0, pTokenInfo); - pTokenInfo = NULL; } + if (NULL != hToken) { CloseHandle(hToken); - hToken = NULL; } } diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 9f614366..5951bfa6 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -195,12 +195,27 @@ namespace Components { if (params.Length() < 2) return; - Network::Address addr(params[1]); - - auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr); - if (i != Logger::LoggingAddresses[0].end()) + int num = atoi(params[1]); + if (fmt::sprintf("%i", num) == params[1] && static_cast(num) < Logger::LoggingAddresses[0].size()) { - Logger::LoggingAddresses[0].erase(i); + auto addr = Logger::LoggingAddresses[0].begin() + num; + Logger::Print("Address %s removed\n", addr->GetCString()); + Logger::LoggingAddresses[0].erase(addr); + } + else + { + Network::Address addr(params[1]); + + auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr); + if (i != Logger::LoggingAddresses[0].end()) + { + Logger::LoggingAddresses[0].erase(i); + Logger::Print("Address %s removed\n", addr.GetCString()); + } + else + { + Logger::Print("Address %s not found!\n", addr.GetCString()); + } } }); @@ -215,7 +230,7 @@ namespace Components } }); - Command::AddSV("glog_add", [] (Command::Params params) + Command::AddSV("g_log_add", [] (Command::Params params) { if (params.Length() < 2) return; @@ -227,20 +242,35 @@ namespace Components } }); - Command::AddSV("glog_del", [] (Command::Params params) + Command::AddSV("g_log_del", [] (Command::Params params) { if (params.Length() < 2) return; - Network::Address addr(params[1]); - - auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr); - if (i != Logger::LoggingAddresses[1].end()) + int num = atoi(params[1]); + if (fmt::sprintf("%i", num) == params[1] && static_cast(num) < Logger::LoggingAddresses[1].size()) { - Logger::LoggingAddresses[1].erase(i); + auto addr = Logger::LoggingAddresses[1].begin() + num; + Logger::Print("Address %s removed\n", addr->GetCString()); + Logger::LoggingAddresses[1].erase(addr); + } + else + { + Network::Address addr(params[1]); + + auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr); + if (i != Logger::LoggingAddresses[1].end()) + { + Logger::LoggingAddresses[1].erase(i); + Logger::Print("Address %s removed\n", addr.GetCString()); + } + else + { + Logger::Print("Address %s not found!\n", addr.GetCString()); + } } }); - Command::AddSV("glog_list", [] (Command::Params) + Command::AddSV("g_log_list", [] (Command::Params) { Logger::Print("# ID: Address\n"); Logger::Print("-------------\n"); From f045863ddc1f05c5177ef038515a79644bf74023 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 12:37:17 +0200 Subject: [PATCH 69/81] Shift version number --- src/Components/Modules/QuickPatch.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 01019f39..d2089fa2 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -170,7 +170,7 @@ namespace Components Utils::Hook::Set(0x45ACE0, 0xC301B0); // fs_basegame - Utils::Hook::Set(0x6431D1, BASEGAME); + Utils::Hook::Set(0x6431D1, BASEGAME); // UI version string Utils::Hook::Set(0x43F73B, "IW4x: " VERSION); @@ -181,6 +181,14 @@ namespace Components // version string Utils::Hook::Set(0x60BD56, "IW4x (" VERSION ")"); + // Shift ui version string to the left (ui_buildlocation) + Utils::Hook::Nop(0x6310A0, 5); // Don't register the initial dvar + Utils::Hook::Nop(0x6310B8, 5); // Don't write the result + Dvar::OnInit([] () + { + *reinterpret_cast(0x62E4B64) = Game::Dvar_RegisterVec2("ui_buildLocation", -80.0f, 15.0f, -10000.0, 10000.0, Game::DVAR_FLAG_READONLY, "Where to draw the build number"); + }); + // console title if (ZoneBuilder::IsEnabled()) { From 4cb707d43da760f75506ee70725f509b84dfa70c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 12:45:47 +0200 Subject: [PATCH 70/81] --- src/Components/Modules/Console.cpp | 3 +++ src/Components/Modules/QuickPatch.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index c948715c..604fb3e1 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -522,6 +522,9 @@ namespace Components FreeConsole(); Utils::Hook::Nop(0x60BB58, 11); + // Redirect input (]command) + Utils::Hook(0x47025A, 0x4F5770, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x60BB68, [] () { Console::ConsoleThread = std::thread(Console::ConsoleRunner); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index d2089fa2..779d2fed 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -170,7 +170,7 @@ namespace Components Utils::Hook::Set(0x45ACE0, 0xC301B0); // fs_basegame - Utils::Hook::Set(0x6431D1, BASEGAME); + Utils::Hook::Set(0x6431D1, BASEGAME); // UI version string Utils::Hook::Set(0x43F73B, "IW4x: " VERSION); From e94d9788d08101a09be6e94bea7931fc8e53946f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 13:06:44 +0200 Subject: [PATCH 71/81] Fix code analysis warnings --- src/Components/Modules/AntiCheat.cpp | 1 - .../Modules/AssetInterfaces/IGfxImage.cpp | 2 +- .../Modules/AssetInterfaces/IPhysPreset.cpp | 2 -- src/Components/Modules/Bans.cpp | 1 - src/Components/Modules/Download.cpp | 7 ------- src/Components/Modules/News.cpp | 1 - src/Components/Modules/Node.cpp | 5 ----- src/Components/Modules/RCon.cpp | 1 - src/Components/Modules/Window.cpp | 1 - src/Utils/IO.cpp | 16 ++++++++++++---- src/Utils/IO.hpp | 2 +- 11 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index 2e81dd88..1c2616ab 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -163,7 +163,6 @@ namespace Components if ((Game::Sys_Milliseconds() - lastCheck) > 1000 * 70) { - // TODO: Move that elsewhere if (HANDLE h = OpenProcess(PROCESS_VM_READ, TRUE, GetCurrentProcessId())) { #ifdef DEBUG_DETECTIONS diff --git a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp index feb08f60..862da050 100644 --- a/src/Components/Modules/AssetInterfaces/IGfxImage.cpp +++ b/src/Components/Modules/AssetInterfaces/IGfxImage.cpp @@ -5,7 +5,7 @@ namespace Assets void IGfxImage::Load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) { Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image; - if (image) return; // TODO: Check for default? + if (image) return; image = builder->GetAllocator()->Allocate(); if (!image) diff --git a/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp b/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp index 304cb60b..763cc95e 100644 --- a/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp +++ b/src/Components/Modules/AssetInterfaces/IPhysPreset.cpp @@ -13,8 +13,6 @@ namespace Assets buffer->PushBlock(Game::XFILE_BLOCK_VIRTUAL); - // TODO: I think we have to write them, even if they are NULL - if (asset->name) { buffer->SaveString(builder->GetAssetName(this->GetType(), asset->name)); diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index d1bdd371..76d1b069 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -110,7 +110,6 @@ namespace Components { Bans::AccessMutex.lock(); - // TODO: Read bans FileSystem::File bans("bans.json"); if (bans.Exists()) diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 8b9fae2c..8fb6bd36 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -542,13 +542,6 @@ namespace Components } else { -// Utils::Hook(0x5AC6E9, [] () -// { -// // TODO: Perform moddownload here -// -// Game::CL_DownloadsComplete(0); -// }, HOOK_CALL).Install()->Quick(); - QuickPatch::OnFrame([] { if (Download::CLDownload.Running) diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index 755ed14b..627d26ac 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -155,7 +155,6 @@ namespace Components Localization::Set("MPUI_MOTD_TEXT", data); } - // TODO: Implement update checks here! if (!Loader::PerformingUnitTests()) { while (!News::Terminate) diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 7c6e8e6f..b2a0fc33 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -768,11 +768,6 @@ namespace Components Node::AddNode(address); } } - else - { - // TODO: Implement client handshake stuff - // Nvm, clients can simply ignore that i guess - } }); Command::Add("listnodes", [] (Command::Params) diff --git a/src/Components/Modules/RCon.cpp b/src/Components/Modules/RCon.cpp index 450caae0..04eeddce 100644 --- a/src/Components/Modules/RCon.cpp +++ b/src/Components/Modules/RCon.cpp @@ -45,7 +45,6 @@ namespace Components } }); - // TODO: Maybe execute that for clients as well, when we use triangular natting. if (!Dedicated::IsEnabled()) return; // Load public key diff --git a/src/Components/Modules/Window.cpp b/src/Components/Modules/Window.cpp index e1f30658..4a755f37 100644 --- a/src/Components/Modules/Window.cpp +++ b/src/Components/Modules/Window.cpp @@ -143,7 +143,6 @@ namespace Components if (Window::CursorVisible) { - // TODO: Apply custom cursor SetCursor(LoadCursor(NULL, IDC_ARROW)); while ((value = ShowCursor(TRUE)) < 0); diff --git a/src/Utils/IO.cpp b/src/Utils/IO.cpp index d953c06a..5fdf05a4 100644 --- a/src/Utils/IO.cpp +++ b/src/Utils/IO.cpp @@ -48,9 +48,9 @@ namespace Utils return buffer; } - void CreateDirectory(std::string dir) + bool CreateDirectory(std::string dir) { - char opath[MAX_PATH]; + char opath[MAX_PATH] = { 0 }; char *p; size_t len; @@ -70,7 +70,10 @@ namespace Utils if (_access(opath, 0)) { - _mkdir(opath); + if (_mkdir(opath) == -1) + { + return false; + } } *p = L'\\'; @@ -79,8 +82,13 @@ namespace Utils if (_access(opath, 0)) { - _mkdir(opath); + if (_mkdir(opath) == -1) + { + return false; + } } + + return true; } } } diff --git a/src/Utils/IO.hpp b/src/Utils/IO.hpp index bc91be09..817eb7d4 100644 --- a/src/Utils/IO.hpp +++ b/src/Utils/IO.hpp @@ -5,6 +5,6 @@ namespace Utils bool FileExists(std::string file); void WriteFile(std::string file, std::string data); std::string ReadFile(std::string file); - void CreateDirectory(std::string dir); + bool CreateDirectory(std::string dir); } } From 5e71960c7e630b496fda31f4414f00480db0c6b3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 17:13:06 +0200 Subject: [PATCH 72/81] IW5 material emedding system --- src/Components/Loader.cpp | 8 +-- src/Components/Modules/Materials.cpp | 92 ++++++++++++++++++++------ src/Components/Modules/Materials.hpp | 13 ++-- src/Components/Modules/StringTable.cpp | 4 ++ 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 411eaf0a..f1a8335c 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -24,9 +24,6 @@ namespace Components Loader::Register(new Maps()); Loader::Register(new News()); Loader::Register(new Node()); -#ifndef DISABLE_BITMESSAGE - Loader::Register(new BitMessage()); -#endif Loader::Register(new RCon()); Loader::Register(new Menus()); Loader::Register(new Toast()); @@ -53,9 +50,11 @@ namespace Components Loader::Register(new Dedicated()); Loader::Register(new Discovery()); Loader::Register(new Exception()); - Loader::Register(new MinidumpUpload()); Loader::Register(new FastFiles()); Loader::Register(new Materials()); +#ifndef DISABLE_BITMESSAGE + Loader::Register(new BitMessage()); +#endif Loader::Register(new FileSystem()); Loader::Register(new QuickPatch()); Loader::Register(new ServerInfo()); @@ -65,6 +64,7 @@ namespace Components Loader::Register(new AssetHandler()); Loader::Register(new Localization()); Loader::Register(new MusicalTalent()); + Loader::Register(new MinidumpUpload()); Loader::Register(new StructuredData()); Loader::Register(new ConnectProtocol()); diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 8830f24f..f257f8d5 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -2,6 +2,7 @@ namespace Components { + int Materials::ImageNameLength; Utils::Hook Materials::ImageVersionCheckHook; __declspec(naked) void Materials::ImageVersionCheck() @@ -20,31 +21,32 @@ namespace Components } } - Game::Material* Materials::VerifyMaterial(Game::Material* material) + Game::Material* Materials::ResolveMaterial(const char* stringPtr) { -// if (!IsBadReadPtr(material, 4) && !IsBadReadPtr(material->name, 1)) -// { -// return material; -// } + const char* imagePtr = stringPtr + 4; + unsigned int length = static_cast(stringPtr[3] & 0xFF); - Materials::VerifyContainer container = { false, material }; - Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_MATERIAL, [] (Game::XAssetHeader header, void* data) + if (strlen(imagePtr) >= length) { - Materials::VerifyContainer* container = reinterpret_cast(data); - - if (container && header.material == container->material) - { - container->isValid = true; - } - }, &container, false); - - if (container.isValid) - { - return material; + Materials::ImageNameLength = 4 + length; + std::string image(imagePtr, length); + + return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material; } - else + + Materials::ImageNameLength = 4; + return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; + } + + __declspec(naked) void Materials::PostDrawMaterialStub() + { + __asm { - return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; + mov eax, Materials::ImageNameLength + add [esp + 30h], eax + + mov eax, 5358FFh + jmp eax } } @@ -52,8 +54,8 @@ namespace Components { __asm { - push eax - call Materials::VerifyMaterial + push ecx + call Materials::ResolveMaterial add esp, 4h mov edx, 5310F0h @@ -61,13 +63,59 @@ namespace Components } } + int Materials::WriteDeathMessageIcon(char* string, int offset, Game::Material* material) + { + if (!material) + { + material = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; + } + + int length = strlen(material->name); + string[offset++] = static_cast(length); + + strncpy_s(string + offset, 1024 - offset, material->name, length); + + return offset + length; + } + + __declspec(naked) void Materials::DeathMessageStub() + { + __asm + { + push edx // Material + push eax // offset + push ecx // String + + call Materials::WriteDeathMessageIcon + + add esp, 14h + retn + } + } + Materials::Materials() { + Materials::ImageNameLength = 7; + // Allow codo images Materials::ImageVersionCheckHook.Initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->Install(); // Fix material pointer exploit Utils::Hook(0x534E0C, Materials::DrawMaterialStub, HOOK_CALL).Install()->Quick(); + + // Increment string pointer accordingly + Utils::Hook(0x5358FA, Materials::PostDrawMaterialStub, HOOK_JUMP).Install()->Quick(); + + // Adapt death message to IW5 material format + Utils::Hook(0x5A30D9, Materials::DeathMessageStub, HOOK_JUMP).Install()->Quick(); + +// Renderer::OnFrame([] () +// { +// Game::Font* font = Game::R_RegisterFont("fonts/normalFont"); +// float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; +// +// Game::R_AddCmdDrawText("test^==preview_mp_rustzob", 0x7FFFFFFF, font, 500.0f, 150.0f, 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); +// }); } Materials::~Materials() diff --git a/src/Components/Modules/Materials.hpp b/src/Components/Modules/Materials.hpp index 6b9b5bf8..2066130f 100644 --- a/src/Components/Modules/Materials.hpp +++ b/src/Components/Modules/Materials.hpp @@ -11,17 +11,16 @@ namespace Components #endif private: - class VerifyContainer - { - public: - bool isValid; - Game::Material* material; - }; + static int ImageNameLength; static Utils::Hook ImageVersionCheckHook; static void ImageVersionCheck(); - static Game::Material* VerifyMaterial(Game::Material* material); + static Game::Material* ResolveMaterial(const char* stringPtr); static void DrawMaterialStub(); + static void PostDrawMaterialStub(); + + static int WriteDeathMessageIcon(char* string, int offset, Game::Material* material); + static void DeathMessageStub(); }; } diff --git a/src/Components/Modules/StringTable.cpp b/src/Components/Modules/StringTable.cpp index 7bf4f0b4..3d0738f7 100644 --- a/src/Components/Modules/StringTable.cpp +++ b/src/Components/Modules/StringTable.cpp @@ -21,6 +21,8 @@ namespace Components Game::StringTable* StringTable::LoadObject(std::string filename) { + filename = Utils::String::ToLower(filename); + Game::StringTable* table = nullptr; FileSystem::File rawTable(filename); @@ -73,6 +75,8 @@ namespace Components { Game::XAssetHeader header = { 0 }; + filename = Utils::String::ToLower(filename); + if (StringTable::StringTableMap.find(filename) != StringTable::StringTableMap.end()) { header.stringTable = StringTable::StringTableMap[filename]; From 7dc18695d49b6b84bc0f08f328eead85184b85bd Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 4 Sep 2016 22:19:47 +0200 Subject: [PATCH 73/81] --- src/Components/Modules/Auth.cpp | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index cebec5ec..ed33eff8 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -391,23 +391,26 @@ namespace Components Logger::Print("Your guid: %llX\n", Steam::SteamUser()->GetSteamID().Bits); }); - Command::Add("securityLevel", [] (Command::Params params) + if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) { - if (params.Length() < 2) + Command::Add("securityLevel", [] (Command::Params params) { - uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey()); - Logger::Print("Your current security level is %d\n", level); - Logger::Print("Your security token is: %s\n", Utils::String::DumpHex(Auth::GuidToken.ToString(), "").data()); - Logger::Print("Your computation token is: %s\n", Utils::String::DumpHex(Auth::ComputeToken.ToString(), "").data()); + if (params.Length() < 2) + { + uint32_t level = Auth::GetZeroBits(Auth::GuidToken, Auth::GuidKey.GetPublicKey()); + Logger::Print("Your current security level is %d\n", level); + Logger::Print("Your security token is: %s\n", Utils::String::DumpHex(Auth::GuidToken.ToString(), "").data()); + Logger::Print("Your computation token is: %s\n", Utils::String::DumpHex(Auth::ComputeToken.ToString(), "").data()); - Toast::Show("cardicon_locked", "^5Security Level", fmt::sprintf("Your security level is %d", level), 3000); - } - else - { - uint32_t level = static_cast(atoi(params[1])); - Auth::IncreaseSecurityLevel(level); - } - }); + Toast::Show("cardicon_locked", "^5Security Level", fmt::sprintf("Your security level is %d", level), 3000); + } + else + { + uint32_t level = static_cast(atoi(params[1])); + Auth::IncreaseSecurityLevel(level); + } + }); + } UIScript::Add("security_increase_cancel", [] () { From e43a645712b3c552b782fd6f0bbf2e6e2d6a298a Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 5 Sep 2016 19:54:16 +0200 Subject: [PATCH 74/81] Fixes and update command structure --- deps/mongoose | 2 +- deps/protobuf | 2 +- src/Components/Modules/Command.cpp | 6 ++++-- src/Components/Modules/Command.hpp | 2 +- src/Components/Modules/Console.cpp | 10 +++++++++- src/Components/Modules/Lean.cpp | 8 ++++---- src/Game/Functions.hpp | 2 +- src/Game/Structs.hpp | 2 +- 8 files changed, 22 insertions(+), 12 deletions(-) diff --git a/deps/mongoose b/deps/mongoose index 36405545..5f93f716 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 36405545033489ccfeb6c139c6e609998efc3cf9 +Subproject commit 5f93f7162f23949050335e9b1518c90a9fc0944d diff --git a/deps/protobuf b/deps/protobuf index 96a9d973..9b8da104 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 96a9d97352436c7284e8194e103ca8d92649ad02 +Subproject commit 9b8da104c12a2947b6e6d7a7da30a3ae56b31675 diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index 6b4939c0..b09b5da1 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -70,9 +70,9 @@ namespace Components Command::FunctionMapSV[command] = callback; } - void Command::AddRaw(const char* name, void(*callback)()) + void Command::AddRaw(const char* name, void(*callback)(), bool key) { - Game::Cmd_AddCommand(name, callback, Command::Allocate(), 0); + Game::Cmd_AddCommand(name, callback, Command::Allocate(), key); } void Command::AddRawSV(const char* name, void(*callback)()) @@ -145,6 +145,8 @@ namespace Components Command::Command() { + Assert_Size(Game::cmd_function_t, 24); + // Disable native noclip command Utils::Hook::Nop(0x474846, 5); diff --git a/src/Components/Modules/Command.hpp b/src/Components/Modules/Command.hpp index 7a4401d8..b429ec6c 100644 --- a/src/Components/Modules/Command.hpp +++ b/src/Components/Modules/Command.hpp @@ -34,7 +34,7 @@ namespace Components static void Add(const char* name, Callback* callback); static void AddSV(const char* name, Callback* callback); - static void AddRaw(const char* name, void(*callback)()); + static void AddRaw(const char* name, void(*callback)(), bool key = false); static void AddRawSV(const char* name, void(*callback)()); static void Execute(std::string command, bool sync = true); diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 604fb3e1..0cd17fa5 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -402,7 +402,15 @@ namespace Components // Force process termination // if the main thread is not responding OutputDebugStringA("Process termination forced, as the main thread is not responding!"); - ExitProcess(static_cast(-1)); + + // We can not force the termination in this thread + // The destructor would be called in this thread + // and would try to join this thread, which is impossible + std::thread([] () + { + std::this_thread::sleep_for(200ms); + ExitProcess(static_cast(-1)); + }).detach(); } else { diff --git a/src/Components/Modules/Lean.cpp b/src/Components/Modules/Lean.cpp index a0830b3e..7d794284 100644 --- a/src/Components/Modules/Lean.cpp +++ b/src/Components/Modules/Lean.cpp @@ -58,11 +58,11 @@ namespace Components Lean::Lean() { - Game::Cmd_AddCommand("+leanleft", Lean::IN_LeanLeft_Down, Command::Allocate(), 1); - Game::Cmd_AddCommand("-leanleft", Lean::IN_LeanLeft_Up, Command::Allocate(), 1); + Command::AddRaw("+leanleft", Lean::IN_LeanLeft_Down, true); + Command::AddRaw("-leanleft", Lean::IN_LeanLeft_Up, true); - Game::Cmd_AddCommand("+leanright", Lean::IN_LeanRight_Down, Command::Allocate(), 1); - Game::Cmd_AddCommand("-leanright", Lean::IN_LeanRight_Up, Command::Allocate(), 1); + Command::AddRaw("+leanright", Lean::IN_LeanRight_Down, true); + Command::AddRaw("-leanright", Lean::IN_LeanRight_Up, true); Utils::Hook(0x5A6D84, Lean::CL_CmdButtonsStub, HOOK_CALL).Install()->Quick(); } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index c3f29b05..a5adfcab 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -36,7 +36,7 @@ namespace Game typedef void(__cdecl * CL_SelectStringTableEntryInDvar_f_t)(); extern CL_SelectStringTableEntryInDvar_f_t CL_SelectStringTableEntryInDvar_f; - typedef void(__cdecl * Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, char); + typedef void(__cdecl * Cmd_AddCommand_t)(const char* cmdName, void(*function), cmd_function_t* allocedCmd, bool isKey); extern Cmd_AddCommand_t Cmd_AddCommand; typedef void(__cdecl * Cmd_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 1da60c32..ea949aeb 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -136,7 +136,7 @@ namespace Game const char *autoCompleteDir; const char *autoCompleteExt; void(__cdecl *function)(); - int unknown; + bool isKey; // Looks like this is true when the command is a key/button } cmd_function_t; #pragma pack(push, 4) From 7ed67debfc4d19b33912a01d4abd1170a704aa00 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 5 Sep 2016 19:55:47 +0200 Subject: [PATCH 75/81] Start working on issue --- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 1 + src/Components/Modules/PlayerName.cpp | 33 +++++++++++++++++++++++++++ src/Components/Modules/PlayerName.hpp | 18 +++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 src/Components/Modules/PlayerName.cpp create mode 100644 src/Components/Modules/PlayerName.hpp diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index f1a8335c..90e40d33 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -56,6 +56,7 @@ namespace Components Loader::Register(new BitMessage()); #endif Loader::Register(new FileSystem()); + Loader::Register(new PlayerName()); Loader::Register(new QuickPatch()); Loader::Register(new ServerInfo()); Loader::Register(new ServerList()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index e5d1080b..00883999 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -69,6 +69,7 @@ namespace Components #include "Modules\Singleton.hpp" #include "Modules\BitMessage.hpp" #include "Modules\FileSystem.hpp" +#include "Modules\PlayerName.hpp" #include "Modules\QuickPatch.hpp" #include "Modules\ServerInfo.hpp" #include "Modules\ServerList.hpp" diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp new file mode 100644 index 00000000..90257b04 --- /dev/null +++ b/src/Components/Modules/PlayerName.cpp @@ -0,0 +1,33 @@ +#include "STDInclude.hpp" + +namespace Components +{ + std::string PlayerName::PlayerNames[18]; + + int PlayerName::GetClientName(int /*localClientNum*/, int index, char *buf, int size) + { + if (index < 0 || index >= 18) return 0; + return strncpy_s(buf, size, PlayerName::PlayerNames[index].data(), PlayerName::PlayerNames[index].size()) == 0; + } + + PlayerName::PlayerName() + { + if (0) + { + for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) + { + PlayerName::PlayerNames[i] = "mumu"; + } + + Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).Install()->Quick(); + } + } + + PlayerName::~PlayerName() + { + for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) + { + PlayerName::PlayerNames[i].clear(); + } + } +} diff --git a/src/Components/Modules/PlayerName.hpp b/src/Components/Modules/PlayerName.hpp new file mode 100644 index 00000000..d9442ab3 --- /dev/null +++ b/src/Components/Modules/PlayerName.hpp @@ -0,0 +1,18 @@ +namespace Components +{ + class PlayerName : public Component + { + public: + PlayerName(); + ~PlayerName(); + +#ifdef DEBUG + const char* GetName() { return "PlayerName"; }; +#endif + + private: + static std::string PlayerNames[18]; + + static int GetClientName(int localClientNum, int index, char *buf, int size); + }; +} From d6ade559588a28570519360f88887b136ae6ec3c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 5 Sep 2016 19:57:17 +0200 Subject: [PATCH 76/81] Add comment and update mongoose --- deps/mongoose | 2 +- src/Components/Modules/PlayerName.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deps/mongoose b/deps/mongoose index 5f93f716..2a541175 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 5f93f7162f23949050335e9b1518c90a9fc0944d +Subproject commit 2a541175b56a1aeecd2dc8474f981923ef580af6 diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp index 90257b04..9e5595a3 100644 --- a/src/Components/Modules/PlayerName.cpp +++ b/src/Components/Modules/PlayerName.cpp @@ -12,7 +12,7 @@ namespace Components PlayerName::PlayerName() { - if (0) + if (0) // Disabled for now (comment out that line to enable it) { for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) { From 8fb6ea0b634b0231983e54e0ce1cbc92fa7e31c1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 5 Sep 2016 21:58:59 +0200 Subject: [PATCH 77/81] Use lock guards for mutex locking --- src/Components/Modules/Bans.cpp | 4 +--- src/Components/Modules/BitMessage.cpp | 4 ++-- src/Components/Modules/Logger.cpp | 3 +-- src/Components/Modules/ServerList.cpp | 8 ++------ src/STDInclude.cpp | 12 ++++++++---- src/Utils/Hooking.cpp | 5 +---- 6 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index 76d1b069..3e0f0c07 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -108,7 +108,7 @@ namespace Components void Bans::LoadBans(Bans::BanList* list) { - Bans::AccessMutex.lock(); + std::lock_guard _(Bans::AccessMutex); FileSystem::File bans("bans.json"); @@ -161,8 +161,6 @@ namespace Components } } } - - Bans::AccessMutex.unlock(); } void Bans::BanClientNum(int num, std::string reason) diff --git a/src/Components/Modules/BitMessage.cpp b/src/Components/Modules/BitMessage.cpp index 727583ad..7a2e6cb4 100644 --- a/src/Components/Modules/BitMessage.cpp +++ b/src/Components/Modules/BitMessage.cpp @@ -251,7 +251,7 @@ Logger::Print("Initializing BitMessage...\n"); } // Resolve our own copy to the registered PubAddr copy in BitMRC if possible - auto resolvedAddress = FindPublicKey(address); + auto resolvedAddress = BitMessage::FindPublicKey(address); if (resolvedAddress != nullptr && !resolvedAddress->waitingPubKey() && !resolvedAddress->getPubEncryptionKey().empty()) return true; @@ -261,7 +261,7 @@ Logger::Print("Initializing BitMessage...\n"); { // Request public key BitMessage::BMClient->getPubKey(address); - resolvedAddress = FindPublicKey(address); + resolvedAddress = BitMessage::FindPublicKey(address); } BitMessage::Save(); diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 5951bfa6..7b0a66a3 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -80,7 +80,7 @@ namespace Components void Logger::Frame() { - Logger::MessageMutex.lock(); + std::lock_guard _(Logger::MessageMutex); for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) { @@ -93,7 +93,6 @@ namespace Components } Logger::MessageQueue.clear(); - Logger::MessageMutex.unlock(); } void Logger::PipeOutput(void(*callback)(std::string)) diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index 06aa5454..f234e760 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -381,7 +381,7 @@ namespace Components void ServerList::Insert(Network::Address address, Utils::InfoString info) { - ServerList::RefreshContainer.Mutex.lock(); + std::lock_guard _(ServerList::RefreshContainer.Mutex); for (auto i = ServerList::RefreshContainer.Servers.begin(); i != ServerList::RefreshContainer.Servers.end();) { @@ -469,8 +469,6 @@ namespace Components ++i; } } - - ServerList::RefreshContainer.Mutex.unlock(); } ServerList::ServerInfo* ServerList::GetCurrentServer() @@ -625,7 +623,7 @@ namespace Components ServerList::RefreshContainer.AwatingList = false; - ServerList::RefreshContainer.Mutex.lock(); + std::lock_guard _(ServerList::RefreshContainer.Mutex); int offset = 0; int count = ServerList::RefreshContainer.Servers.size(); @@ -649,8 +647,6 @@ namespace Components } Logger::Print("Parsed %d servers from master\n", ServerList::RefreshContainer.Servers.size() - count); - - ServerList::RefreshContainer.Mutex.unlock(); }); // Set default masterServerName + port and save it diff --git a/src/STDInclude.cpp b/src/STDInclude.cpp index 3c2ddf00..037fe84b 100644 --- a/src/STDInclude.cpp +++ b/src/STDInclude.cpp @@ -17,6 +17,10 @@ Assert_Size(DWORD, 4); Assert_Size(WORD, 2); Assert_Size(BYTE, 1); +// 128 bit integers (only x64) +//Assert_Size(__int128, 16); +//Assert_Size(unsigned __int128, 16); + // 64 bit integers Assert_Size(__int64, 8); Assert_Size(unsigned __int64, 8); @@ -64,8 +68,8 @@ static_assert(sizeof(intptr_t) == 4 && sizeof(void*) == 4 && sizeof(size_t) == 4 // Disable telemetry data logging extern "C" { - void _cdecl __vcrt_initialize_telemetry_provider() {} - void _cdecl __telemetry_main_invoke_trigger() {} - void _cdecl __telemetry_main_return_trigger() {} - void _cdecl __vcrt_uninitialize_telemetry_provider() {} + void __cdecl __vcrt_initialize_telemetry_provider() {} + void __cdecl __telemetry_main_invoke_trigger() {} + void __cdecl __telemetry_main_return_trigger() {} + void __cdecl __vcrt_uninitialize_telemetry_provider() {} }; diff --git a/src/Utils/Hooking.cpp b/src/Utils/Hooking.cpp index d8928327..3ab1c563 100644 --- a/src/Utils/Hooking.cpp +++ b/src/Utils/Hooking.cpp @@ -136,11 +136,10 @@ namespace Utils Hook* Hook::Install(bool unprotect, bool keepUnportected) { - Hook::StateMutex.lock(); + std::lock_guard _(Hook::StateMutex); if (!Hook::Initialized || Hook::Installed) { - Hook::StateMutex.unlock(); return this; } @@ -159,8 +158,6 @@ namespace Utils FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); - Hook::StateMutex.unlock(); - return this; } From 9298e5688f36c3cbc67dc3924379a925212f5088 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 6 Sep 2016 21:31:12 +0200 Subject: [PATCH 78/81] Temporary fix --- deps/bitmrc | 2 +- deps/protobuf | 2 +- src/Components/Modules/Bans.cpp | 4 +--- src/Components/Modules/Toast.cpp | 4 +--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/deps/bitmrc b/deps/bitmrc index 52aa771b..43f63eeb 160000 --- a/deps/bitmrc +++ b/deps/bitmrc @@ -1 +1 @@ -Subproject commit 52aa771b9274056eb1e30b5c7fbfd1669c053265 +Subproject commit 43f63eeb1f900fd03b192e7e577c033a6be072ab diff --git a/deps/protobuf b/deps/protobuf index 9b8da104..74638a25 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 9b8da104c12a2947b6e6d7a7da30a3ae56b31675 +Subproject commit 74638a253ea76baa0aed78491b92d157326295a6 diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index 3e0f0c07..3f6cbc23 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -39,7 +39,7 @@ namespace Components Bans::BanList list; Bans::LoadBans(&list); - Bans::AccessMutex.lock(); + std::lock_guard _(Bans::AccessMutex); if (entry.first.Bits) { @@ -102,8 +102,6 @@ namespace Components FileSystem::FileWriter ban("bans.json"); ban.Write(bans.dump()); - - Bans::AccessMutex.unlock(); } void Bans::LoadBans(Bans::BanList* list) diff --git a/src/Components/Modules/Toast.cpp b/src/Components/Modules/Toast.cpp index 2279de8d..f60f1f2e 100644 --- a/src/Components/Modules/Toast.cpp +++ b/src/Components/Modules/Toast.cpp @@ -103,7 +103,7 @@ namespace Components { if (Toast::Queue.empty()) return; - Toast::Mutex.lock(); + std::lock_guard _(Toast::Mutex); Toast::UIToast* toast = &Toast::Queue.front(); @@ -121,8 +121,6 @@ namespace Components { Toast::Draw(toast); } - - Toast::Mutex.unlock(); } Toast::Toast() From af21b8a6d9a14b6af55369c06bd2f6bc2d5326de Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 8 Sep 2016 21:41:01 +0200 Subject: [PATCH 79/81] Optimize moddownload --- deps/protobuf | 2 +- src/Components/Modules/Download.cpp | 77 +++++++++++++++++-------- src/Components/Modules/Download.hpp | 16 ++--- src/Components/Modules/Localization.cpp | 16 ++++- src/Components/Modules/Localization.hpp | 1 + src/Components/Modules/Menus.cpp | 1 + src/Utils/String.cpp | 22 +++++++ src/Utils/String.hpp | 1 + 8 files changed, 102 insertions(+), 34 deletions(-) diff --git a/deps/protobuf b/deps/protobuf index 74638a25..14e74f6a 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 74638a253ea76baa0aed78491b92d157326295a6 +Subproject commit 14e74f6a21f2726d25e0e679c59d569f6bc8fe8e diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 8fb6bd36..5e819aeb 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -11,11 +11,11 @@ namespace Components { if (Download::CLDownload.Running) return; - Download::CLDownload.Mutex.lock(); - Download::CLDownload.Progress = "Downloading mod"; - Download::CLDownload.Mutex.unlock(); + Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(0)); + Localization::SetTemp("MPUI_PROGRESS_DL", "(0/0) %"); + Localization::SetTemp("MPUI_TRANS_RATE", "0.0 MB/s"); - Command::Execute("openmenu popup_reconnectingtoparty", true); + Command::Execute("openmenu mod_download_popmenu", true); Download::CLDownload.Running = true; Download::CLDownload.Mod = mod; @@ -35,6 +35,8 @@ namespace Components if (!error.empty() || !listData.is_array()) return false; + download->TotalBytes = 0; + for (auto& file : listData.array_items()) { if (!file.is_object()) return false; @@ -53,6 +55,7 @@ namespace Components if (!fileEntry.Name.empty()) { download->Files.push_back(fileEntry); + download->TotalBytes += fileEntry.Size; } } @@ -75,12 +78,32 @@ namespace Components if (ev == MG_EV_RECV) { - fDownload->receivedBytes += static_cast(*reinterpret_cast(ev_data)); + size_t bytes = static_cast(*reinterpret_cast(ev_data)); + fDownload->receivedBytes += bytes; + fDownload->download->DownBytes += bytes; + fDownload->download->TimeStampBytes += bytes; - double progress = (100.0 / fDownload->file.Size) * fDownload->receivedBytes; - fDownload->download->Mutex.lock(); - fDownload->download->Progress = fmt::sprintf("Downloading file (%d/%d) %s %d%%", fDownload->index + 1, fDownload->download->Files.size(), fDownload->file.Name.data(), static_cast(progress)); - fDownload->download->Mutex.unlock(); + double progress = (100.0 / fDownload->download->TotalBytes) * fDownload->download->DownBytes; + Localization::SetTemp("MPUI_PROGRESS_DL", fmt::sprintf("(%d/%d) %d%%", fDownload->index + 1, fDownload->download->Files.size(), static_cast(progress))); + + int delta = Game::Sys_Milliseconds() - fDownload->download->LastTimeStamp; + if (delta > 300) + { + bool doFormat = fDownload->download->LastTimeStamp != 0; + fDownload->download->LastTimeStamp = Game::Sys_Milliseconds(); + + size_t dataLeft = fDownload->download->TotalBytes - fDownload->download->DownBytes; + double timeLeftD = ((1.0 * dataLeft) / fDownload->download->TimeStampBytes) * delta; + int timeLeft = static_cast(timeLeftD); + + if (doFormat) + { + Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(timeLeft)); + Localization::SetTemp("MPUI_TRANS_RATE", Utils::String::FormatBandwidth(fDownload->download->TimeStampBytes, delta)); + } + + fDownload->download->TimeStampBytes = 0; + } } if (ev == MG_EV_HTTP_REPLY) @@ -98,10 +121,6 @@ namespace Components auto file = download->Files[index]; - download->Mutex.lock(); - download->Progress = fmt::sprintf("Downloading file (%d/%d) %s 0%%", index + 1, download->Files.size(), file.Name.data()); - download->Mutex.unlock(); - std::string path = download->Mod + "/" + file.Name; if (Utils::IO::FileExists(path)) { @@ -109,6 +128,7 @@ namespace Components if (data.size() == file.Size && Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(data), "") == file.Hash) { + download->TotalBytes += file.Size; return true; } } @@ -122,6 +142,8 @@ namespace Components fDownload.downloading = true; fDownload.receivedBytes = 0; + Utils::String::Replace(url, " ", "%20"); + download->Valid = true; mg_mgr_init(&download->Mgr, &fDownload); mg_connect_http(&download->Mgr, Download::DownloadHandler, url.data(), NULL, NULL); @@ -154,6 +176,8 @@ namespace Components if (list.empty()) { + if (download->TerminateThread) return; + download->Thread.detach(); download->Clear(); @@ -169,6 +193,8 @@ namespace Components if (!Download::ParseModList(download, list)) { + if (download->TerminateThread) return; + download->Thread.detach(); download->Clear(); @@ -182,21 +208,27 @@ namespace Components if (download->TerminateThread) return; + static std::string mod = download->Mod; + for (unsigned int i = 0; i < download->Files.size(); ++i) { if (download->TerminateThread) return; if (!Download::DownloadFile(download, i)) { - Dvar::Var("partyend_reason").Set(fmt::sprintf("Failed to download file: %s!", download->Files[i].Name.data())); + if (download->TerminateThread) return; + mod = fmt::sprintf("Failed to download file: %s!", download->Files[i].Name.data()); download->Thread.detach(); download->Clear(); QuickPatch::Once([] () { + Dvar::Var("partyend_reason").Set(mod); + mod.clear(); + Localization::ClearTemp(); - Command::Execute("closemenu popup_reconnectingtoparty"); + Command::Execute("closemenu mod_download_popmenu"); Command::Execute("openmenu menu_xboxlive_partyended"); }); @@ -206,8 +238,6 @@ namespace Components if (download->TerminateThread) return; - static std::string mod = download->Mod; - download->Thread.detach(); download->Clear(); @@ -221,7 +251,7 @@ namespace Components mod.clear(); Localization::ClearTemp(); - Command::Execute("closemenu popup_reconnectingtoparty", true); + Command::Execute("closemenu mod_download_popmenu", true); if (Dvar::Var("cl_modVidRestart").Get()) { @@ -346,6 +376,8 @@ namespace Components Utils::String::Replace(url, "\\", "/"); url = url.substr(6); + Utils::String::Replace(url, "%20", " "); + if (url.find_first_of("/") != std::string::npos || (!Utils::String::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL) { Download::Forbid(nc); @@ -542,14 +574,9 @@ namespace Components } else { - QuickPatch::OnFrame([] + UIScript::Add("mod_download_cancel", [] () { - if (Download::CLDownload.Running) - { - Download::CLDownload.Mutex.lock(); - Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", Download::CLDownload.Progress); - Download::CLDownload.Mutex.unlock(); - } + Download::CLDownload.Clear(); }); } } diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index f0f97266..7a32e4c0 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -16,7 +16,7 @@ namespace Components class ClientDownload { public: - ClientDownload() : Valid(false), Running(false), TerminateThread(false) {} + ClientDownload() : Valid(false), Running(false), TerminateThread(false), TotalBytes(0), DownBytes(0), LastTimeStamp(0), TimeStampBytes(0) {} ~ClientDownload() { this->Clear(); } bool Running; @@ -25,10 +25,13 @@ namespace Components mg_mgr Mgr; Network::Address Target; std::string Mod; - std::mutex Mutex; std::thread Thread; - std::string Progress; + size_t TotalBytes; + size_t DownBytes; + + int LastTimeStamp; + size_t TimeStampBytes; class File { @@ -58,10 +61,6 @@ namespace Components this->Valid = false; mg_mgr_free(&(this->Mgr)); } - - this->Mutex.lock(); - this->Progress.clear(); - this->Mutex.unlock(); } }; @@ -71,10 +70,13 @@ namespace Components ClientDownload* download; ClientDownload::File file; + int timestamp; bool downloading; unsigned int index; std::string buffer; size_t receivedBytes; + + }; static mg_mgr Mgr; diff --git a/src/Components/Modules/Localization.cpp b/src/Components/Modules/Localization.cpp index f9d9115d..52361182 100644 --- a/src/Components/Modules/Localization.cpp +++ b/src/Components/Modules/Localization.cpp @@ -2,6 +2,7 @@ namespace Components { + std::mutex Localization::LocalizeMutex; Dvar::Var Localization::UseLocalization; Utils::Memory::Allocator Localization::MemAllocator; std::map Localization::LocalizeMap; @@ -9,6 +10,8 @@ namespace Components void Localization::Set(std::string key, std::string value) { + std::lock_guard _(Localization::LocalizeMutex); + if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end()) { Game::LocalizedEntry* entry = Localization::LocalizeMap[key]; @@ -46,6 +49,7 @@ namespace Components if (!Localization::UseLocalization.Get()) return key; Game::LocalizedEntry* entry = nullptr; + std::lock_guard _(Localization::LocalizeMutex); if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end()) { @@ -56,7 +60,12 @@ namespace Components entry = Localization::LocalizeMap[key]; } - if (!entry || !entry->value) entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE, key).localize; + if (!entry || !entry->value) + { + Localization::LocalizeMutex.unlock(); + entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE, key).localize; + Localization::LocalizeMutex.lock(); + } if (entry && entry->value) { @@ -68,6 +77,8 @@ namespace Components void Localization::SetTemp(std::string key, std::string value) { + std::lock_guard _(Localization::LocalizeMutex); + if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end()) { Game::LocalizedEntry* entry = Localization::TempLocalizeMap[key]; @@ -100,6 +111,8 @@ namespace Components void Localization::ClearTemp() { + std::lock_guard _(Localization::LocalizeMutex); + for (auto i = Localization::TempLocalizeMap.begin(); i != Localization::TempLocalizeMap.end(); ++i) { if (i->second) @@ -131,6 +144,7 @@ namespace Components AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE, [] (Game::XAssetType, std::string filename) { Game::XAssetHeader header = { 0 }; + std::lock_guard _(Localization::LocalizeMutex); if (Localization::TempLocalizeMap.find(filename) != Localization::TempLocalizeMap.end()) { diff --git a/src/Components/Modules/Localization.hpp b/src/Components/Modules/Localization.hpp index 3880f048..a7a27bba 100644 --- a/src/Components/Modules/Localization.hpp +++ b/src/Components/Modules/Localization.hpp @@ -17,6 +17,7 @@ namespace Components static void ClearTemp(); private: + static std::mutex LocalizeMutex; static Utils::Memory::Allocator MemAllocator; static std::map LocalizeMap; static std::map TempLocalizeMap; diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index db2b2a1b..6259bc30 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -674,6 +674,7 @@ namespace Components Menus::Add("ui_mp/stats_reset.menu"); Menus::Add("ui_mp/stats_unlock.menu"); Menus::Add("ui_mp/security_increase_popmenu.menu"); + Menus::Add("ui_mp/mod_download_popmenu.menu"); } Menus::~Menus() diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index f303014d..0e2da5f8 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -119,6 +119,28 @@ namespace Utils return fmt::sprintf("%02d:%02d:%02d", hoursTotal, minutes, seconds); } + std::string FormatBandwidth(size_t bytes, int milliseconds) + { + static char* sizes[] = + { + "B", + "KB", + "MB", + "GB", + "TB" + }; + + double bytesPerSecond = (1000.0 / milliseconds) * bytes; + + int i = 0; + for (i = 0; bytesPerSecond > 1000 && i < ARRAY_SIZE(sizes); ++i) // 1024 or 1000? + { + bytesPerSecond /= 1000; + } + + return fmt::sprintf("%.2f %s/s", static_cast(bytesPerSecond), sizes[i]); + } + // Encodes a given string in Base64 std::string EncodeBase64(const char* input, const unsigned long inputSize) { diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 6ca9cc57..33312035 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -35,6 +35,7 @@ namespace Utils std::string &Trim(std::string &s); std::string FormatTimeSpan(int milliseconds); + std::string FormatBandwidth(size_t bytes, int milliseconds); std::string DumpHex(std::string data, std::string separator = " "); From daac5489d9b38137f3a7413a6b757323c0f2a6c3 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 8 Sep 2016 21:46:12 +0200 Subject: [PATCH 80/81] Free console earlier --- src/Components/Modules/Console.cpp | 9 ++++++++- src/Components/Modules/Console.hpp | 2 ++ src/Components/Modules/Singleton.cpp | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 0cd17fa5..55f3fd26 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -483,6 +483,14 @@ namespace Components Console::SkipShutdown = true; } + void Console::FreeNativeConsole() + { + if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) + { + FreeConsole(); + } + } + Console::Console() { // Console '%s: %s> ' string @@ -527,7 +535,6 @@ namespace Components } else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted. { - FreeConsole(); Utils::Hook::Nop(0x60BB58, 11); // Redirect input (]command) diff --git a/src/Components/Modules/Console.hpp b/src/Components/Modules/Console.hpp index fc38497e..49d7e1e4 100644 --- a/src/Components/Modules/Console.hpp +++ b/src/Components/Modules/Console.hpp @@ -15,6 +15,8 @@ namespace Components static void SetSkipShutdown(); + static void FreeNativeConsole(); + private: // Text-based console stuff static WINDOW* OutputWindow; diff --git a/src/Components/Modules/Singleton.cpp b/src/Components/Modules/Singleton.cpp index bb13be4f..1a50fa5b 100644 --- a/src/Components/Modules/Singleton.cpp +++ b/src/Components/Modules/Singleton.cpp @@ -17,6 +17,8 @@ namespace Components ExitProcess(0); } + Console::FreeNativeConsole(); + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return; Singleton::FirstInstance = (CreateMutexA(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS); From fa18695898066eb473f499bd23ac39b7eac0d97a Mon Sep 17 00:00:00 2001 From: momo5502 Date: Thu, 8 Sep 2016 21:53:58 +0200 Subject: [PATCH 81/81] Unload mod --- src/Components/Modules/Party.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 9ff29dde..ed693242 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -383,6 +383,17 @@ namespace Components Command::Execute("closemenu popup_reconnectingtoparty"); Download::InitiateClientDownload(info.Get("fs_game")); } + else if (!Dvar::Var("fs_game").Get().empty() && info.Get("fs_game").empty()) + { + Dvar::Var("fs_game").Set(""); + + if (Dvar::Var("cl_modVidRestart").Get()) + { + Command::Execute("vid_restart", false); + } + + Command::Execute("reconnect", false); + } else { if (Party::Container.MatchType == 1) // Party