AuroraRuntime/Source/IO/IPC/IPCHandle.cpp
J Reece Wilson 21902a5d5b [+] AuParse::[Stringify/Parse][U/S]Int[16] class of parse APIs
[*] Optimize UNIX IPC ABI: Handle String encodes an array of U16s to optimize space. Could still be better.
2022-08-04 14:08:12 +01:00

317 lines
9.4 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: IPCHandle.cpp
Date: 2022-4-13
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "IPC.hpp"
#include "IPCHandle.hpp"
namespace Aurora::IO::IPC
{
#define AURORA_IPC_BRAND "AuroraIPC_"
IPCToken::IPCToken()
{
AuMemset(this, 0, sizeof(*this));
}
AuString IPCToken::ToNTPath() const
{
if (this->pid)
{
return "Global\\" AURORA_IPC_BRAND + AuString(this->path, this->path + 16);
}
else
{
return "Local\\" AURORA_IPC_BRAND + AuString(this->path, this->path + 16);
}
}
AuUInt32 IPCToken::ToUnixServerCookie() const
{
return this->cookie;
}
void IPCToken::NewId()
{
#if defined(AURORA_IS_POSIX_DERIVED)
while (!this->cookie)
{
this->cookie = AuRng::RngU32();
}
#else
auto temp = AuRng::ReadString(AuArraySize(this->path), AuRng::ERngStringCharacters::eAlphaNumericCharacters);
AuMemcpy(this->path, temp.data(), temp.size());
#endif
}
IPCHandle::IPCHandle()
{
#if defined(AURORA_IS_POSIX_DERIVED)
this->pid = getpid();
#endif
}
bool IPCHandle::IsTopEq(EIPCHandleType type) const
{
if (this->values.empty())
{
return false;
}
return this->values[0].subtype == type;
}
bool IPCHandle::PushId(EIPCHandleType type, const IPCToken &token)
{
IPCValue val;
val.subtype = type;
val.token = token;
return AuTryInsert(this->values, val) && this->values.size() < 7;
}
IPCValue *IPCHandle::GetToken(EIPCHandleType type, int id)
{
if (this->values.size() <= id)
{
return {};
}
auto val = &this->values[id];
if (val->subtype != type)
{
return {};
}
return val;
}
bool IPCHandle::FromString(const AuString &in)
{
AuString nextToken;
AuUInt nextInt;
if (in.size() < 2)
{
return false;
}
AuUInt32 magic {0x811c9dc5};
for (int i = 0; i < in.size() - 2; i++)
{
magic ^= (in[i] * 0x01000193);
}
if (AuUInt8(AuUInt8(in[in.size() - 2] - 'A') & 15) != AuUInt8(magic & 15))
{
return false;
}
if (AuUInt8(AuUInt8(in[in.size() - 1] - 'A') & 15) != AuUInt8((magic >> 4) & 15))
{
return false;
}
#define READ_NEXT_TOKEN \
{ \
nextToken.clear(); \
\
if (((in.size() - stringOffset) < 2)) \
{ \
return false; \
} \
\
char cur; \
while (((stringOffset) < in.size()) && \
((cur = in[stringOffset]) != ':')) \
{ \
nextToken.push_back(cur); \
stringOffset++; \
} \
stringOffset++; \
}
#define READ_NEXT_INT \
{ \
char cur; \
auto startOffset = stringOffset; \
while (((stringOffset) < in.size()) && \
((cur = in[stringOffset]) != ':')) \
{ \
stringOffset++; \
} \
const char *endPtr = &in[stringOffset]; \
const char *startPtr = &in[startOffset]; \
stringOffset++; \
auto nextIntOpt = AuParse::ParseUInt16(startPtr, endPtr); \
if (!nextIntOpt.has_value()) \
{ \
return false; \
} \
nextInt = nextIntOpt.value(); \
}
int stringOffset {};
int count {};
while (in.size() > (stringOffset + 2))
{
int index = count++;
IPCHeader header;
header.bValue = AuUInt8((((in[stringOffset + 1] - 'A') & 15) << 4) |
((in[stringOffset + 0] - 'A') & 15));
stringOffset += 2;
if (index == 0 && header.bmHasPid)
{
READ_NEXT_INT;
this->pid = nextInt;
}
auto readIPC = [&](IPCHeader header, IPCValue &value)
{
value.subtype = (EIPCHandleType)header.bmType;
if (header.bmHasWord)
{
READ_NEXT_INT;
value.token.word = nextInt;
}
else
{
value.token.word = 0;
}
if constexpr (AuBuild::kIsNtDerived)
{
READ_NEXT_TOKEN;
value.token.cookie = nextInt;
if (nextToken.size() > 16)
{
return false;
}
AuMemcpy(value.token.path, nextToken.data(), AuMin<AuUInt8>(nextToken.size() + 1, AuArraySize(value.token.path)));
}
else
{
READ_NEXT_INT;
value.token.cookie = nextInt;
}
return true;
};
if (header.bmArray)
{
for (int i = 0; i < header.bmArray; i++)
{
IPCHeader header2;
if (i == 0)
{
header2 = header;
}
else
{
header2.bValue = (in[stringOffset] - 'A') & 15;
stringOffset++;
}
IPCValue value;
value.token.pid = this->pid;
if (!readIPC(header2, value))
{
return false;
}
this->values.push_back(value);
}
}
else
{
IPCValue value;
value.token.pid = this->pid;
if (!readIPC(header, value))
{
return false;
}
this->values.push_back(value);
}
}
return true;
}
AuString IPCHandle::ToString() const
{
AuString ret;
int count {};
for (const auto &ipcValue : this->values)
{
int index = count++;
IPCHeader header;
header.bmArray = index == 0 ? this->values.size() : 0;
header.bmHasPid = index == 0 ? (this->pid ? 1 : 0) : 0;
header.bmType = (AuUInt8)ipcValue.subtype;
header.bmHasWord = (AuUInt8)(ipcValue.token.word ? 1 : 0);
ret += ('A' + ((header.bValue & 15)));
if (!index)
{
ret += ('A' + ((header.bValue >> 4) & 15));
}
if (header.bmHasPid)
{
ret += AuParse::StringifyUInt16(this->pid, false);
ret += ':';
}
if (header.bmHasWord)
{
ret += AuParse::StringifyUInt16(ipcValue.token.word, false);
ret += ':';
}
if constexpr (AuBuild::kIsNtDerived)
{
ret += AuString(ipcValue.token.path, ipcValue.token.path + strnlen(ipcValue.token.path, AuArraySize(ipcValue.token.path)));
ret += ':';
}
else
{
ret += AuParse::StringifyUInt16(ipcValue.token.cookie, false);
ret += ':';
}
}
AuUInt32 magic {0x811c9dc5};
for (int i = 0; i < ret.size(); i++)
{
magic ^= (ret[i] * 0x01000193);
}
ret.push_back(((magic & 15) + 'A'));
ret.push_back((((magic >> 4) & 15) + 'A'));
return ret;
}
#if defined(AURORA_IS_POSIX_DERIVED)
pid_t IPCHandle::ToUnixPid() const
{
return this->pid;
}
pid_t IPCToken::ToUnixPid() const
{
return this->pid;
}
#endif
}