Preparing for initial WSA network POC rewrite, not porting gen1 code. Linux support is way behind. Will work on it soon.
[*] Minor refactors [*] Begin refactoring the Processes subsystem [*] Added empty files ready to move the gross c++ functional callback in the parse subsystem to a dedicated interface w/ utils [*] Broke out Win32 Process into an NT base variant (Process.NT.cpp) with Win32 overloaded process exit pokes (Process.Win32.cpp)
This commit is contained in:
parent
a6f96315f3
commit
19ebdf3761
@ -22,14 +22,14 @@ namespace Aurora::Crypto::AES
|
|||||||
// Initialization vectors could be derived from SHA1, Tiger, or SHA2 digests
|
// Initialization vectors could be derived from SHA1, Tiger, or SHA2 digests
|
||||||
AUKN_SYM bool Encrypt(const Memory::MemoryViewRead &plainText,
|
AUKN_SYM bool Encrypt(const Memory::MemoryViewRead &plainText,
|
||||||
const Memory::MemoryViewRead &inIv,
|
const Memory::MemoryViewRead &inIv,
|
||||||
const Memory::MemoryViewWrite &outIv,
|
const Memory::MemoryViewWrite &outIv, // optional
|
||||||
const Memory::MemoryViewRead &inKey,
|
const Memory::MemoryViewRead &inKey,
|
||||||
Memory::ByteBuffer &out,
|
Memory::ByteBuffer &out,
|
||||||
bool auCoolCodePadding);
|
bool auCoolCodePadding);
|
||||||
|
|
||||||
AUKN_SYM bool Decrypt(const Memory::MemoryViewRead &cipherText,
|
AUKN_SYM bool Decrypt(const Memory::MemoryViewRead &cipherText,
|
||||||
const Memory::MemoryViewRead &inIv,
|
const Memory::MemoryViewRead &inIv,
|
||||||
const Memory::MemoryViewWrite &outIv,
|
const Memory::MemoryViewWrite &outIv, // optional
|
||||||
const Memory::MemoryViewRead &inKey,
|
const Memory::MemoryViewRead &inKey,
|
||||||
Memory::ByteBuffer &plainText,
|
Memory::ByteBuffer &plainText,
|
||||||
bool auCoolCodePadding);
|
bool auCoolCodePadding);
|
||||||
|
@ -18,25 +18,20 @@ namespace Aurora::Debug
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Retrieves a print-friendly callstack of the last trap (either innocent exception or fatal mem access) <br>
|
Retrieves a print-friendly callstack of the last trap (either innocent exception or fatal mem access) <br>
|
||||||
On Win32, this information is always available <br>
|
On Win32, this information is always available
|
||||||
On other platforms, this function will likely yield no valuable information
|
|
||||||
*/
|
*/
|
||||||
AUKN_SYM AuString GetLastErrorStack();
|
AUKN_SYM AuString GetLastErrorStack();
|
||||||
|
|
||||||
AUKN_SYM StackTrace GetLastStackTrace();
|
AUKN_SYM StackTrace GetLastStackTrace();
|
||||||
|
|
||||||
AUKN_SYM StackTrace GetStackTrace();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Retrieve information about the last exception. <br>
|
Retrieve information about the last exception.
|
||||||
On Win32, this information is always available <br>
|
On Win32, this information is always available
|
||||||
On other platforms, this information is only available within C++14 catch blocks
|
|
||||||
*/
|
*/
|
||||||
AUKN_SYM AuString GetLastException();
|
AUKN_SYM AuString GetLastException();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Retrieve the last system error (IE: Win32, GetLastError())
|
Retrieve the last system error (Example -> Win32, GetLastError())
|
||||||
*/
|
*/
|
||||||
AUKN_SYM OSError_t GetLastSystemMessage();
|
AUKN_SYM OSError_t GetLastSystemMessage();
|
||||||
|
|
||||||
@ -53,6 +48,9 @@ namespace Aurora::Debug
|
|||||||
|
|
||||||
AUKN_SYM void CheckErrors();
|
AUKN_SYM void CheckErrors();
|
||||||
|
|
||||||
|
|
||||||
|
AUKN_SYM StackTrace GetStackTrace();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Immediately terminates the process.
|
Immediately terminates the process.
|
||||||
May attempt some hardened telemetry debug ops
|
May attempt some hardened telemetry debug ops
|
||||||
|
@ -12,7 +12,7 @@ namespace Aurora::Hashing
|
|||||||
class IHashStream
|
class IHashStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*
|
/**
|
||||||
* Digest length of pBuf bytes
|
* Digest length of pBuf bytes
|
||||||
*/
|
*/
|
||||||
virtual void Ingest(const void *pBuf, AuUInt32 length) = 0;
|
virtual void Ingest(const void *pBuf, AuUInt32 length) = 0;
|
||||||
|
12
Include/Aurora/IO/Character/Character.hpp
Normal file
12
Include/Aurora/IO/Character/Character.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: Character.hpp
|
||||||
|
Date: 2022-1-29
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ICharacterProvider.hpp"
|
||||||
|
#include "IBufferedCharacterConsumer.hpp"
|
||||||
|
#include "ILineBufferer.hpp"
|
13
Include/Aurora/IO/Character/IBufferedCharacterConsumer.hpp
Normal file
13
Include/Aurora/IO/Character/IBufferedCharacterConsumer.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: IBufferedCharacterConsumer.hpp
|
||||||
|
Date: 2022-1-29
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::IO::Character
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
15
Include/Aurora/IO/Character/ICharacterProvider.hpp
Normal file
15
Include/Aurora/IO/Character/ICharacterProvider.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: ICharacterProvider.hpp
|
||||||
|
Date: 2022-1-29
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::IO::Character
|
||||||
|
{
|
||||||
|
AUKN_INTERFACE(ICharacterProvider,
|
||||||
|
AUI_METHOD(AuUInt8, GetByte, ())
|
||||||
|
);
|
||||||
|
}
|
13
Include/Aurora/IO/Character/ILineBufferer.hpp
Normal file
13
Include/Aurora/IO/Character/ILineBufferer.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: ILineBufferer.hpp
|
||||||
|
Date: 2022-1-29
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::IO::Character
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -33,7 +33,7 @@ namespace Aurora::IO::Net
|
|||||||
eIPProtocolV6
|
eIPProtocolV6
|
||||||
));
|
));
|
||||||
|
|
||||||
struct IPAddress
|
struct AUKN_SYM IPAddress
|
||||||
{
|
{
|
||||||
EIPProtocol ip;
|
EIPProtocol ip;
|
||||||
union
|
union
|
||||||
@ -42,10 +42,17 @@ namespace Aurora::IO::Net
|
|||||||
AuUInt16 v6[8];
|
AuUInt16 v6[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
AUKN_SYM IPAddress(const AuString &parse);
|
IPAddress();
|
||||||
|
IPAddress(const AuString &parse);
|
||||||
|
|
||||||
AUKN_SYM AuString ToString();
|
AuString ToString() const;
|
||||||
AUKN_SYM bool IsValid();
|
bool IsValid() const;
|
||||||
|
|
||||||
|
|
||||||
|
inline operator bool() const
|
||||||
|
{
|
||||||
|
return IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
inline bool operator ==(const IPAddress &cmp) const
|
inline bool operator ==(const IPAddress &cmp) const
|
||||||
{
|
{
|
||||||
@ -268,7 +275,7 @@ namespace Aurora::IO::Net
|
|||||||
// Attempts to seek backwards or forwards in the UDP or TCP packet
|
// Attempts to seek backwards or forwards in the UDP or TCP packet
|
||||||
// If you are under the callstack of a HasXXXHasData callback, you are guaranteed (bufferedReadSize - streamPosition - streamRemaining) bytes backwards
|
// If you are under the callstack of a HasXXXHasData callback, you are guaranteed (bufferedReadSize - streamPosition - streamRemaining) bytes backwards
|
||||||
//
|
//
|
||||||
virtual bool SeekAsync(int signedDistanceFromCur = 0);
|
virtual bool SeekAsync(int signedDistanceFromCur = 0) = 0;
|
||||||
|
|
||||||
// When BufferInputStreamAdhoc is called with false / in the default condition, read sync will be constrained by the async buffer
|
// When BufferInputStreamAdhoc is called with false / in the default condition, read sync will be constrained by the async buffer
|
||||||
// When BufferInputStreamAdhoc is called with true, you will block until you can get the requested data (all of it if, all = true; any of it, all = false)
|
// When BufferInputStreamAdhoc is called with true, you will block until you can get the requested data (all of it if, all = true; any of it, all = false)
|
||||||
@ -415,18 +422,42 @@ namespace Aurora::IO::Net
|
|||||||
virtual AuSPtr<ISocketFactory> GetSocketFactory() = 0;
|
virtual AuSPtr<ISocketFactory> GetSocketFactory() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AUKN_SYM WorkRange
|
||||||
|
{
|
||||||
|
WorkRange();
|
||||||
|
|
||||||
|
AuUInt8 workerOffsetOrAny;
|
||||||
|
AuUInt8 workerCountOrAny;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AUKN_SYM WorkPoolGroup
|
||||||
|
{
|
||||||
|
WorkPoolGroup();
|
||||||
|
|
||||||
|
AuSPtr<Async::IThreadPool> pool; // optional -> defaults to async apps core loop
|
||||||
|
AuUInt8 asyncWorkGroup;
|
||||||
|
AuUInt8 asyncWorkPoolOffsetOrAny;
|
||||||
|
WorkRange range;
|
||||||
|
};
|
||||||
|
|
||||||
struct INetworkingPool
|
struct INetworkingPool
|
||||||
{
|
{
|
||||||
// A:
|
// A:
|
||||||
virtual AuUInt32 Pump(int idx) = 0;
|
virtual AuUInt32 Pump(AuUInt8 workerId) = 0;
|
||||||
|
|
||||||
// B:
|
// B:
|
||||||
virtual AuUInt32 PumpRead(int idx) = 0;
|
virtual AuUInt32 PumpRead(AuUInt8 workerId) = 0;
|
||||||
virtual AuUInt32 PumpWrite(int idx) = 0;
|
virtual AuUInt32 PumpWrite(AuUInt8 workerId) = 0;
|
||||||
|
|
||||||
// C:
|
// C:
|
||||||
virtual AuUInt32 PollWorker(int idx) = 0;
|
virtual AuUInt32 PollWorker(AuUInt8 workerId) = 0;
|
||||||
virtual AuUInt32 RunWorker(int idx, AuUInt32 timeout) = 0;
|
virtual AuUInt32 RunWorker(AuUInt8 workerId, AuUInt32 timeout) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// D: class APIs
|
||||||
|
virtual bool BeginReadPollingOnWorkQueues(const WorkPoolGroup &workGroup) = 0;
|
||||||
|
virtual bool BeginSubmissionsOnOnWorkQueues(const WorkPoolGroup &workGroup) = 0;
|
||||||
|
virtual void StopPollingOnWorkQueues() = 0;
|
||||||
|
|
||||||
virtual AuUInt8 GetWorkers() = 0;
|
virtual AuUInt8 GetWorkers() = 0;
|
||||||
|
|
||||||
@ -435,34 +466,10 @@ namespace Aurora::IO::Net
|
|||||||
virtual void Shutdown() = 0;
|
virtual void Shutdown() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
AUE_DEFINE(ENetworkPoolModel, (
|
|
||||||
|
|
||||||
// Do not attach to a thread subsystem
|
|
||||||
eNoHooks,
|
|
||||||
|
|
||||||
/// given a group id, uses prespawned async application event queues
|
|
||||||
eAsyncApp,
|
|
||||||
|
|
||||||
/// it just werks
|
|
||||||
eInternalThreadPool,
|
|
||||||
|
|
||||||
/// Developer intends to call the INetworkingPoll poll functions with the respective thread id
|
|
||||||
eUserCreateThreadRunnable
|
|
||||||
))
|
|
||||||
|
|
||||||
struct NetworkPool
|
struct NetworkPool
|
||||||
{
|
{
|
||||||
AuUInt8 workers {1};
|
AuUInt8 workers {1};
|
||||||
|
|
||||||
ENetworkPoolModel mode;
|
|
||||||
|
|
||||||
AuUInt8 asyncWorkGroup {};
|
|
||||||
AuUInt8 asyncWorkerIdOffset {};
|
|
||||||
|
|
||||||
AuSPtr<Async::IThreadPool> threadPool;
|
|
||||||
|
|
||||||
/// Ignore me. Used on platforms that suck (win32) when the model is defined as eAsyncApp or eAsyncThreadPool
|
|
||||||
AuUInt32 frequencyNotAsync {50};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AUKN_SHARED_API(CreateNetworkPool, INetworkingPool, const NetworkPool & meta);
|
AUKN_SHARED_API(CreateNetworkPool, INetworkingPool, const NetworkPool & meta);
|
||||||
|
@ -21,6 +21,6 @@ namespace Aurora::Parse
|
|||||||
AUKN_SYM void ByteToHex(AuUInt8 val, char(&hex)[2]);
|
AUKN_SYM void ByteToHex(AuUInt8 val, char(&hex)[2]);
|
||||||
AUKN_SYM bool HexToInt (const char *hex, AuUInt32 length, AuUInt64 &val);
|
AUKN_SYM bool HexToInt (const char *hex, AuUInt32 length, AuUInt64 &val);
|
||||||
|
|
||||||
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &out);
|
AUKN_SYM bool EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &out);
|
||||||
AUKN_SYM bool DecodeHex(const AuString &in, Memory::ByteBuffer &out);
|
AUKN_SYM bool DecodeHex(const AuString &in, Memory::ByteBuffer &out);
|
||||||
}
|
}
|
@ -9,10 +9,13 @@
|
|||||||
|
|
||||||
namespace Aurora::Processes
|
namespace Aurora::Processes
|
||||||
{
|
{
|
||||||
enum class ESpawnType
|
AUE_DEFINE(ESpawnType,
|
||||||
{
|
(
|
||||||
eSpawnAtomicOvermap, // posix: exec, win32: i dunno
|
// posix: exec, win32: i dunno
|
||||||
eSpawnChildProcessWorker, // posix: thread, win32: job process
|
eSpawnAtomicOvermap,
|
||||||
eSpawnThreadLeader // posix: thread leader / new sid / pid != 0 daemon, win32: process
|
// posix: thread, win32: job process
|
||||||
};
|
eSpawnChildProcessWorker,
|
||||||
|
// posix: thread leader / new sid / pid != 0 daemon, win32: process
|
||||||
|
eSpawnThreadLeader
|
||||||
|
));
|
||||||
}
|
}
|
11
Include/Aurora/Processes/EStandardHandle.hpp
Normal file
11
Include/Aurora/Processes/EStandardHandle.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Processes
|
||||||
|
{
|
||||||
|
AUE_DEFINE(EStandardHandle,
|
||||||
|
(
|
||||||
|
eStdIn,
|
||||||
|
eStdOut,
|
||||||
|
eStdError
|
||||||
|
));
|
||||||
|
}
|
@ -28,9 +28,7 @@ namespace Aurora::Processes
|
|||||||
|
|
||||||
virtual AuUInt GetProcessId() = 0;
|
virtual AuUInt GetProcessId() = 0;
|
||||||
|
|
||||||
///
|
virtual bool Start() = 0;
|
||||||
// TODO(Reece): what in the hell this is ugly
|
|
||||||
virtual bool Start(enum ESpawnType, bool fwdOut, bool fwdErr, bool fwdIn) = 0;
|
|
||||||
|
|
||||||
virtual bool Terminate() = 0;
|
virtual bool Terminate() = 0;
|
||||||
virtual bool TryKill() = 0;
|
virtual bool TryKill() = 0;
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ESpawnType.hpp"
|
#include "ESpawnType.hpp"
|
||||||
|
#include "EStandardHandle.hpp"
|
||||||
#include "IProcess.hpp"
|
#include "IProcess.hpp"
|
||||||
|
#include "StartupParmaters.hpp"
|
||||||
#include "Spawn.hpp"
|
#include "Spawn.hpp"
|
||||||
#include "UtilRun.hpp"
|
#include "UtilRun.hpp"
|
||||||
|
|
||||||
|
@ -9,5 +9,5 @@
|
|||||||
|
|
||||||
namespace Aurora::Processes
|
namespace Aurora::Processes
|
||||||
{
|
{
|
||||||
AUKN_SHARED_API(Spawn, IProcess, const AuString &app, const AuList<AuString> &args);
|
AUKN_SHARED_API(Spawn, IProcess, const StartupParmaters &startup);
|
||||||
}
|
}
|
15
Include/Aurora/Processes/StartupParmaters.hpp
Normal file
15
Include/Aurora/Processes/StartupParmaters.hpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Processes
|
||||||
|
{
|
||||||
|
struct StartupParmaters
|
||||||
|
{
|
||||||
|
AuString process;
|
||||||
|
AuList<AuString> args;
|
||||||
|
enum ESpawnType type;
|
||||||
|
bool fwdOut {};
|
||||||
|
bool fwdErr {};
|
||||||
|
bool fwdIn {};
|
||||||
|
bool noShowConsole {}; // Hides conhost or otherwise blanks stdin/out handles
|
||||||
|
};
|
||||||
|
}
|
@ -10,8 +10,9 @@
|
|||||||
#include <Source/Telemetry/Telemetry.hpp>
|
#include <Source/Telemetry/Telemetry.hpp>
|
||||||
|
|
||||||
#if defined(AURORA_PLATFORM_WIN32)
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
#include "ExceptionWatcher.NT.hpp"
|
#include "ExceptionWatcher.NT.hpp"
|
||||||
#include "ExceptionWatcher.Win32.hpp"
|
#include "ExceptionWatcher.Win32.hpp"
|
||||||
|
#include "Stack.Win32.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Aurora::Debug
|
namespace Aurora::Debug
|
||||||
@ -200,7 +201,11 @@ namespace Aurora::Debug
|
|||||||
|
|
||||||
AUKN_SYM StackTrace GetStackTrace()
|
AUKN_SYM StackTrace GetStackTrace()
|
||||||
{
|
{
|
||||||
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
|
return PlatformWalkCallStack();
|
||||||
|
#else
|
||||||
return {};
|
return {};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AUKN_SYM AuString GetLastException()
|
AUKN_SYM AuString GetLastException()
|
||||||
|
@ -138,7 +138,6 @@ namespace Aurora::Debug
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void HandleFatal(bool fatal, _EXCEPTION_POINTERS *pExceptionInfo)
|
static void HandleFatal(bool fatal, _EXCEPTION_POINTERS *pExceptionInfo)
|
||||||
{
|
{
|
||||||
static bool handlingFatal = false;
|
static bool handlingFatal = false;
|
||||||
|
@ -128,4 +128,3 @@ namespace Aurora::Debug
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
0
Source/IO/Character/BufferedCharacterConsumer.cpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.cpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.hpp
Normal file
0
Source/IO/Character/BufferedCharacterConsumer.hpp
Normal file
0
Source/IO/Character/LineBuffer.cpp
Normal file
0
Source/IO/Character/LineBuffer.cpp
Normal file
0
Source/IO/Character/LineBuffer.hpp
Normal file
0
Source/IO/Character/LineBuffer.hpp
Normal file
@ -193,7 +193,7 @@ namespace Aurora::Parse
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &in)
|
AUKN_SYM bool EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &in)
|
||||||
{
|
{
|
||||||
bool hexedit = formatting == EHexDump::eHexEditor;
|
bool hexedit = formatting == EHexDump::eHexEditor;
|
||||||
|
|
||||||
@ -206,100 +206,111 @@ namespace Aurora::Parse
|
|||||||
|
|
||||||
bool space = formatting != EHexDump::eString;
|
bool space = formatting != EHexDump::eString;
|
||||||
|
|
||||||
in.reserve(length * 4);
|
try
|
||||||
|
|
||||||
auto &newLine = AuLocale::NewLine();
|
|
||||||
|
|
||||||
if (hexedit)
|
|
||||||
{
|
{
|
||||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15");
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
in.insert(in.size(), " ");
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
}
|
|
||||||
else if (squareBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.end(), '[');
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
}
|
|
||||||
else if (curlyBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.end(), '{');
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < length; )
|
in.reserve(length * 4);
|
||||||
{
|
|
||||||
AuUInt32 x, rowMax;
|
|
||||||
|
|
||||||
if (i != 0)
|
auto &newLine = AuLocale::NewLine();
|
||||||
{
|
|
||||||
if (hexedit || squareBracket || curlyBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (squareBracket || curlyBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.size(), " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
rowMax = AuMin(AuUInt32(i + 16), AuUInt32(length));
|
|
||||||
|
|
||||||
for (x = i;
|
|
||||||
x < rowMax;
|
|
||||||
x ++)
|
|
||||||
{
|
|
||||||
if (space)
|
|
||||||
{
|
|
||||||
if (x != i)
|
|
||||||
{
|
|
||||||
in.insert(in.end(), ' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zeroX)
|
|
||||||
{
|
|
||||||
in.insert(in.size(), "0x");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char hex[2];
|
|
||||||
ByteToHex(reinterpret_cast<const AuUInt8*>(pBuf)[x], hex);
|
|
||||||
in.insert(in.size(), hex, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x != (length - 1))
|
|
||||||
{
|
|
||||||
if (squareBracket || curlyBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.end(), ',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i = x;
|
|
||||||
|
|
||||||
if (hexedit)
|
if (hexedit)
|
||||||
{
|
{
|
||||||
// TODO: print space + i * 16 padded + space hex(i * 16 padded)
|
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15");
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
in.insert(in.size(), " ");
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
}
|
||||||
|
else if (squareBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.end(), '[');
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
}
|
||||||
|
else if (curlyBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.end(), '{');
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (squareBracket)
|
for (int i = 0; i < length; )
|
||||||
{
|
{
|
||||||
in.insert(in.size(), newLine);
|
AuUInt32 x, rowMax;
|
||||||
in.insert(in.end(), ']');
|
|
||||||
}
|
|
||||||
else if (curlyBracket)
|
|
||||||
{
|
|
||||||
in.insert(in.size(), newLine);
|
|
||||||
in.insert(in.end(), '}');
|
|
||||||
}
|
|
||||||
|
|
||||||
in.shrink_to_fit();
|
if (i != 0)
|
||||||
|
{
|
||||||
|
if (hexedit || squareBracket || curlyBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (squareBracket || curlyBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.size(), " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
rowMax = AuMin(AuUInt32(i + 16), AuUInt32(length));
|
||||||
|
|
||||||
|
for (x = i;
|
||||||
|
x < rowMax;
|
||||||
|
x++)
|
||||||
|
{
|
||||||
|
if (space)
|
||||||
|
{
|
||||||
|
if (x != i)
|
||||||
|
{
|
||||||
|
in.insert(in.end(), ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zeroX)
|
||||||
|
{
|
||||||
|
in.insert(in.size(), "0x");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char hex[2];
|
||||||
|
ByteToHex(reinterpret_cast<const AuUInt8 *>(pBuf)[x], hex);
|
||||||
|
in.insert(in.size(), hex, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x != (length - 1))
|
||||||
|
{
|
||||||
|
if (squareBracket || curlyBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.end(), ',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i = x;
|
||||||
|
|
||||||
|
if (hexedit)
|
||||||
|
{
|
||||||
|
// TODO: print space + i * 16 padded + space hex(i * 16 padded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (squareBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
in.insert(in.end(), ']');
|
||||||
|
}
|
||||||
|
else if (curlyBracket)
|
||||||
|
{
|
||||||
|
in.insert(in.size(), newLine);
|
||||||
|
in.insert(in.end(), '}');
|
||||||
|
}
|
||||||
|
|
||||||
|
in.shrink_to_fit();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
SysPushErrorGen("EncodeHex failed");
|
||||||
|
in.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
404
Source/Processes/Process.NT.cpp
Normal file
404
Source/Processes/Process.NT.cpp
Normal file
@ -0,0 +1,404 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: Process.NT.cpp
|
||||||
|
Date: 2021-6-12
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#include <Source/RuntimeInternal.hpp>
|
||||||
|
#include "Processes.hpp"
|
||||||
|
#include "Process.Win32.hpp"
|
||||||
|
#include <process.h>
|
||||||
|
|
||||||
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
|
#include "Process.Win32.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Aurora::Processes
|
||||||
|
{
|
||||||
|
class ProcessImpl : public IProcess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProcessImpl(const StartupParmaters ¶ms);
|
||||||
|
~ProcessImpl();
|
||||||
|
|
||||||
|
bool TermWinEnumProcesses();
|
||||||
|
|
||||||
|
bool TryKill() override;
|
||||||
|
bool HasExited();
|
||||||
|
|
||||||
|
AuUInt GetProcessId() override;
|
||||||
|
|
||||||
|
bool Terminate() override;
|
||||||
|
AuSPtr<Threading::IWaitable> AsWaitable() override;
|
||||||
|
AuSInt GetExitCode() override;
|
||||||
|
|
||||||
|
void ShutdownPipes();
|
||||||
|
|
||||||
|
bool Read(bool error, void *buffer, AuUInt32 &len) override;
|
||||||
|
bool Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock) override;
|
||||||
|
|
||||||
|
bool Write(const void *buffer, AuUInt32 len) override;
|
||||||
|
|
||||||
|
bool Start() override;
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
HANDLE pipeStdOutRead_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE pipeStdOutWrite_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE pipeStdErrRead_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE pipeStdErrWrite_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE pipeStdInRead_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE pipeStdInWrite_ {INVALID_HANDLE_VALUE};
|
||||||
|
|
||||||
|
StartupParmaters startup_;
|
||||||
|
ESpawnType type_;
|
||||||
|
|
||||||
|
AuList<const char *> cargs_;
|
||||||
|
AuString windowsCli_;
|
||||||
|
|
||||||
|
AuThreads::ThreadUnique_t thread_;
|
||||||
|
HANDLE process_ {INVALID_HANDLE_VALUE};
|
||||||
|
HANDLE hthread_ {INVALID_HANDLE_VALUE};
|
||||||
|
AuSInt exitCode_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ProcessImpl::ProcessImpl(const StartupParmaters ¶ms) : startup_(params)
|
||||||
|
{
|
||||||
|
startup_.args.insert(startup_.args.begin(), startup_.process);
|
||||||
|
|
||||||
|
// ehhhh https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
|
||||||
|
for (const auto &arg : this->startup_.args)
|
||||||
|
{
|
||||||
|
this->cargs_.push_back(arg.c_str());
|
||||||
|
this->windowsCli_ += arg + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->cargs_.push_back(nullptr);
|
||||||
|
this->windowsCli_.resize(this->windowsCli_.size() - 1);
|
||||||
|
this->type_ = params.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessImpl::~ProcessImpl()
|
||||||
|
{
|
||||||
|
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||||
|
{
|
||||||
|
TryKill();
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->thread_)
|
||||||
|
{
|
||||||
|
this->thread_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuWin32CloseHandle(this->process_);
|
||||||
|
AuWin32CloseHandle(this->hthread_);
|
||||||
|
|
||||||
|
ShutdownPipes();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuUInt ProcessImpl::GetProcessId()
|
||||||
|
{
|
||||||
|
if (this->process_ == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::GetProcessId(this->process_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::TermWinEnumProcesses()
|
||||||
|
{
|
||||||
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
|
return SendExitSignal(this->process_);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::TryKill()
|
||||||
|
{
|
||||||
|
return TermWinEnumProcesses();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::HasExited()
|
||||||
|
{
|
||||||
|
DWORD a;
|
||||||
|
if (!GetExitCodeProcess(this->process_, &a)) return true;
|
||||||
|
return a != STILL_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::Terminate()
|
||||||
|
{
|
||||||
|
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TerminateProcess(this->process_, 0) || HasExited();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSPtr<Threading::IWaitable> ProcessImpl::AsWaitable()
|
||||||
|
{
|
||||||
|
if (!this->thread_) return nullptr;
|
||||||
|
return this->thread_->AsWaitable();
|
||||||
|
}
|
||||||
|
|
||||||
|
AuSInt ProcessImpl::GetExitCode()
|
||||||
|
{
|
||||||
|
return this->exitCode_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessImpl::ShutdownPipes()
|
||||||
|
{
|
||||||
|
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdOutWrite_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdErrWrite_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdInRead_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::Read(bool error, void *buffer, AuUInt32 &len)
|
||||||
|
{
|
||||||
|
return Read(buffer, len, error, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock)
|
||||||
|
{
|
||||||
|
DWORD size = AuExchange(len, 0);
|
||||||
|
|
||||||
|
auto handle = errorStream ? pipeStdErrRead_ : pipeStdOutRead_;
|
||||||
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonblock)
|
||||||
|
{
|
||||||
|
DWORD avail {};
|
||||||
|
if (!PeekNamedPipe(handle, NULL, NULL, NULL, &avail, NULL))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = AuMin(size, avail);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ret = ReadFile(handle, buffer, size, &size, NULL);
|
||||||
|
len = size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::Write(const void *buffer, AuUInt32 len)
|
||||||
|
{
|
||||||
|
DWORD size = len;
|
||||||
|
if (pipeStdInWrite_ == INVALID_HANDLE_VALUE) return false;
|
||||||
|
return WriteFile(pipeStdInWrite_, buffer, size, &size, NULL) && size == len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ProcessImpl::Init()
|
||||||
|
{
|
||||||
|
SECURITY_ATTRIBUTES saAttr {};
|
||||||
|
|
||||||
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
|
saAttr.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
if (this->type_ == ESpawnType::eSpawnAtomicOvermap)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->exitCode_ = 0x10110100;
|
||||||
|
if (this->startup_.fwdOut)
|
||||||
|
{
|
||||||
|
if (!CreatePipe(&pipeStdOutRead_, &pipeStdOutWrite_, &saAttr, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetHandleInformation(pipeStdOutRead_, HANDLE_FLAG_INHERIT, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->startup_.fwdErr)
|
||||||
|
{
|
||||||
|
if (!CreatePipe(&pipeStdErrRead_, &pipeStdErrWrite_, &saAttr, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetHandleInformation(pipeStdErrRead_, HANDLE_FLAG_INHERIT, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->startup_.fwdIn)
|
||||||
|
{
|
||||||
|
if (!CreatePipe(&pipeStdInRead_, &pipeStdInWrite_, &saAttr, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetHandleInformation(pipeStdInWrite_, HANDLE_FLAG_INHERIT, 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->startup_.noShowConsole)
|
||||||
|
{
|
||||||
|
HANDLE nulFile = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
// I dont want to move the other SetHandleInformations down below the if block above is, just to find out double SetHandleInfo with the same input params results in a return false condition
|
||||||
|
// This will do for.now
|
||||||
|
#define CHK_NUL \
|
||||||
|
if (nulFile == INVALID_HANDLE_VALUE) \
|
||||||
|
{ \
|
||||||
|
nulFile = CreateFileA("nul:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); \
|
||||||
|
SetHandleInformation(nulFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->pipeStdInRead_ == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CHK_NUL;
|
||||||
|
this->pipeStdInRead_ = nulFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->pipeStdErrWrite_ == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CHK_NUL;
|
||||||
|
this->pipeStdErrWrite_ = nulFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->pipeStdOutWrite_ == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CHK_NUL;
|
||||||
|
this->pipeStdOutWrite_ = nulFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessImpl::Start()
|
||||||
|
{
|
||||||
|
if (this->process_ != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->type_ == ESpawnType::eSpawnAtomicOvermap)
|
||||||
|
{
|
||||||
|
_spawnv(_P_OVERLAY, this->startup_.process.c_str(), this->cargs_.data());
|
||||||
|
SysPushErrorGen("_spawnv didn't overwrite the process map, given {} ({})", this->startup_.process, this->windowsCli_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_INFORMATION processInfo = { 0 };
|
||||||
|
{
|
||||||
|
STARTUPINFOW startupInfo = { 0 };
|
||||||
|
startupInfo.cb = sizeof(startupInfo);
|
||||||
|
|
||||||
|
bool inheritHandles = this->startup_.fwdIn || this->startup_.fwdErr || this->startup_.fwdOut || this->startup_.noShowConsole;
|
||||||
|
|
||||||
|
startupInfo.hStdInput = pipeStdInRead_;
|
||||||
|
startupInfo.hStdError = pipeStdErrWrite_;
|
||||||
|
startupInfo.hStdOutput = pipeStdOutWrite_;
|
||||||
|
startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0);
|
||||||
|
|
||||||
|
auto result = CreateProcessW(Locale::ConvertFromUTF8(this->startup_.process).c_str(),
|
||||||
|
Locale::ConvertFromUTF8(this->windowsCli_).data(),
|
||||||
|
NULL, NULL, inheritHandles,
|
||||||
|
this->startup_.noShowConsole ? CREATE_NO_WINDOW : NULL, // yea we can keep CREATE_NO_WINDOW on for non-console apps. its legal -> https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||||
|
NULL, NULL, &startupInfo, &processInfo);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
SysPushErrorGen("CreateProcess failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->process_ = processInfo.hProcess;
|
||||||
|
this->hthread_ = processInfo.hThread;
|
||||||
|
|
||||||
|
AuWin32CloseHandle(this->pipeStdOutRead_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdErrRead_);
|
||||||
|
AuWin32CloseHandle(this->pipeStdInWrite_);
|
||||||
|
|
||||||
|
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
||||||
|
{
|
||||||
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
|
AssignJobWorker(processInfo.hProcess);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: delegate to a singular worker thread
|
||||||
|
auto a = [=]()
|
||||||
|
{
|
||||||
|
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
||||||
|
|
||||||
|
DWORD exitCode;
|
||||||
|
auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
|
||||||
|
this->exitCode_ = exitCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
this->thread_ = AuThreads::ThreadUnique(AuThreads::ThreadInfo(
|
||||||
|
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(a)),
|
||||||
|
AuThreads::IThreadVectorsFunctional::OnExit_t{})
|
||||||
|
));
|
||||||
|
|
||||||
|
if (!this->thread_)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->thread_->Run();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM IProcess *SpawnNew(const StartupParmaters ¶ms)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto hi = _new ProcessImpl(params);
|
||||||
|
if (!hi) return {};
|
||||||
|
|
||||||
|
if (!hi->Init())
|
||||||
|
{
|
||||||
|
delete hi;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return hi;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AUKN_SYM void SpawnRelease(IProcess *process)
|
||||||
|
{
|
||||||
|
SafeDelete<ProcessImpl *>(process);
|
||||||
|
}
|
||||||
|
}
|
13
Source/Processes/Process.NT.hpp
Normal file
13
Source/Processes/Process.NT.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/***
|
||||||
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
|
File: Process.NT.hpp
|
||||||
|
Date: 2022-1-29
|
||||||
|
Author: Reece
|
||||||
|
***/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Aurora::Processes
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
/***
|
/***
|
||||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
Copyright (C) 2021-2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
File: Process.Win32.cpp
|
File: Process.Win32.cpp
|
||||||
Date: 2021-6-12
|
Date: 2022-1-29
|
||||||
Author: Reece
|
Author: Reece
|
||||||
***/
|
***/
|
||||||
#include <Source/RuntimeInternal.hpp>
|
#include <Source/RuntimeInternal.hpp>
|
||||||
#include "Processes.hpp"
|
|
||||||
#include "Process.Win32.hpp"
|
#include "Process.Win32.hpp"
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <tlhelp32.h>
|
#include <tlhelp32.h>
|
||||||
@ -38,98 +37,26 @@ namespace Aurora::Processes
|
|||||||
AuWin32CloseHandle(gLeaderJob);
|
AuWin32CloseHandle(gLeaderJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProcessImpl : public IProcess
|
void AssignJobWorker(HANDLE handle)
|
||||||
{
|
{
|
||||||
public:
|
if (gLeaderJob)
|
||||||
ProcessImpl(AuString execModule, AuList<AuString> args);
|
|
||||||
~ProcessImpl();
|
|
||||||
|
|
||||||
bool TermWinEnumProcesses();
|
|
||||||
|
|
||||||
bool TryKill() override;
|
|
||||||
bool HasExited();
|
|
||||||
|
|
||||||
AuUInt GetProcessId() override;
|
|
||||||
|
|
||||||
bool Terminate() override;
|
|
||||||
AuSPtr<Threading::IWaitable> AsWaitable() override;
|
|
||||||
AuSInt GetExitCode() override;
|
|
||||||
|
|
||||||
void ShutdownPipes();
|
|
||||||
|
|
||||||
bool Read(bool error, void *buffer, AuUInt32 &len) override;
|
|
||||||
bool Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock) override;
|
|
||||||
|
|
||||||
bool Write(const void *buffer, AuUInt32 len) override;
|
|
||||||
|
|
||||||
// TODO: what in the hell this is ugly
|
|
||||||
bool Start(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
HANDLE pipeStdOutRead_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE pipeStdOutWrite_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE pipeStdErrRead_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE pipeStdErrWrite_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE pipeStdInRead_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE pipeStdInWrite_ {INVALID_HANDLE_VALUE};
|
|
||||||
|
|
||||||
AuString execModule_;
|
|
||||||
ESpawnType type_;
|
|
||||||
|
|
||||||
AuList<AuString> args_;
|
|
||||||
AuList<const char *> cargs_;
|
|
||||||
AuString windowsCli_;
|
|
||||||
|
|
||||||
AuThreads::ThreadUnique_t thread_;
|
|
||||||
HANDLE process_ {INVALID_HANDLE_VALUE};
|
|
||||||
HANDLE hthread_ {INVALID_HANDLE_VALUE};
|
|
||||||
AuSInt exitCode_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ProcessImpl::ProcessImpl(AuString execModule, AuList<AuString> args) : execModule_(execModule), args_(args)
|
|
||||||
{
|
|
||||||
this->args_.insert(this->args_.begin(), execModule);
|
|
||||||
|
|
||||||
// ehhhh https://github.com/tritao/WindowsSDK/blob/07983c7ba4f6861d15e23f195744c60c0c249ce0/SDKs/SourceDir/Windows%20Kits/10/Source/10.0.17763.0/ucrt/exec/cenvarg.cpp#L23
|
|
||||||
for (const auto &arg : this->args_)
|
|
||||||
{
|
{
|
||||||
this->cargs_.push_back(arg.c_str());
|
if (!AssignProcessToJobObject(gLeaderJob, handle))
|
||||||
this->windowsCli_ += arg + " ";
|
{
|
||||||
|
SysPushErrorGen("Could not AssignProcessToObject");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->cargs_.push_back(nullptr);
|
|
||||||
this->windowsCli_.resize(this->windowsCli_.size() - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessImpl::~ProcessImpl()
|
static bool HasWin32ProcessExited(HANDLE handle)
|
||||||
{
|
{
|
||||||
if (this->type_ == ESpawnType::eSpawnChildProcessWorker)
|
DWORD exitCode;
|
||||||
|
if (!GetExitCodeProcess(handle, &exitCode))
|
||||||
{
|
{
|
||||||
TryKill();
|
return true;
|
||||||
Terminate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->thread_)
|
return exitCode != STILL_ACTIVE;
|
||||||
{
|
|
||||||
this->thread_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
AuWin32CloseHandle(this->process_);
|
|
||||||
AuWin32CloseHandle(this->hthread_);
|
|
||||||
|
|
||||||
ShutdownPipes();
|
|
||||||
}
|
|
||||||
|
|
||||||
AuUInt ProcessImpl::GetProcessId()
|
|
||||||
{
|
|
||||||
if (this->process_ == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ::GetProcessId(this->process_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL TermWinHandleWin32Thread(HWND handle, LPARAM a)
|
static BOOL TermWinHandleWin32Thread(HWND handle, LPARAM a)
|
||||||
@ -139,17 +66,12 @@ namespace Aurora::Processes
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessImpl::TermWinEnumProcesses()
|
static bool SendExtermianteWinloopCloseMessages(HANDLE handle)
|
||||||
{
|
{
|
||||||
THREADENTRY32 te{};
|
THREADENTRY32 te{};
|
||||||
HANDLE h{};
|
HANDLE h{};
|
||||||
|
|
||||||
if (this->process_ == INVALID_HANDLE_VALUE)
|
h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetProcessId(handle));
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetProcessId());
|
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -177,229 +99,57 @@ namespace Aurora::Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Threading::YieldPoll(true, 2500, [=]()
|
return true;
|
||||||
{
|
|
||||||
return !HasExited();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessImpl::TryKill()
|
static bool SendControlCEquiv(HANDLE handle)
|
||||||
{
|
{
|
||||||
return TermWinEnumProcesses();
|
if (!(AttachConsole(GetProcessId(handle))))
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::HasExited()
|
|
||||||
{
|
|
||||||
DWORD a;
|
|
||||||
if (!GetExitCodeProcess(this->process_, &a)) return true;
|
|
||||||
return a != STILL_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::Terminate()
|
|
||||||
{
|
|
||||||
if (this->process_ != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TerminateProcess(this->process_, 0) || HasExited();
|
if (SetConsoleCtrlHandler({}, true))
|
||||||
|
{
|
||||||
|
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
|
||||||
|
SysAssert(FreeConsole(), "Couldn't pop off zombie process console");
|
||||||
|
Sleep(750);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SysAssert(FreeConsole(), "Couldn't pop off zombie process console");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetConsoleCtrlHandler({}, true))
|
||||||
|
{
|
||||||
|
SysPushErrorHAL("Couldn't swap control+c handler -> wont accept control termination on exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuSPtr<Threading::IWaitable> ProcessImpl::AsWaitable()
|
static bool Wait2500OrUntilClose(HANDLE handle)
|
||||||
{
|
{
|
||||||
if (!this->thread_) return nullptr;
|
return Threading::YieldPoll(true, 2500, [=]()
|
||||||
return this->thread_->AsWaitable();
|
{
|
||||||
|
return !HasWin32ProcessExited(handle);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AuSInt ProcessImpl::GetExitCode()
|
bool SendExitSignal(HANDLE handle)
|
||||||
{
|
{
|
||||||
return this->exitCode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessImpl::ShutdownPipes()
|
|
||||||
{
|
|
||||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdOutWrite_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdErrWrite_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdInRead_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::Read(bool error, void *buffer, AuUInt32 &len)
|
|
||||||
{
|
|
||||||
return Read(buffer, len, error, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::Read(void *buffer, AuUInt32 &len, bool errorStream, bool nonblock)
|
|
||||||
{
|
|
||||||
DWORD size = AuExchange(len, 0);
|
|
||||||
|
|
||||||
auto handle = errorStream ? pipeStdErrRead_ : pipeStdOutRead_;
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonblock)
|
if (!(SendControlCEquiv(handle) // send GenerateConsoleCtrlEvent
|
||||||
{
|
|| SendExtermianteWinloopCloseMessages(handle))) // send WM_CLOSE
|
||||||
DWORD avail {};
|
|
||||||
if (!PeekNamedPipe(handle, NULL, NULL, NULL, &avail, NULL))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!avail)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = AuMin(size, avail);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ret = ReadFile(handle, buffer, size, &size, NULL);
|
|
||||||
len = size;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::Write(const void *buffer, AuUInt32 len)
|
|
||||||
{
|
|
||||||
DWORD size = len;
|
|
||||||
if (pipeStdInWrite_ == INVALID_HANDLE_VALUE) return false;
|
|
||||||
return WriteFile(pipeStdInWrite_, buffer, size, &size, NULL) && size == len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ProcessImpl::Start(enum ESpawnType type, bool fwdOut, bool fwdErr, bool fwdIn)
|
|
||||||
{
|
|
||||||
this->exitCode_ = 0x10110100;
|
|
||||||
this->type_ = type;
|
|
||||||
|
|
||||||
if (type == ESpawnType::eSpawnAtomicOvermap)
|
|
||||||
{
|
|
||||||
_spawnv(_P_OVERLAY, this->execModule_.c_str(), this->cargs_.data());
|
|
||||||
SysPushErrorGen("_spawnv didn't overwrite the process map, given {} ({})", this->execModule_, this->windowsCli_);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
SECURITY_ATTRIBUTES saAttr{};
|
|
||||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
||||||
saAttr.bInheritHandle = TRUE;
|
|
||||||
|
|
||||||
if (fwdOut)
|
|
||||||
{
|
|
||||||
if (!CreatePipe(&pipeStdOutRead_, &pipeStdOutWrite_, &saAttr, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetHandleInformation(pipeStdOutRead_, HANDLE_FLAG_INHERIT, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwdErr)
|
|
||||||
{
|
|
||||||
if (!CreatePipe(&pipeStdErrRead_, &pipeStdErrWrite_, &saAttr, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetHandleInformation(pipeStdErrRead_, HANDLE_FLAG_INHERIT, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwdIn)
|
|
||||||
{
|
|
||||||
if (!CreatePipe(&pipeStdInRead_, &pipeStdInWrite_, &saAttr, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetHandleInformation(pipeStdInWrite_, HANDLE_FLAG_INHERIT, 0))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PROCESS_INFORMATION processInfo = { 0 };
|
|
||||||
{
|
|
||||||
STARTUPINFOW startupInfo = { 0 };
|
|
||||||
startupInfo.cb = sizeof(startupInfo);
|
|
||||||
|
|
||||||
bool inheritHandles = fwdIn || fwdErr || fwdOut;
|
|
||||||
|
|
||||||
startupInfo.hStdInput = pipeStdInRead_;
|
|
||||||
startupInfo.hStdError = pipeStdErrWrite_;
|
|
||||||
startupInfo.hStdOutput = pipeStdOutWrite_;
|
|
||||||
startupInfo.dwFlags |= (inheritHandles ? STARTF_USESTDHANDLES : 0);
|
|
||||||
|
|
||||||
auto result = CreateProcessW(Locale::ConvertFromUTF8(this->execModule_).c_str(),
|
|
||||||
Locale::ConvertFromUTF8(this->windowsCli_).data(),
|
|
||||||
NULL, NULL, inheritHandles,
|
|
||||||
NULL,
|
|
||||||
NULL, NULL, &startupInfo, &processInfo);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
SysPushErrorGen("CreateProcess failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->process_ = processInfo.hProcess;
|
|
||||||
this->hthread_ = processInfo.hThread;
|
|
||||||
|
|
||||||
AuWin32CloseHandle(this->pipeStdOutRead_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdErrRead_);
|
|
||||||
AuWin32CloseHandle(this->pipeStdInWrite_);
|
|
||||||
|
|
||||||
if (type == ESpawnType::eSpawnChildProcessWorker)
|
|
||||||
{
|
|
||||||
if (gLeaderJob)
|
|
||||||
{
|
|
||||||
if (!AssignProcessToJobObject(gLeaderJob, processInfo.hProcess))
|
|
||||||
{
|
|
||||||
SysPushErrorGen("Could not AssignProcessToObject");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: delegate to a singular worker thread
|
|
||||||
auto a = [=]()
|
|
||||||
{
|
|
||||||
WaitForSingleObject(processInfo.hProcess, INFINITE);
|
|
||||||
|
|
||||||
DWORD exitCode;
|
|
||||||
auto result = GetExitCodeProcess(processInfo.hProcess, &exitCode);
|
|
||||||
this->exitCode_ = exitCode;
|
|
||||||
};
|
|
||||||
|
|
||||||
this->thread_ = AuThreads::ThreadUnique(AuThreads::ThreadInfo(
|
|
||||||
AuMakeShared<AuThreads::IThreadVectorsFunctional>(AuThreads::IThreadVectorsFunctional::OnEntry_t(std::bind(a)),
|
|
||||||
AuThreads::IThreadVectorsFunctional::OnExit_t{})
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!this->thread_)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->thread_->Run();
|
return Wait2500OrUntilClose(handle);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
AUKN_SYM IProcess *SpawnNew(const AuString &app, const AuList<AuString> &args)
|
|
||||||
{
|
|
||||||
return _new ProcessImpl(app, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
AUKN_SYM void SpawnRelease(IProcess *process)
|
|
||||||
{
|
|
||||||
SafeDelete<ProcessImpl *>(process);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,14 +1,16 @@
|
|||||||
/***
|
/***
|
||||||
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||||||
|
|
||||||
File: Process.Win32.hpp
|
File: Process.Win32.hpp
|
||||||
Date: 2021-6-12
|
Date: 2022-1-29
|
||||||
Author: Reece
|
Author: Reece
|
||||||
***/
|
***/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Aurora::Processes
|
namespace Aurora::Processes
|
||||||
{
|
{
|
||||||
void InitWin32();
|
|
||||||
void DeinitWin32();
|
void DeinitWin32();
|
||||||
|
void InitWin32();
|
||||||
|
void AssignJobWorker(HANDLE handle);
|
||||||
|
bool SendExitSignal(HANDLE handle);
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ using high_res_clock = std::chrono::high_resolution_clock;
|
|||||||
using sys_clock = std::chrono::system_clock;
|
using sys_clock = std::chrono::system_clock;
|
||||||
|
|
||||||
#if defined(AURORA_PLATFORM_WIN32)
|
#if defined(AURORA_PLATFORM_WIN32)
|
||||||
#define timegm _mkgmtime
|
#define timegm _mkgmtime
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static sys_clock::duration gEpoch;
|
static sys_clock::duration gEpoch;
|
||||||
@ -20,13 +20,7 @@ static sys_clock::duration gUnixDelta;
|
|||||||
|
|
||||||
static auto InitEpoch()
|
static auto InitEpoch()
|
||||||
{
|
{
|
||||||
std::tm start{};
|
std::tm start{0, 15, 10, 29, 7, 101, 0, 0, 0};
|
||||||
start.tm_mday = 29; // day number
|
|
||||||
start.tm_mon = 7; // month idx, aug
|
|
||||||
start.tm_year = 101; // 1900 + 101
|
|
||||||
start.tm_hour = 9; // 11 - index - DST
|
|
||||||
start.tm_min = 15; // minute offset
|
|
||||||
|
|
||||||
auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch();
|
auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch();
|
||||||
|
|
||||||
std::tm unixStart{};
|
std::tm unixStart{};
|
||||||
|
@ -16,7 +16,7 @@ namespace Aurora::Time
|
|||||||
ULARGE_INTEGER ull;
|
ULARGE_INTEGER ull;
|
||||||
ull.LowPart = ft.dwLowDateTime;
|
ull.LowPart = ft.dwLowDateTime;
|
||||||
ull.HighPart = ft.dwHighDateTime;
|
ull.HighPart = ft.dwHighDateTime;
|
||||||
return ull.QuadPart / 10000ULL - 12'643'550'100'000ULL;
|
return ull.QuadPart / 10000ULL - 12'643'553'700'000ULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user