diff options
Diffstat (limited to 'src/zenutil/zenserverprocess.cpp')
| -rw-r--r-- | src/zenutil/zenserverprocess.cpp | 247 |
1 files changed, 246 insertions, 1 deletions
diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index b9c50be4f..ac614f779 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -449,6 +449,30 @@ ZenServerState::ZenServerEntry::IsReady() const return (Flags.load() & static_cast<uint16_t>(FlagsEnum::kIsReady)) != 0; } +void +ZenServerState::ZenServerEntry::SignalHasInstanceInfo() +{ + Flags |= uint16_t(FlagsEnum::kHasInstanceInfo); +} + +bool +ZenServerState::ZenServerEntry::HasInstanceInfo() const +{ + return (Flags.load() & static_cast<uint16_t>(FlagsEnum::kHasInstanceInfo)) != 0; +} + +void +ZenServerState::ZenServerEntry::SignalNoNetwork() +{ + Flags |= uint16_t(FlagsEnum::kNoNetwork); +} + +bool +ZenServerState::ZenServerEntry::IsNoNetwork() const +{ + return (Flags.load() & static_cast<uint16_t>(FlagsEnum::kNoNetwork)) != 0; +} + bool ZenServerState::ZenServerEntry::AddSponsorProcess(uint32_t PidToAdd, uint64_t Timeout) { @@ -492,6 +516,222 @@ ZenServerState::ZenServerEntry::AddSponsorProcess(uint32_t PidToAdd, uint64_t Ti } ////////////////////////////////////////////////////////////////////////// +// ZenServerInstanceInfo +////////////////////////////////////////////////////////////////////////// + +static constexpr size_t kInstanceInfoSize = 4096; + +ZenServerInstanceInfo::ZenServerInstanceInfo() = default; + +ZenServerInstanceInfo::~ZenServerInstanceInfo() +{ +#if ZEN_PLATFORM_WINDOWS + if (m_Data) + { + UnmapViewOfFile(m_Data); + } + if (m_hMapFile) + { + CloseHandle(m_hMapFile); + } +#else + if (m_Data != nullptr) + { + munmap(m_Data, kInstanceInfoSize); + } + if (m_hMapFile != nullptr) + { + int Fd = int(intptr_t(m_hMapFile)); + close(Fd); + } + if (m_IsOwner) + { + std::string Name = MakeName(m_SessionId); + shm_unlink(Name.c_str()); + } +#endif + m_Data = nullptr; +} + +std::string +ZenServerInstanceInfo::MakeName(const Oid& SessionId) +{ +#if ZEN_PLATFORM_WINDOWS + return fmt::format("Global\\ZenInstance_{}", SessionId); +#else + // macOS limits shm_open names to ~31 chars (PSHMNAMLEN), so keep this short. + // "/ZenI_" (6) + 24 hex = 30 chars, within the limit. + return fmt::format("/ZenI_{}", SessionId); +#endif +} + +void +ZenServerInstanceInfo::Create(const Oid& SessionId, const InstanceInfoData& Data) +{ + m_SessionId = SessionId; + m_IsOwner = true; + + // Serialize the data to compact binary + CbObjectWriter Cbo; + if (!Data.UnixSocketPath.empty()) + { + Cbo << "unix_socket" << PathToUtf8(Data.UnixSocketPath); + } + CbObject Payload = Cbo.Save(); + + MemoryView PayloadView = Payload.GetView(); + uint32_t PayloadSize = gsl::narrow<uint32_t>(PayloadView.GetSize()); + + std::string Name = MakeName(SessionId); + +#if ZEN_PLATFORM_WINDOWS + zenutil::AnyUserSecurityAttributes Attrs; + + std::wstring WideName(Name.begin(), Name.end()); + + HANDLE hMap = + CreateFileMappingW(INVALID_HANDLE_VALUE, Attrs.Attributes(), PAGE_READWRITE, 0, DWORD(kInstanceInfoSize), WideName.c_str()); + + if (hMap == NULL) + { + // Fall back to Local namespace + std::string LocalName = fmt::format("Local\\ZenInstance_{}", SessionId); + std::wstring WideLocalName(LocalName.begin(), LocalName.end()); + hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, + Attrs.Attributes(), + PAGE_READWRITE, + 0, + DWORD(kInstanceInfoSize), + WideLocalName.c_str()); + } + + if (hMap == NULL) + { + ThrowLastError("Could not create instance info shared memory"); + } + + void* pBuf = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, DWORD(kInstanceInfoSize)); + if (pBuf == NULL) + { + CloseHandle(hMap); + ThrowLastError("Could not map instance info shared memory"); + } +#else + int Fd = shm_open(Name.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0666); + if (Fd < 0) + { + ThrowLastError("Could not create instance info shared memory"); + } + fchmod(Fd, 0666); + + if (ftruncate(Fd, kInstanceInfoSize) < 0) + { + close(Fd); + shm_unlink(Name.c_str()); + ThrowLastError("Could not resize instance info shared memory"); + } + + void* pBuf = mmap(nullptr, kInstanceInfoSize, PROT_READ | PROT_WRITE, MAP_SHARED, Fd, 0); + if (pBuf == MAP_FAILED) + { + close(Fd); + shm_unlink(Name.c_str()); + ThrowLastError("Could not map instance info shared memory"); + } + + void* hMap = reinterpret_cast<void*>(intptr_t(Fd)); +#endif + + m_hMapFile = hMap; + m_Data = reinterpret_cast<uint8_t*>(pBuf); + + // Write payload: [uint32_t size][compact binary bytes] + memcpy(m_Data, &PayloadSize, sizeof PayloadSize); + if (PayloadSize > 0) + { + memcpy(m_Data + sizeof(uint32_t), PayloadView.GetData(), PayloadSize); + } +} + +bool +ZenServerInstanceInfo::OpenReadOnly(const Oid& SessionId) +{ + m_SessionId = SessionId; + + std::string Name = MakeName(SessionId); + +#if ZEN_PLATFORM_WINDOWS + std::wstring WideName(Name.begin(), Name.end()); + + HANDLE hMap = OpenFileMappingW(FILE_MAP_READ, FALSE, WideName.c_str()); + if (hMap == NULL) + { + // Fall back to Local namespace + std::string LocalName = fmt::format("Local\\ZenInstance_{}", SessionId); + std::wstring WideLocalName(LocalName.begin(), LocalName.end()); + hMap = OpenFileMappingW(FILE_MAP_READ, FALSE, WideLocalName.c_str()); + } + + if (hMap == NULL) + { + return false; + } + + void* pBuf = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, DWORD(kInstanceInfoSize)); + if (pBuf == NULL) + { + CloseHandle(hMap); + return false; + } +#else + int Fd = shm_open(Name.c_str(), O_RDONLY | O_CLOEXEC, 0666); + if (Fd < 0) + { + return false; + } + + void* pBuf = mmap(nullptr, kInstanceInfoSize, PROT_READ, MAP_SHARED, Fd, 0); + if (pBuf == MAP_FAILED) + { + close(Fd); + return false; + } + + void* hMap = reinterpret_cast<void*>(intptr_t(Fd)); +#endif + + m_hMapFile = hMap; + m_Data = reinterpret_cast<uint8_t*>(pBuf); + m_IsOwner = false; + + return true; +} + +InstanceInfoData +ZenServerInstanceInfo::Read() const +{ + InstanceInfoData Result; + + if (m_Data == nullptr) + { + return Result; + } + + uint32_t PayloadSize = 0; + memcpy(&PayloadSize, m_Data, sizeof PayloadSize); + + if (PayloadSize == 0 || PayloadSize > kInstanceInfoSize - sizeof(uint32_t)) + { + return Result; + } + + CbObject Payload = CbObject::Clone(m_Data + sizeof(uint32_t)); + Result.UnixSocketPath = Payload["unix_socket"].AsU8String(); + + return Result; +} + +////////////////////////////////////////////////////////////////////////// std::atomic<int> ZenServerTestCounter{0}; @@ -1234,6 +1474,10 @@ MakeLockFilePayload(const LockFileInfo& Info) CbObjectWriter Cbo; Cbo << "pid" << Info.Pid << "data" << PathToUtf8(Info.DataDir) << "port" << Info.EffectiveListenPort << "session_id" << Info.SessionId << "ready" << Info.Ready << "executable" << PathToUtf8(Info.ExecutablePath); + if (!Info.UnixSocketPath.empty()) + { + Cbo << "unix_socket" << PathToUtf8(Info.UnixSocketPath); + } return Cbo.Save(); } LockFileInfo @@ -1246,6 +1490,7 @@ ReadLockFilePayload(const CbObject& Payload) Info.Ready = Payload["ready"].AsBool(); Info.DataDir = Payload["data"].AsU8String(); Info.ExecutablePath = Payload["executable"].AsU8String(); + Info.UnixSocketPath = Payload["unix_socket"].AsU8String(); return Info; } @@ -1275,7 +1520,7 @@ ValidateLockFileInfo(const LockFileInfo& Info, std::string& OutReason) OutReason = fmt::format("session id ({}) is not valid", Info.SessionId); return false; } - if (Info.EffectiveListenPort == 0) + if (Info.EffectiveListenPort == 0 && Info.UnixSocketPath.empty()) { OutReason = fmt::format("listen port ({}) is not valid", Info.EffectiveListenPort); return false; |