This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch tymux
in repository terminology.

View the commit online.

commit fa91812d3cdb63510f45d5ec775196a54231b234
Author: [email protected] <[email protected]>
AuthorDate: Sun Mar 22 12:51:26 2026 -0600

    feat: implement tymux backlog buffer request/response
    
    Add BACKLOG_BUF_REQ/BACKLOG_BUF message handling so clients can lazily
    fetch older backlog buffer memfds from the daemon. The daemon validates
    the requested buffer index and responds with the memfd via SCM_RIGHTS.
    The client temporarily clears O_NONBLOCK for the blocking recv, then
    restores the original flags.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 src/bin/termd_tymux.c | 18 +++++++++++++
 src/bin/termsrv.c     | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/termsrv.h     | 13 +++++++++
 src/bin/termtymux.c   | 49 ++++++++++++++++++++++++++++++++++
 src/bin/termtymux.h   | 14 ++++++++++
 5 files changed, 167 insertions(+)

diff --git a/src/bin/termd_tymux.c b/src/bin/termd_tymux.c
index 13919289..857d6ebb 100644
--- a/src/bin/termd_tymux.c
+++ b/src/bin/termd_tymux.c
@@ -444,6 +444,24 @@ _cb_client_data(void *data, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
            }
          break;
 
+      case TSRV_MSG_BACKLOG_BUF_REQ:
+         if (payload && size >= sizeof(TermSrvMsgBacklogBufReq))
+           {
+              TermSrvMsgBacklogBufReq *req = payload;
+              int idx = (int)req->buf_id - sess->oldest_buf_id;
+              if (idx >= 0 && idx < sess->backlog_buf_count)
+                {
+                   TermBacklogBufHeader *h = sess->backlog_bufs[idx].hdr;
+                   termsrv_send_backlog_buf(client->fd,
+                                            sess->backlog_bufs[idx].fd,
+                                            req->buf_id,
+                                            h->cols,
+                                            h->num_lines,
+                                            h->max_lines);
+                }
+           }
+         break;
+
       case TSRV_MSG_DETACH:
          free(payload);
          _client_remove(sess, client);
diff --git a/src/bin/termsrv.c b/src/bin/termsrv.c
index cd4a824e..60a24cc5 100644
--- a/src/bin/termsrv.c
+++ b/src/bin/termsrv.c
@@ -261,4 +261,77 @@ termsrv_recv_attached(int sock_fd, int *shm_fd_out, int *backlog_fd_out,
     return 0;
 }
 
+int
+termsrv_send_backlog_buf(int sock_fd, int buf_fd,
+                         uint32_t buf_id, uint32_t cols,
+                         uint32_t num_lines, uint32_t max_lines)
+{
+    TermSrvMsgHdr       hdr = { .type = TSRV_MSG_BACKLOG_BUF,
+                                .size = sizeof(TermSrvMsgBacklogBuf) };
+    TermSrvMsgBacklogBuf pl  = {
+        .buf_id    = buf_id,
+        .cols      = cols,
+        .num_lines = num_lines,
+        .max_lines = max_lines,
+    };
+    struct iovec iov[2] = {
+        { &hdr, sizeof(hdr) },
+        { &pl,  sizeof(pl)  }
+    };
+    char cmsgbuf[CMSG_SPACE(sizeof(int))];
+    memset(cmsgbuf, 0, sizeof(cmsgbuf));
+    struct msghdr msg = {
+        .msg_iov        = iov,
+        .msg_iovlen     = 2,
+        .msg_control    = cmsgbuf,
+        .msg_controllen = (socklen_t)CMSG_SPACE(sizeof(int))
+    };
+    struct cmsghdr *cm = CMSG_FIRSTHDR(&msg);
+    cm->cmsg_level = SOL_SOCKET;
+    cm->cmsg_type  = SCM_RIGHTS;
+    cm->cmsg_len   = CMSG_LEN(sizeof(int));
+    memcpy(CMSG_DATA(cm), &buf_fd, sizeof(int));
+
+    return (sendmsg(sock_fd, &msg, MSG_NOSIGNAL) < 0) ? -1 : 0;
+}
+
+int
+termsrv_recv_backlog_buf(int sock_fd, int *buf_fd_out,
+                         uint32_t *buf_id_out, uint32_t *cols_out,
+                         uint32_t *num_lines_out, uint32_t *max_lines_out)
+{
+    TermSrvMsgHdr        hdr;
+    TermSrvMsgBacklogBuf pl;
+    char cmsgbuf[CMSG_SPACE(sizeof(int))];
+    memset(cmsgbuf, 0, sizeof(cmsgbuf));
+    struct iovec iov[2] = {
+        { &hdr, sizeof(hdr) },
+        { &pl,  sizeof(pl)  }
+    };
+    struct msghdr msg = {
+        .msg_iov        = iov,
+        .msg_iovlen     = 2,
+        .msg_control    = cmsgbuf,
+        .msg_controllen = sizeof(cmsgbuf)
+    };
+
+    *buf_fd_out = -1;
+    ssize_t n = recvmsg(sock_fd, &msg, MSG_WAITALL);
+    if (n < (ssize_t)(sizeof(hdr) + sizeof(pl))) return -1;
+    if (msg.msg_flags & MSG_CTRUNC) return -1;
+    if (hdr.type != TSRV_MSG_BACKLOG_BUF) return -1;
+    if (hdr.size != sizeof(TermSrvMsgBacklogBuf)) return -1;
+
+    struct cmsghdr *cm = CMSG_FIRSTHDR(&msg);
+    if (!cm || cm->cmsg_type != SCM_RIGHTS ||
+        cm->cmsg_len < CMSG_LEN(sizeof(int))) return -1;
+    memcpy(buf_fd_out, CMSG_DATA(cm), sizeof(int));
+
+    *buf_id_out    = pl.buf_id;
+    *cols_out      = pl.cols;
+    *num_lines_out = pl.num_lines;
+    *max_lines_out = pl.max_lines;
+    return 0;
+}
+
 #endif /* HAVE_TYMUX */
diff --git a/src/bin/termsrv.h b/src/bin/termsrv.h
index 305009a9..97921815 100644
--- a/src/bin/termsrv.h
+++ b/src/bin/termsrv.h
@@ -206,5 +206,18 @@ int termsrv_recv_attached(int sock_fd, int *shm_fd_out, int *backlog_fd_out,
                           uint32_t *backlog_max_lines_out,
                           uint32_t *oldest_buf_id_out);
 
+/* Send BACKLOG_BUF with the buffer memfd via SCM_RIGHTS.
+ * Returns 0/-1. */
+int termsrv_send_backlog_buf(int sock_fd, int buf_fd,
+                             uint32_t buf_id, uint32_t cols,
+                             uint32_t num_lines, uint32_t max_lines);
+
+/* Receive BACKLOG_BUF and extract the buffer memfd.
+ * Blocking receive — caller must ensure no concurrent reads on sock_fd.
+ * Returns 0/-1. */
+int termsrv_recv_backlog_buf(int sock_fd, int *buf_fd_out,
+                             uint32_t *buf_id_out, uint32_t *cols_out,
+                             uint32_t *num_lines_out, uint32_t *max_lines_out);
+
 #endif /* HAVE_TYMUX */
 #endif /* TERMINOLOGY_TERMSRV_H_ */
diff --git a/src/bin/termtymux.c b/src/bin/termtymux.c
index 5a8bbc25..bb2ebc49 100644
--- a/src/bin/termtymux.c
+++ b/src/bin/termtymux.c
@@ -635,4 +635,53 @@ termtymux_resize(TermTymux *ts, int cols, int rows)
      ERR("termtymux: send RESIZE: %s", strerror(errno));
 }
 
+int
+termsession_request_backlog_buf(TermTymux *ts, uint32_t buf_id,
+                                int *fd_out, uint32_t *cols_out,
+                                uint32_t *num_lines_out,
+                                uint32_t *max_lines_out)
+{
+   TermSrvMsgBacklogBufReq req;
+   int                     flags;
+   int                     ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ts, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(fd_out, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cols_out, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(num_lines_out, -1);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(max_lines_out, -1);
+
+   if (ts->sock_fd < 0)
+     return -1;
+
+   req.buf_id = buf_id;
+   if (termsrv_msg_send(ts->sock_fd, TSRV_MSG_BACKLOG_BUF_REQ,
+                        &req, sizeof(req)) < 0)
+     {
+        ERR("termsession: send BACKLOG_BUF_REQ: %s", strerror(errno));
+        return -1;
+     }
+
+   /* Temporarily clear O_NONBLOCK so termsrv_recv_backlog_buf can use
+    * MSG_WAITALL to receive header + payload + cmsg atomically.
+    * The socket was set non-blocking after the attach handshake; restore
+    * it unconditionally after the recv so the Ecore fd handler is not
+    * affected regardless of the recv outcome. */
+   flags = fcntl(ts->sock_fd, F_GETFL, 0);
+   if (flags >= 0)
+     fcntl(ts->sock_fd, F_SETFL, flags & ~O_NONBLOCK);
+
+   ret = termsrv_recv_backlog_buf(ts->sock_fd, fd_out,
+                                  &buf_id, cols_out,
+                                  num_lines_out, max_lines_out);
+   if (ret < 0)
+     ERR("termsession: recv BACKLOG_BUF failed");
+
+   /* Restore non-blocking mode regardless of recv outcome */
+   if (flags >= 0)
+     fcntl(ts->sock_fd, F_SETFL, flags);
+
+   return ret;
+}
+
 #endif /* HAVE_TYMUX */
diff --git a/src/bin/termtymux.h b/src/bin/termtymux.h
index 51a04313..2862c1e4 100644
--- a/src/bin/termtymux.h
+++ b/src/bin/termtymux.h
@@ -49,5 +49,19 @@ void termtymux_free(TermTymux *ts);
 /* Send a resize event to the daemon. */
 void termtymux_resize(TermTymux *ts, int cols, int rows);
 
+/*
+ * Request a specific backlog buffer from the daemon and receive it
+ * synchronously.  The socket is briefly set to blocking mode for the
+ * recv, then restored to O_NONBLOCK.
+ *
+ * On success *fd_out is a new memfd (caller must close it when done);
+ * *cols_out, *num_lines_out and *max_lines_out describe the buffer.
+ * Returns 0 on success, -1 on failure.
+ */
+int termsession_request_backlog_buf(TermTymux *ts, uint32_t buf_id,
+                                    int *fd_out, uint32_t *cols_out,
+                                    uint32_t *num_lines_out,
+                                    uint32_t *max_lines_out);
+
 #endif /* HAVE_TYMUX */
 #endif /* TERMINOLOGY_TERMTYMUX_H_ */

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to