aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/include
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-13 09:24:59 +0100
committerGitHub Enterprise <[email protected]>2026-03-13 09:24:59 +0100
commitef586f5930ac761f8e8e18cde2ebd5248efeaa4a (patch)
treebe6c7d3e11f9261c1d03d646bc579ac0d27452d7 /src/zenutil/include
parentSwitch httpclient default back-end over to libcurl (#832) (diff)
downloadarchived-zen-ef586f5930ac761f8e8e18cde2ebd5248efeaa4a.tar.xz
archived-zen-ef586f5930ac761f8e8e18cde2ebd5248efeaa4a.zip
Unix Domain Socket auto discovery (#833)
This PR adds end-to-end Unix domain socket (UDS) support, allowing zen CLI to discover and connect to UDS-only servers automatically. - **`unix://` URI scheme in zen CLI**: The `-u` / `--hosturl` option now accepts `unix:///path/to/socket` to connect to a zenserver via a Unix domain socket instead of TCP. - **Per-instance shared memory for extended server info**: Each zenserver instance now publishes a small shared memory section (keyed by SessionId) containing per-instance data that doesn't fit in the fixed-size ZenServerEntry -- starting with the UDS socket path. This is a 4KB pagefile-backed section on Windows (`Global\ZenInstance_{sessionid}`) and a POSIX shared memory object on Linux/Mac (`/UnrealEngineZen_{sessionid}`). - **Client-side auto-discovery of UDS servers**: `zen info`, `zen status`, etc. now automatically discover and prefer UDS connections when a server publishes a socket path. Servers running with `--no-network` (UDS-only) are no longer invisible to the CLI. - **`kNoNetwork` flag in ZenServerEntry**: Servers started with `--no-network` advertise this in their shared state entry. Clients skip TCP fallback for these servers, and display commands (`ps`, `status`, `top`) show `-` instead of a port number to indicate TCP is not available.
Diffstat (limited to 'src/zenutil/include')
-rw-r--r--src/zenutil/include/zenutil/zenserverprocess.h56
1 files changed, 54 insertions, 2 deletions
diff --git a/src/zenutil/include/zenutil/zenserverprocess.h b/src/zenutil/include/zenutil/zenserverprocess.h
index 1b8750628..2f76f0d6c 100644
--- a/src/zenutil/include/zenutil/zenserverprocess.h
+++ b/src/zenutil/include/zenutil/zenserverprocess.h
@@ -224,8 +224,10 @@ public:
enum class FlagsEnum : uint16_t
{
- kShutdownPlease = 1 << 0,
- kIsReady = 1 << 1,
+ kShutdownPlease = 1 << 0,
+ kIsReady = 1 << 1,
+ kHasInstanceInfo = 1 << 2,
+ kNoNetwork = 1 << 3,
};
FRIEND_ENUM_CLASS_FLAGS(FlagsEnum);
@@ -236,6 +238,10 @@ public:
bool IsShutdownRequested() const;
void SignalReady();
bool IsReady() const;
+ void SignalHasInstanceInfo();
+ bool HasInstanceInfo() const;
+ void SignalNoNetwork();
+ bool IsNoNetwork() const;
bool AddSponsorProcess(uint32_t Pid, uint64_t Timeout = 0);
};
@@ -258,6 +264,51 @@ private:
bool m_IsReadOnly = true;
};
+/** Per-instance extended data published via a small shared memory section keyed by SessionId.
+
+ Servers create a writable section; clients open it read-only during Snapshot()
+ enumeration to discover fields that don't fit in the fixed-size ZenServerEntry
+ (e.g. Unix domain socket path).
+
+ SessionId is preferred over PID for naming because it is unique per server
+ instance lifetime, avoiding issues with PID reuse on crash/restart.
+ */
+
+struct InstanceInfoData
+{
+ std::filesystem::path UnixSocketPath;
+ // Extensible: add more per-instance fields here in the future
+};
+
+class ZenServerInstanceInfo
+{
+public:
+ ZenServerInstanceInfo();
+ ~ZenServerInstanceInfo();
+
+ ZenServerInstanceInfo(const ZenServerInstanceInfo&) = delete;
+ ZenServerInstanceInfo& operator=(const ZenServerInstanceInfo&) = delete;
+
+ /// Server-side: create read-write, populate with data
+ void Create(const Oid& SessionId, const InstanceInfoData& Data);
+
+ /// Client-side: open read-only by SessionId, returns false if not found
+ [[nodiscard]] bool OpenReadOnly(const Oid& SessionId);
+
+ /// Read the data (valid after Create or successful OpenReadOnly)
+ [[nodiscard]] InstanceInfoData Read() const;
+
+ bool IsValid() const { return m_Data != nullptr; }
+
+private:
+ static std::string MakeName(const Oid& SessionId);
+
+ void* m_hMapFile = nullptr;
+ uint8_t* m_Data = nullptr;
+ bool m_IsOwner = false;
+ Oid m_SessionId; // for POSIX cleanup (shm_unlink)
+};
+
struct LockFileInfo
{
int32_t Pid;
@@ -266,6 +317,7 @@ struct LockFileInfo
bool Ready;
std::filesystem::path DataDir;
std::filesystem::path ExecutablePath;
+ std::filesystem::path UnixSocketPath;
};
CbObject MakeLockFilePayload(const LockFileInfo& Info);