[+] IIOHandle::InitFromSharing

[+] IIOHandle::SharingGetString
[+] IIOHandle::SharingIsShared
[+] IIOHandle::SharingStop
[+] HANDLEPipeServer.[h/c]pp
This commit is contained in:
Reece Wilson 2024-01-03 02:39:54 +00:00
parent 1c0efebd87
commit ce1ae24506
8 changed files with 511 additions and 0 deletions

View File

@ -111,6 +111,8 @@ namespace Aurora::IO
virtual bool InitFromStreamEnum(EStandardStream eStream) = 0;
virtual bool InitFromSharing(const AuString &handle) = 0;
virtual AuUInt64 GetOSHandle() const = 0;
virtual AuOptionalEx<AuUInt64> GetOSHandleSafe() const = 0;
@ -147,6 +149,12 @@ namespace Aurora::IO
virtual bool SectionUnlock(AuUInt64 uOffset,
AuUInt64 uLength) = 0;
virtual AuString SharingGetString() = 0;
virtual bool SharingIsShared() = 0;
virtual void SharingStop() = 0;
};
AUKN_SHARED_SOO_CC(IOHandle, IIOHandle, 256);

View File

@ -0,0 +1,22 @@
/***
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: HANDLEPipeServer.hpp
Date: 2024-01-02
Author: Reece
Note: These file is excluded from the default include tree.
You must explicitly include this via:
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include <Aurora/IO/NT/HANDLEPipeServer.hpp>
#endif
***/
#pragma once
namespace Aurora::IO::NT
{
AUKN_SYM AuString ShareFileDescriptor(HANDLE hHandle);
AUKN_SYM void ShareFileDescriptorStop(const AuString &handle);
AUKN_SYM HANDLE ShareFileDescriptorAccept(const AuString &handle);
}

View File

@ -29,6 +29,9 @@
#include "Extensions/Win32/DarkTheme.hpp"
#include <timeapi.h>
#endif
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include <Source/IO/NT/HANDLEPipeServer.hpp>
#endif
#include "Debug/MemoryCrunch.hpp"
#include "Process/Process.hpp"
#include "Exit/AuExit.hpp"
@ -160,6 +163,10 @@ static void RuntimeLateClean()
Aurora::Processes::Deinit();
#if defined(AURORA_IS_MODERNNT_DERIVED)
Aurora::IO::NT::ShutdownNTIPCHandleServer();
#endif
// Static variables we should probably manually release ->
// (there is no real logic under the following functions)
Aurora::IO::Deinit();

View File

@ -9,6 +9,14 @@
#include "AuIOHandle.hpp"
#include "FS/FileAdvisory.hpp"
#if defined(AURORA_IS_MODERNNT_DERIVED)
#include <Aurora/IO/NT/HANDLEPipeServer.hpp>
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
#include <Aurora/IO/UNIX/UNIX.hpp>
#endif
namespace Aurora::IO
{
AFileHandle::~AFileHandle()
@ -303,6 +311,87 @@ namespace Aurora::IO
return FS::UnapplyFileSectionLock(AuUnsafeRaiiToShared(this), uOffset, uLength);
}
bool AFileHandle::InitFromSharing(const AuString &handle)
{
if (this->uOSReadHandle ||
this->uOSWriteHandle)
{
return false;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
auto hHandle = NT::ShareFileDescriptorAccept(handle);
if (hHandle == INVALID_HANDLE_VALUE)
{
return false;
}
auto uOSWriteHandle = AuUInt(hHandle);
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
auto iHandle = UNIX::ShareFileDescriptorAccept(handle);
if (iHandle == -1 ||
iHandle == 0)
{
return false;
}
auto uOSWriteHandle = AuUInt(iHandle);
this->uOSReadHandle = uOSWriteHandle;
this->uOSWriteHandle = uOSWriteHandle;
#endif
return true;
}
AuString AFileHandle::SharingGetString()
{
AuString handle;
if (this->pIPCString)
{
return *this->pIPCString;
}
#if defined(AURORA_IS_MODERNNT_DERIVED)
handle = NT::ShareFileDescriptor((HANDLE)this->GetOSHandleSafe().ValueOr(-1));
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
handle = UNIX::ShareFileDescriptor((HANDLE)this->GetOSHandleSafe().ValueOr(-1));
#endif
if (handle.empty())
{
return {};
}
this->pIPCString = AuMakeSharedPanic<AuString>(handle);
return *this->pIPCString;
}
bool AFileHandle::SharingIsShared()
{
return bool(this->pIPCString);
}
void AFileHandle::SharingStop()
{
if (auto pString = AuExchange(this->pIPCString, {}))
{
#if defined(AURORA_IS_MODERNNT_DERIVED)
NT::ShareFileDescriptorStop(*pString);
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
UNIX::ShareFileDescriptorStop(*pString);
#endif
}
}
AUKN_SYM IIOHandle *IOHandleNew()
{
return _new AFileHandle();

View File

@ -32,6 +32,8 @@ namespace Aurora::IO
bool InitFromStreamEnum(EStandardStream eStream) override;
bool InitFromSharing(const AuString &handle) override;
bool InitFromPath(HandleCreate create) override;
AuUInt64 GetOSHandle() const override;
@ -70,6 +72,10 @@ namespace Aurora::IO
bool SectionUnlock(AuUInt64 uOffset,
AuUInt64 uLength) override;
AuString SharingGetString() override;
bool SharingIsShared() override;
void SharingStop() override;
AuOptionalEx<AuUInt64> uOSWriteHandle;
AuOptionalEx<AuUInt64> uOSReadHandle;
@ -81,6 +87,7 @@ namespace Aurora::IO
mutable AuOptional<bool> optIsFile;
mutable AuOptional<bool> optIsPipe;
mutable AuOptional<bool> optIsTTY;
mutable AuSPtr<AuString> pIPCString;
protected:
// Implement me:

View File

@ -391,7 +391,11 @@ namespace Aurora::IO::IPC
auto path = token.ToNTPath();
#if defined(AURORA_PLATFORM_WIN32)
auto name = "\\\\.\\pipe\\" + token.ToNTPath();
#else
auto name = "\\\\.\\pipe\\LOCAL\\" + token.ToNTPath();
#endif
auto pageSize = AuHwInfo::GetPageSize();
auto maxLength = uBytesLength ? AuPageRound(uBytesLength, pageSize) : pageSize ? 16 * pageSize : 4096;
auto pipeServer = CreateNamedPipeA(name.c_str(),
@ -450,7 +454,11 @@ namespace Aurora::IO::IPC
return {};
}
#if defined(AURORA_PLATFORM_WIN32)
auto name = "\\\\.\\pipe\\" + token->token.ToNTPath();
#else
auto name = "\\\\.\\pipe\\LOCAL\\" + token->token.ToNTPath();
#endif
pipe = CreateFileA(name.c_str(),
GENERIC_WRITE | GENERIC_READ,
0,

View File

@ -0,0 +1,357 @@
/***
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: HANDLEPipeServer.cpp
Date: 2024-01-02
Author: Reece
Note: Rushed Windows HANDLE sharing of any unnamed kernel object
***/
#include <Source/RuntimeInternal.hpp>
#include <Source/IO/IPC/AuIPCHandle.hpp>
namespace Aurora::IO::NT
{
static AuMutex gMutex;
static AuBST<AuUInt32, HANDLE> gHANDLECookieMap;
static AuThreads::ThreadUnique_t gServerThread {};
static const auto kDefaultMessageSize = 8192u;
static AuString GetIPCServerNameOfPid(AuUInt32 uPid)
{
#if defined(AURORA_PLATFORM_WIN32)
return fmt::format("\\\\.\\pipe\\_HANDLESOF_{}", uPid);
#else
return fmt::format("\\\\.\\pipe\\LOCAL\\_HANDLESOF_{}", uPid);
#endif
}
HANDLE GetHandleForToken(AuUInt32 uToken)
{
AU_LOCK_GUARD(gMutex);
auto itr = gHANDLECookieMap.find(uToken);
if (itr != gHANDLECookieMap.end())
{
return itr->second;
}
else
{
return INVALID_HANDLE_VALUE;
}
}
// TODO: use AuLoop
DWORD WINAPI WaitForCookieThread(LPVOID lpvParam)
{
AuUInt32 uTokenID {};
HANDLE hHandle { INVALID_HANDLE_VALUE }, hPipe { (HANDLE)lpvParam };
DWORD dwBytesRead {}, dwWritten {};
BOOL bSuccess { true };
if (!lpvParam)
{
return (DWORD)-1;
}
do
{
bSuccess = ReadFile(hPipe,
&uTokenID,
sizeof(uTokenID),
&dwBytesRead,
NULL);
if (!bSuccess ||
dwBytesRead == 0)
{
if (GetLastError() != ERROR_BROKEN_PIPE)
{
SysPushErrorIO("IO HANDLE Server Error");
}
break;
}
hHandle = GetHandleForToken(uTokenID);
if (hHandle == INVALID_HANDLE_VALUE)
{
SysPushErrorIO("Tried to serve bad token: {}", uTokenID);
break;
}
{
ULONG pid {};
if (!GetNamedPipeClientProcessId(hPipe, &pid))
{
SysPushErrorIO("IO HANDLE Server Error");
break;
}
HANDLE hProcess {};
if (!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid)))
{
SysPushErrorIO("IO HANDLE Server Error");
break;
}
if (!DuplicateHandle(GetCurrentProcess(),
hHandle,
hProcess,
&hHandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS))
{
SysPushErrorIO("IO HANDLE Server Error");
break;
}
}
bSuccess = WriteFile(hPipe,
&hHandle,
sizeof(hHandle),
&dwWritten,
NULL);
if (!bSuccess ||
sizeof(hHandle) != sizeof(HANDLE))
{
SysPushErrorIO("IO HANDLE Server Error");
break;
}
}
while (false);
AuWin32CloseHandle(hPipe);
return bSuccess ? 0 : (DWORD)-1;
}
static void IPCServer()
{
HANDLE hPipe = INVALID_HANDLE_VALUE;
HANDLE hThread = NULL;
auto name = GetIPCServerNameOfPid(GetCurrentProcessId());
while (AuIsThreadRunning())
{
// TODO: use AuLoop
hPipe = CreateNamedPipeA(name.c_str(),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE |
PIPE_READMODE_MESSAGE |
PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
kDefaultMessageSize,
kDefaultMessageSize,
0,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
SysPushErrorIOResourceFailure("NO IPC Handle Server");
return;
}
if (ConnectNamedPipe(hPipe, NULL) ||
(GetLastError() == ERROR_PIPE_CONNECTED))
{
// TODO: use AuLoop
hThread = CreateThread(NULL,
0,
WaitForCookieThread,
(LPVOID)hPipe,
0,
NULL);
if (hThread == NULL)
{
DisconnectNamedPipe(hPipe);
}
else
{
AuWin32CloseHandle(hThread);
}
}
else
{
AuWin32CloseHandle(hPipe);
}
}
}
static void StartServerIfNotAlready()
{
static AuInitOnce gInitOnce;
gInitOnce.Call([]()
{
gServerThread = AuThreads::Spawn(IPCServer);
SysAssert(gServerThread, "No NT Handle Server Thread");
gServerThread->SetName("Microsoft NT HANDLE IPC Server/IPC-Provider");
});
}
bool FDServe(HANDLE hHandle, IPC::IPCToken &outHandle)
{
if (!hHandle ||
hHandle == INVALID_HANDLE_VALUE)
{
return false;
}
{
StartServerIfNotAlready();
}
{
AU_LOCK_GUARD(gMutex);
do
{
outHandle.cookie = AuRng::RngU32();
}
while (AuExists(gHANDLECookieMap, outHandle.cookie));
outHandle.word = outHandle.cookie;
outHandle.pid = GetCurrentProcessId();
outHandle.path[0] = '\x00'; // msvc removing something it shouldn't have?
//strcat(outHandle.path, AuToString(outHandle.cookie).c_str()); // ignore warning
return AuTryInsert(gHANDLECookieMap, AuConstReference(outHandle.cookie), AuConstReference(hHandle));
}
}
void FDServeEnd(const IPC::IPCToken &handle)
{
AU_LOCK_GUARD(gMutex);
AuTryRemove(gHANDLECookieMap, handle.cookie);
}
bool FDAccept(const IPC::IPCToken &handle, HANDLE &outHandle)
{
outHandle = INVALID_HANDLE_VALUE;
HANDLE hPipe {};
HANDLE hHandle {};
BOOL bSuccess {};
DWORD dwWritten {};
auto name = GetIPCServerNameOfPid(handle.pid);
hPipe = CreateFileA(name.c_str(),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_PIPE_BUSY)
{
SysPushErrorIO("Pipe is used -> a client has already connected or the nt server is not ready");
return false;
}
else
{
SysPushErrorIO("No Server: {}", GetLastError());
return false;
}
}
bSuccess = WriteFile(hPipe,
&handle.cookie,
sizeof(AuUInt32),
&dwWritten,
NULL);
if (!bSuccess)
{
AuWin32CloseHandle(hPipe);
SysPushErrorIO("No Server");
return false;
}
FlushFileBuffers(hPipe);
bSuccess = ReadFile(hPipe,
&hHandle,
sizeof(hHandle),
&dwWritten,
NULL);
if (!bSuccess)
{
AuWin32CloseHandle(hPipe);
SysPushErrorIO("No Handle");
return false;
}
outHandle = hHandle;
return true;
}
void ShutdownNTIPCHandleServer()
{
gServerThread.reset();
}
AUKN_SYM AuString ShareFileDescriptor(HANDLE hHandle)
{
IPC::IPCToken token;
IPC::IPCHandle handle;
if (!FDServe(hHandle, token))
{
return {};
}
handle.pid = token.pid;
handle.PushId(IPC::EIPCHandleType::eIPCSharedFd, token);
return handle.ToString();
}
AUKN_SYM void ShareFileDescriptorStop(const AuString &handle)
{
IPC::IPCHandle handle2;
if (!handle2.FromString(handle))
{
SysPushErrorIO("Invalid handle string");
return;
}
if (auto val = handle2.GetToken(IPC::EIPCHandleType::eIPCSharedFd, 0))
{
FDServeEnd(val->token);
}
else
{
SysPushErrorSyntax("Invalid handle string");
}
}
AUKN_SYM HANDLE ShareFileDescriptorAccept(const AuString &handle)
{
IPC::IPCHandle handle2;
HANDLE hHandle { INVALID_HANDLE_VALUE };
if (!handle2.FromString(handle))
{
SysPushErrorIO("Invalid handle string");
return hHandle;
}
auto val = handle2.GetToken(IPC::EIPCHandleType::eIPCSharedFd, 0);
if (!val)
{
SysPushErrorSyntax("Invalid handle string");
return hHandle;
}
if (!FDAccept(val->token, hHandle))
{
SysPushErrorNested();
return hHandle;
}
return hHandle;
}
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2024 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: HANDLEPipeServer.hpp
Date: 2024-01-02
Author: Reece
***/
#pragma once
namespace Aurora::IO::NT
{
void ShutdownNTIPCHandleServer();
}