J Reece Wilson
21902a5d5b
[*] Optimize UNIX IPC ABI: Handle String encodes an array of U16s to optimize space. Could still be better.
317 lines
9.4 KiB
C++
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
|
|
} |