This is an automated email from the git hooks/post-receive script.
git pushed a commit to reference refs/pull/36/head
in repository terminology.
View the commit online.
commit 3ad11e97332bdc46686dee9d6328734d05f4f448
Author: [email protected] <[email protected]>
AuthorDate: Sun Mar 15 18:01:15 2026 -0600
feat: add termsrv.h header for tymux session recovery IPC
Defines the shared memory and messaging protocol for the tymux feature,
which allows recovering disconnected Terminology sessions. Includes:
- TermShmHeader: memfd-backed screen buffer layout with atomic sequence
numbers for lock-free client-server synchronization
- TermSrvMsgType enum: 9 message types for attach, detach, input,
resize, notifications, title, bell, and session exit events
- Message structs: type-safe payload definitions for IPC communication
- Helper declarations: socket path functions and message I/O primitives
Linux-only feature gated with HAVE_TYMUX.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
src/bin/termsrv.h | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
diff --git a/src/bin/termsrv.h b/src/bin/termsrv.h
new file mode 100644
index 00000000..0ba4ee9b
--- /dev/null
+++ b/src/bin/termsrv.h
@@ -0,0 +1,137 @@
+#ifndef TERMINOLOGY_TERMSRV_H_
+#define TERMINOLOGY_TERMSRV_H_
+
+#include "config.h"
+
+#ifdef HAVE_TYMUX
+
+#include <stdint.h>
+#include <stdatomic.h>
+#include <stddef.h>
+#include "termpty.h" /* Termcell */
+
+/* ── shared memory ──────────────────────────────────────────────── */
+
+#define TERMSRV_SHM_MAGIC 0x544D5348u /* "TMSH" */
+#define TERMSRV_SHM_VERSION 1u
+#define TERMSRV_MAX_COLS 500
+#define TERMSRV_MAX_ROWS 200
+
+/*
+ * Header occupies the first 4096 bytes (one page) of the memfd.
+ * Cells follow at TERMSRV_SHM_HEADER_SIZE, in display order (row 0 = top).
+ * Client reads write_seq with ACQUIRE; server stores with RELEASE.
+ */
+typedef struct {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t cols;
+ uint32_t rows;
+ uint32_t cursor_x;
+ uint32_t cursor_y;
+ uint8_t cursor_visible;
+ uint8_t _pad[7];
+ _Atomic uint64_t write_seq;
+} TermShmHeader;
+
+#define TERMSRV_SHM_HEADER_SIZE 4096u
+#define TERMSRV_SHM_CELLS_SIZE \
+ ((size_t)TERMSRV_MAX_COLS * TERMSRV_MAX_ROWS * sizeof(Termcell))
+#define TERMSRV_SHM_TOTAL_SIZE \
+ (TERMSRV_SHM_HEADER_SIZE + TERMSRV_SHM_CELLS_SIZE)
+
+#define TERMSRV_SHM_CELLS(shm_ptr) \
+ ((Termcell *)((uint8_t *)(shm_ptr) + TERMSRV_SHM_HEADER_SIZE))
+
+/* ── IPC messages ───────────────────────────────────────────────── */
+
+typedef enum {
+ TSRV_MSG_ATTACH = 1, /* client → server: attach to this session */
+ TSRV_MSG_ATTACHED = 2, /* server → client: cols/rows + memfd via SCM_RIGHTS */
+ TSRV_MSG_DETACH = 3, /* client → server: clean disconnect */
+ TSRV_MSG_INPUT = 4, /* client → server: raw PTY bytes */
+ TSRV_MSG_RESIZE = 5, /* client → server: new cols/rows */
+ TSRV_MSG_NOTIFY = 6, /* server → client: write_seq updated */
+ TSRV_MSG_TITLE = 7, /* server → client: new window title */
+ TSRV_MSG_BELL = 8, /* server → client: BEL */
+ TSRV_MSG_EXIT = 9, /* server → client: session ended, exit code */
+} TermSrvMsgType;
+
+/* Every message starts with this 8-byte header */
+typedef struct {
+ uint32_t type; /* TermSrvMsgType */
+ uint32_t size; /* payload bytes after this header */
+} TermSrvMsgHdr;
+
+/* ATTACHED payload (memfd via SCM_RIGHTS alongside this) */
+typedef struct {
+ uint32_t cols;
+ uint32_t rows;
+} TermSrvMsgAttached;
+
+/* RESIZE payload */
+typedef struct {
+ uint32_t cols;
+ uint32_t rows;
+} TermSrvMsgResize;
+
+/* NOTIFY payload */
+typedef struct {
+ uint64_t write_seq;
+} TermSrvMsgNotify;
+
+/* EXIT payload */
+typedef struct {
+ int32_t exit_code;
+} TermSrvMsgExit;
+
+/* ── session name ───────────────────────────────────────────────── */
+
+/* Maximum length of a session name (excluding null terminator).
+ * Must be safe as a filename component. */
+#define TSRV_MAX_SESSION_NAME 64
+
+/* ── socket paths ───────────────────────────────────────────────── */
+
+/*
+ * Fill buf with the socket path for a named session:
+ * $XDG_RUNTIME_DIR/terminology/tymux/<name>.sock
+ * Falls back to /tmp if XDG_RUNTIME_DIR is unset.
+ * Returns 0 on success, -1 if buf too small or name contains '/'.
+ */
+int termsrv_socket_path(const char *session_name, char *buf, size_t bufsz);
+
+/*
+ * Fill buf with the sessions directory path:
+ * $XDG_RUNTIME_DIR/terminology/tymux
+ * Returns 0 on success, -1 if buf too small.
+ */
+int termsrv_sessions_dir(char *buf, size_t bufsz);
+
+/*
+ * Create $XDG_RUNTIME_DIR/terminology/tymux/ (and parents) if absent.
+ * Returns 0 on success, -1 on error (errno set).
+ */
+int termsrv_ensure_sessions_dir(void);
+
+/* ── message I/O ────────────────────────────────────────────────── */
+
+/* Send header + payload over a blocking socket fd. Returns 0/-1. */
+int termsrv_msg_send(int fd, TermSrvMsgType type,
+ const void *payload, uint32_t size);
+
+/* Receive a message. *payload_out is malloc'd; caller must free().
+ * Returns msg type (>0) on success, -1 on EOF/error.
+ * *payload_out is NULL and *size_out is 0 when there is no payload. */
+int termsrv_msg_recv(int fd, void **payload_out, uint32_t *size_out);
+
+/* Send ATTACHED with memfd via SCM_RIGHTS. Returns 0/-1. */
+int termsrv_send_attached(int sock_fd, int shm_fd,
+ uint32_t cols, uint32_t rows);
+
+/* Receive ATTACHED and extract the shm fd. Returns 0/-1. */
+int termsrv_recv_attached(int sock_fd, int *shm_fd_out,
+ uint32_t *cols_out, uint32_t *rows_out);
+
+#endif /* HAVE_TYMUX */
+#endif /* TERMINOLOGY_TERMSRV_H_ */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.