Skip to content

Commit

Permalink
Plugin: add support for DedicatedServerMapGlobally preference.
Browse files Browse the repository at this point in the history
  • Loading branch information
TheIronWolfModding committed Mar 29, 2018
1 parent 8c60246 commit 06033ce
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 29 deletions.
103 changes: 82 additions & 21 deletions Include/MappedBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Website: thecrewchief.org
EndUpdate once they're done.
*/
#pragma once
#include <sddl.h>
#include "Utils.h"

template <typename BuffT>
class MappedBuffer
Expand All @@ -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();
Expand Down Expand Up @@ -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<PACL>(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();
Expand Down
3 changes: 2 additions & 1 deletion Include/rFactor2SharedMemoryMap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
36 changes: 30 additions & 6 deletions Source/rFactor2SharedMemoryMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ Shared resources:
Shared resources use the following naming convention:
- $rFactor2SMMP_<BUFFER_TYPE>$
or
- $rFactor2SMMP_<BUFFER_TYPE>$PID where PID is dedicated server process PID.
or
- Global\\$rFactor2SMMP_<BUFFER_TYPE>$PID if running in dedicated server and DedicatedServerMapGlobally option is set to 1.
where <BUFFER_TYPE> is one of the following:
* Telemetry - mapped view of rF2Telemetry structure
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}


Expand Down Expand Up @@ -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");
}
}


Expand Down
2 changes: 1 addition & 1 deletion VC12/rFactor2SharedMemoryMapPlugin.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0f4496aa-02de-43c9-bebb-4cd84d9b1843}</ProjectGuid>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
Expand Down

0 comments on commit 06033ce

Please sign in to comment.