From 06033ce3cc03d2d93f313120d6d1c86fd18504c6 Mon Sep 17 00:00:00 2001 From: TheIronWolfModding Date: Thu, 29 Mar 2018 10:19:55 -0700 Subject: [PATCH] Plugin: add support for DedicatedServerMapGlobally preference. --- Include/MappedBuffer.h | 103 ++++++++++++++++----- Include/rFactor2SharedMemoryMap.hpp | 3 +- README.md | 9 ++ Source/rFactor2SharedMemoryMap.cpp | 36 +++++-- VC12/rFactor2SharedMemoryMapPlugin.vcxproj | 2 +- 5 files changed, 124 insertions(+), 29 deletions(-) diff --git a/Include/MappedBuffer.h b/Include/MappedBuffer.h index b7c390f..c3c9e4f 100644 --- a/Include/MappedBuffer.h +++ b/Include/MappedBuffer.h @@ -16,6 +16,8 @@ Website: thecrewchief.org EndUpdate once they're done. */ #pragma once +#include +#include "Utils.h" template class MappedBuffer @@ -31,10 +33,10 @@ class MappedBuffer ReleaseResources(); } - bool Initialize() + bool Initialize(bool mapGlobally) { assert(!mMapped); - mhMap = MapMemoryFile(MM_FILE_NAME, mpMappedView, mpBuffVersionBlock, mpBuff); + mhMap = MapMemoryFile(MM_FILE_NAME, mapGlobally, mpMappedView, mpBuffVersionBlock, mpBuff); if (mhMap == nullptr) { DEBUG_MSG(DebugLevel::Errors, "Failed to map file"); ReleaseResources(); @@ -144,31 +146,90 @@ class MappedBuffer MappedBuffer(MappedBuffer const&) = delete; MappedBuffer& operator=(MappedBuffer const&) = delete; - HANDLE MapMemoryFile(char const* const fileName, LPVOID& pMappedView, rF2MappedBufferVersionBlock*& pBufVersionBlock, BuffT*& pBuf) const + HANDLE MapMemoryFile(char const* const fileName, bool dedicatedServerMapGlobally, LPVOID& pMappedView, rF2MappedBufferVersionBlock*& pBufVersionBlock, BuffT*& pBuf) const { - char mappingName[256] = {}; - strcpy_s(mappingName, fileName); - char moduleName[1024] = {}; ::GetModuleFileNameA(nullptr, moduleName, sizeof(moduleName)); - char pid[8] = {}; - sprintf(pid, "%d", ::GetCurrentProcessId()); - - // Append processId for dedicated server to allow multiple instances - // TODO: Verify for rF2. - if (strstr(moduleName, "Dedicated.exe") != nullptr) - strcat(mappingName, pid); + char mappingName[MAX_PATH] = {}; + auto isDedicatedServer = true; + if (strstr(moduleName, "Dedicated.exe") == nullptr) + strcpy_s(mappingName, fileName); // Regular client use. + else { + // Dedicated server use. Append processId for dedicated server to allow multiple instances. + char pid[8] = {}; + sprintf(pid, "%d", ::GetCurrentProcessId()); + + if (dedicatedServerMapGlobally) + sprintf(mappingName, "Global\\%s%s", fileName, pid); + else + sprintf(mappingName, "%s%s", fileName, pid); + + isDedicatedServer = true; + } - // Init handle and try to create, read if existing - auto hMap = ::CreateFileMappingA( - INVALID_HANDLE_VALUE, - nullptr /*lpFileMappingAttributes*/, - PAGE_READWRITE, - 0 /*dwMaximumSizeLow*/, - sizeof(rF2MappedBufferVersionBlock) + sizeof(BuffT), - mappingName); + HANDLE hMap = INVALID_HANDLE_VALUE; + if (!isDedicatedServer // Regular client use. + || (isDedicatedServer && !dedicatedServerMapGlobally)) { // Dedicated, but no global mapping requested. + // Init handle and try to create, read if existing. + hMap = ::CreateFileMappingA( + INVALID_HANDLE_VALUE, + nullptr /*lpFileMappingAttributes*/, + PAGE_READWRITE, + 0 /*dwMaximumSizeLow*/, + sizeof(rF2MappedBufferVersionBlock) + sizeof(BuffT), + mappingName); + } + else { + assert(isDedicatedServer); + assert(dedicatedServerMapGlobally); + + SECURITY_ATTRIBUTES security = {}; + security.nLength = sizeof(security); + + /*SECURITY_ATTRIBUTES security = {}; + SECURITY_DESCRIPTOR secDesc = {}; + + if (::InitializeSecurityDescriptor(&secDesc, SECURITY_DESCRIPTOR_REVISION) + && ::SetSecurityDescriptorDacl(&secDesc, TRUE, static_cast(0), FALSE)) + { + security.nLength = sizeof(security); + security.lpSecurityDescriptor = &secDesc; + security.bInheritHandle = TRUE; + } + else { + DEBUG_MSG2(DebugLevel::Errors, "Failed to create security descriptor for mapping:", mappingName); + SharedMemoryPlugin::TraceLastWin32Error(); + ::LocalFree(security.lpSecurityDescriptor); + return nullptr; + }*/ + + auto ret = ConvertStringSecurityDescriptorToSecurityDescriptor( + "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GA;;;WD)", + SDDL_REVISION_1, + &security.lpSecurityDescriptor, + nullptr); + + auto onExit = MakeScopeGuard([&]() { + ::LocalFree(security.lpSecurityDescriptor); + }); + + if (!ret) { + DEBUG_MSG2(DebugLevel::Errors, "Failed to create security descriptor for mapping:", mappingName); + SharedMemoryPlugin::TraceLastWin32Error(); + return nullptr; + } + // Init handle and try to create, read if existing + hMap = ::CreateFileMappingA( + INVALID_HANDLE_VALUE, + &security, + PAGE_READWRITE, + 0 /*dwMaximumSizeLow*/, + sizeof(rF2MappedBufferVersionBlock) + sizeof(BuffT), + mappingName); + } + if (hMap == nullptr) { DEBUG_MSG2(DebugLevel::Errors, "Failed to create file mapping for file:", mappingName); SharedMemoryPlugin::TraceLastWin32Error(); diff --git a/Include/rFactor2SharedMemoryMap.hpp b/Include/rFactor2SharedMemoryMap.hpp index 25998f0..941ba51 100644 --- a/Include/rFactor2SharedMemoryMap.hpp +++ b/Include/rFactor2SharedMemoryMap.hpp @@ -27,7 +27,7 @@ Website: thecrewchief.org // Each component can be in [0:99] range. #define PLUGIN_VERSION_MAJOR "3.0" -#define PLUGIN_VERSION_MINOR "0.1" +#define PLUGIN_VERSION_MINOR "1.0" #define PLUGIN_NAME_AND_VERSION "rFactor 2 Shared Memory Map Plugin - v" PLUGIN_VERSION_MAJOR #define SHARED_MEMORY_VERSION PLUGIN_VERSION_MAJOR "." PLUGIN_VERSION_MINOR @@ -74,6 +74,7 @@ class SharedMemoryPlugin : public InternalsPluginV07 // REMINDER: exported func static DebugLevel msDebugOutputLevel; static bool msDebugISIInternals; + static bool msDedicatedServerMapGlobally; // Ouptut files: static FILE* msDebugFile; diff --git a/README.md b/README.md index d4c003c..111bcd3 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ Plugin comes with rF2SMMonitor program that shows how to access exposed internal * Advanced: If you would like to make sure you're not reading a torn (partially overwritten) frame, see `rF2SMMonitor.MainForm.MappedBuffer<>.GetMappedData` for sample implementation. +## Dedicated server use +If ran in dedicated server process, each shared memory buffer name has server PID appended. If DedicatedServerMapGlobally preference is set to 1, plugin will attempt creating shared memory buffers in the Global section. Note that "Create Global Objects" permission is needed on user account running dedicated server. + ## Distribution and reuse You are allowed to include this .dll with your distribution, as long as it is: * Free @@ -48,12 +51,18 @@ Please also be aware, that Crew Chief will always ship with the latest version o ## Current known clients * Crew Chief: https://github.com/mrbelowski/CrewChiefV4 * SimHub: https://github.com/zegreatclan/AssettoCorsaTools/wiki +* rFactor 2 Log Analyzer: https://forum.studio-397.com/index.php?threads/rfactor2-log-analyzer-ver-2-with-offline-and-league-championship-manager.48117/ ## Support this project If you would like to support this project, you can donate [here.](http://thecrewchief.org/misc.php?do=donate) # Release history +03/29/2018 - v3.0.1.0 + + Plugin: + * Add DedicatedServerMapGlobally preference to allow mapping dedicated server shared memory buffers to global section, so that users running under other accounts can access them. Note that "Create Global Objects" permission is needed on user account running dedicated server. + 02/21/2018 - v3.0.0.1 Hotfix for physics options not being captured. diff --git a/Source/rFactor2SharedMemoryMap.cpp b/Source/rFactor2SharedMemoryMap.cpp index 877eef5..f4174b6 100644 --- a/Source/rFactor2SharedMemoryMap.cpp +++ b/Source/rFactor2SharedMemoryMap.cpp @@ -16,6 +16,10 @@ Shared resources: Shared resources use the following naming convention: - $rFactor2SMMP_$ + or + - $rFactor2SMMP_$PID where PID is dedicated server process PID. + or + - Global\\$rFactor2SMMP_$PID if running in dedicated server and DedicatedServerMapGlobally option is set to 1. where is one of the following: * Telemetry - mapped view of rF2Telemetry structure @@ -82,6 +86,11 @@ Hosted Stock Car Rules plugin: are always empty (game clears them out in between plugin calls). See PluginHost.h/.cpp for more. +Dedicated server use: + If ran in dedicated server process, each shared memory buffer name has server PID appended. If DedicatedServerMapGlobally + preference is set to 1, plugin will attempt creating shared memory buffers in the Global section. Note that "Create Global Objects" + permission is needed on user account running dedicated server. + Configuration: Standard rF2 plugin configuration is used. See: SharedMemoryPlugin::AccessCustomVariable. @@ -110,6 +119,7 @@ static double const MICROSECONDS_IN_SECOND = MILLISECONDS_IN_SECOND * MICROSECON DebugLevel SharedMemoryPlugin::msDebugOutputLevel = DebugLevel::Off; bool SharedMemoryPlugin::msDebugISIInternals = false; bool SharedMemoryPlugin::msStockCarRulesPluginRequested = false; +bool SharedMemoryPlugin::msDedicatedServerMapGlobally = false; FILE* SharedMemoryPlugin::msDebugFile; FILE* SharedMemoryPlugin::msIsiTelemetryFile; @@ -166,32 +176,33 @@ void SharedMemoryPlugin::Startup(long version) DEBUG_INT2(DebugLevel::CriticalInfo, "EnableStockCarRulesPlugin:", SharedMemoryPlugin::msStockCarRulesPluginRequested); DEBUG_INT2(DebugLevel::CriticalInfo, "DebugOutputLevel:", SharedMemoryPlugin::msDebugOutputLevel); DEBUG_INT2(DebugLevel::CriticalInfo, "DebugISIInternals:", SharedMemoryPlugin::msDebugISIInternals); + DEBUG_INT2(DebugLevel::CriticalInfo, "DedicatedServerMapGlobally:", SharedMemoryPlugin::msDedicatedServerMapGlobally); char temp[80] = {}; sprintf(temp, "-STARTUP- (version %.3f)", (float)version / 1000.0f); WriteToAllExampleOutputFiles("w", temp); - if (!mTelemetry.Initialize()) { + if (!mTelemetry.Initialize(SharedMemoryPlugin::msDedicatedServerMapGlobally)) { DEBUG_MSG(DebugLevel::Errors, "Failed to initialize telemetry mapping"); return; } - if (!mScoring.Initialize()) { + if (!mScoring.Initialize(SharedMemoryPlugin::msDedicatedServerMapGlobally)) { DEBUG_MSG(DebugLevel::Errors, "Failed to initialize scoring mapping"); return; } - if (!mRules.Initialize()) { + if (!mRules.Initialize(SharedMemoryPlugin::msDedicatedServerMapGlobally)) { DEBUG_MSG(DebugLevel::Errors, "Failed to initialize rules mapping"); return; } - if (!mMultiRules.Initialize()) { + if (!mMultiRules.Initialize(SharedMemoryPlugin::msDedicatedServerMapGlobally)) { DEBUG_MSG(DebugLevel::Errors, "Failed to initialize multi rules mapping"); return; } - if (!mExtended.Initialize()) { + if (!mExtended.Initialize(SharedMemoryPlugin::msDedicatedServerMapGlobally)) { DEBUG_MSG(DebugLevel::Errors, "Failed to initialize extended mapping"); return; } @@ -979,6 +990,12 @@ bool SharedMemoryPlugin::GetCustomVariable(long i, CustomVariableV01& var) var.mCurrentSetting = 0; return true; } + else if (i == 4) { + strcpy_s(var.mCaption, "DedicatedServerMapGlobally"); + var.mNumSettings = 2; + var.mCurrentSetting = 0; + return true; + } return false; } @@ -1002,6 +1019,8 @@ void SharedMemoryPlugin::AccessCustomVariable(CustomVariableV01& var) } else if (_stricmp(var.mCaption, "DebugISIInternals") == 0) SharedMemoryPlugin::msDebugISIInternals = var.mCurrentSetting != 0; + else if (_stricmp(var.mCaption, "DedicatedServerMapGlobally") == 0) + SharedMemoryPlugin::msDedicatedServerMapGlobally = var.mCurrentSetting != 0; } @@ -1029,7 +1048,12 @@ void SharedMemoryPlugin::GetCustomVariableSetting(CustomVariableV01& var, long i else strcpy_s(setting.mName, "True"); } - + else if (_stricmp(var.mCaption, "DedicatedServerMapGlobally") == 0) { + if (i == 0) + strcpy_s(setting.mName, "False"); + else + strcpy_s(setting.mName, "True"); + } } diff --git a/VC12/rFactor2SharedMemoryMapPlugin.vcxproj b/VC12/rFactor2SharedMemoryMapPlugin.vcxproj index 12218d7..b33f6fb 100644 --- a/VC12/rFactor2SharedMemoryMapPlugin.vcxproj +++ b/VC12/rFactor2SharedMemoryMapPlugin.vcxproj @@ -20,7 +20,7 @@ {0f4496aa-02de-43c9-bebb-4cd84d9b1843} - 8.1 + 10.0.16299.0