Pass terminal data on socket on Cygwin platforms

On Cygwin and MSYS2 use a controlling pty for the server client handler
instead of passing a file descriptor over the socket which is not
possible on Cygwin platforms.

Attach an event to STDIN on the client, passing data from it to the
server and attach an event to the pty out_fd on the server client
handler and pass data from it to the client.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
This commit is contained in:
Rafael Kitover 2024-07-25 21:55:40 +00:00
parent 8d6eb4be40
commit 80e6621298
No known key found for this signature in database
GPG Key ID: 08AB596679D86240
6 changed files with 78 additions and 2 deletions

View File

@ -244,6 +244,9 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
char *line = NULL, **caps = NULL, *cause;
u_int ncaps = 0;
struct args_value *values;
#ifdef TTY_OVER_SOCKET
struct tty* tty = xmalloc(sizeof *tty);
#endif
/* Set up the initial command. */
if (shell_command != NULL) {
@ -397,6 +400,10 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
} else if (msg == MSG_SHELL)
proc_send(client_peer, msg, -1, NULL, 0);
#ifdef TTY_OVER_SOCKET
tty_attach_stdin_to_socket(tty, client_peer);
#endif
/* Start main loop. */
proc_loop(client_proc, NULL);
@ -474,12 +481,14 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
caps[i], strlen(caps[i]) + 1);
}
#ifndef TTY_OVER_SOCKET
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
#endif
pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
@ -805,5 +814,10 @@ client_dispatch_attached(struct imsg *imsg)
system(data);
proc_send(client_peer, MSG_UNLOCK, -1, NULL, 0);
break;
#ifdef TTY_OVER_SOCKET
case MSG_TTY_READ:
write(STDOUT_FILENO, data, datalen);
break;
#endif
}
}

View File

@ -69,6 +69,11 @@
#define __weak __attribute__ ((__weak__))
#endif
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
#define WIN32_PLATFORM
#define TTY_OVER_SOCKET
#endif
#ifndef ECHOPRT
#define ECHOPRT 0
#endif

View File

@ -22,6 +22,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@ -2898,6 +2899,11 @@ server_client_dispatch(struct imsg *imsg, void *arg)
case MSG_READ_DONE:
file_read_done(&c->files, imsg);
break;
#ifdef TTY_OVER_SOCKET
case MSG_TTY_WRITE:
write(c->fd, imsg->data, datalen);
break;
#endif
}
}
@ -3069,6 +3075,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->cwd = xstrdup("/");
log_debug("client %p IDENTIFY_CWD %s", c, data);
break;
#ifndef TTY_OVER_SOCKET
case MSG_IDENTIFY_STDIN:
if (datalen != 0)
fatalx("bad MSG_IDENTIFY_STDIN size");
@ -3081,6 +3088,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->out_fd = imsg_get_fd(imsg);
log_debug("client %p IDENTIFY_STDOUT %d", c, c->out_fd);
break;
#endif
case MSG_IDENTIFY_ENVIRON:
if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_IDENTIFY_ENVIRON string");
@ -3109,8 +3117,8 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->name = name;
log_debug("client %p name is %s", c, c->name);
#ifdef __CYGWIN__
c->fd = open(c->ttyname, O_RDWR|O_NOCTTY);
#ifdef TTY_OVER_SOCKET
c->fd = open("/dev/ptmx", O_RDWR|O_NOCTTY);
c->out_fd = dup(c->fd);
#endif

View File

@ -68,6 +68,11 @@ enum msgtype {
MSG_WRITE_READY,
MSG_WRITE_CLOSE,
MSG_READ_CANCEL
#ifdef TTY_OVER_SOCKET
,
MSG_TTY_READ,
MSG_TTY_WRITE
#endif
};
/*

5
tmux.h
View File

@ -2461,6 +2461,11 @@ void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
void tty_default_colours(struct grid_cell *, struct window_pane *);
#ifdef TTY_OVER_SOCKET
int tty_attach_stdin_to_socket(struct tty *, struct tmuxpeer *);
int tty_attach_out_to_socket(struct tty *, struct client *);
#endif
/* tty-term.c */
extern struct tty_terms tty_terms;
u_int tty_term_ncodes(void);

39
tty.c
View File

@ -250,6 +250,11 @@ tty_write_callback(__unused int fd, __unused short events, void *data)
struct client *c = tty->client;
size_t size = EVBUFFER_LENGTH(tty->out);
int nwrite;
#ifdef TTY_OVER_SOCKET
enum msgtype msg = MSG_TTY_READ;
proc_send(c->peer, msg, -1, EVBUFFER_DATA(tty->out), size);
#endif
nwrite = evbuffer_write(tty->out, c->fd);
if (nwrite == -1)
@ -304,6 +309,40 @@ tty_open(struct tty *tty, char **cause)
return (0);
}
#ifdef TTY_OVER_SOCKET
static struct tmuxpeer *client_peer;
static void
tty_stdin_socket_callback(int fd, __unused short events, void *data)
{
struct tty *tty = data;
int nread;
enum msgtype msg = MSG_TTY_WRITE;
nread = evbuffer_read(tty->in, fd, -1);
if (nread == 0 || nread == -1) {
event_del(&tty->event_in);
return;
}
proc_send(client_peer, msg, -1, EVBUFFER_DATA(tty->in), nread);
}
int
tty_attach_stdin_to_socket(struct tty *tty, struct tmuxpeer *peer)
{
client_peer = peer;
event_set(&tty->event_in, STDIN_FILENO, EV_PERSIST|EV_READ,
tty_stdin_socket_callback, tty);
tty->in = evbuffer_new();
if (tty->in == NULL)
fatal("out of memory");
return (0);
}
#endif
static void
tty_start_timer_callback(__unused int fd, __unused short events, void *data)
{