/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IPCHandle.cpp Date: 2022-4-13 Author: Reece ***/ #include #include "IPC.hpp" #include "IPCHandle.hpp" namespace Aurora::IO::IPC { #define AURORA_IPC_BRAND "AuroraIPC_" // A horribly inefficient parsable handle. // Dead simple to implement, it's 22:07, and i wanna sleep soon. // We should text serialize a bitmap later... 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, 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::ParseUInt(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(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; readIPC(header2, value); this->values.push_back(value); } } else { IPCValue value; value.token.pid = this->pid; readIPC(header, value); 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 : 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 += AuToString(this->pid); ret += ':'; } if (header.bmHasWord) { ret += AuToString(ipcValue.token.word); ret += ':'; } if constexpr (AuBuild::kIsNtDerived) { ret += AuString(ipcValue.token.path, ipcValue.token.path + strnlen(ipcValue.token.path, AuArraySize(ipcValue.token.path))); ret += ':'; } else { ret += AuToString(ipcValue.token.cookie); 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; } #endif }