mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Instead of passing stdin/stdout/stderr file descriptors over imsg and
handling them in the server, handle them in the client and pass buffers over imsg. This is much tidier for some upcoming changes and the performance hit isn't critical. The tty fd is still passed to the server as before. This bumps the tmux protocol version so new clients and old servers are incompatible.
This commit is contained in:
		
							
								
								
									
										64
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								client.c
									
									
									
									
									
								
							@@ -35,6 +35,7 @@
 | 
			
		||||
 | 
			
		||||
struct imsgbuf	client_ibuf;
 | 
			
		||||
struct event	client_event;
 | 
			
		||||
struct event	client_stdin;
 | 
			
		||||
enum {
 | 
			
		||||
	CLIENT_EXIT_NONE,
 | 
			
		||||
	CLIENT_EXIT_DETACHED,
 | 
			
		||||
@@ -56,6 +57,7 @@ void		client_send_environ(void);
 | 
			
		||||
void		client_write_server(enum msgtype, void *, size_t);
 | 
			
		||||
void		client_update_event(void);
 | 
			
		||||
void		client_signal(int, short, void *);
 | 
			
		||||
void		client_stdin_callback(int, short, void *);
 | 
			
		||||
void		client_callback(int, short, void *);
 | 
			
		||||
int		client_dispatch_attached(void);
 | 
			
		||||
int		client_dispatch_wait(void *);
 | 
			
		||||
@@ -227,6 +229,11 @@ client_main(int argc, char **argv, int flags)
 | 
			
		||||
	imsg_init(&client_ibuf, fd);
 | 
			
		||||
	event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
 | 
			
		||||
 | 
			
		||||
	/* Create stdin handler. */
 | 
			
		||||
	setblocking(STDIN_FILENO, 0);
 | 
			
		||||
	event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
 | 
			
		||||
	    client_stdin_callback, NULL);
 | 
			
		||||
 | 
			
		||||
	/* Establish signal handlers. */
 | 
			
		||||
	set_signals(client_signal);
 | 
			
		||||
 | 
			
		||||
@@ -255,6 +262,7 @@ client_main(int argc, char **argv, int flags)
 | 
			
		||||
 | 
			
		||||
	/* Set the event and dispatch. */
 | 
			
		||||
	client_update_event();
 | 
			
		||||
	event_add (&client_stdin, NULL);
 | 
			
		||||
	event_dispatch();
 | 
			
		||||
 | 
			
		||||
	/* Print the exit message, if any, and exit. */
 | 
			
		||||
@@ -266,6 +274,7 @@ client_main(int argc, char **argv, int flags)
 | 
			
		||||
		if (client_exittype == MSG_DETACHKILL && ppid > 1)
 | 
			
		||||
			kill(ppid, SIGHUP);
 | 
			
		||||
	}
 | 
			
		||||
	setblocking(STDIN_FILENO, 1);
 | 
			
		||||
	return (client_exitval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -287,20 +296,11 @@ client_send_identify(int flags)
 | 
			
		||||
	    strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
 | 
			
		||||
		*data.term = '\0';
 | 
			
		||||
 | 
			
		||||
	if ((fd = dup(STDOUT_FILENO)) == -1)
 | 
			
		||||
		fatal("dup failed");
 | 
			
		||||
	imsg_compose(&client_ibuf,
 | 
			
		||||
	    MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
 | 
			
		||||
 | 
			
		||||
	if ((fd = dup(STDERR_FILENO)) == -1)
 | 
			
		||||
		fatal("dup failed");
 | 
			
		||||
	imsg_compose(&client_ibuf,
 | 
			
		||||
	    MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
 | 
			
		||||
 | 
			
		||||
	if ((fd = dup(STDIN_FILENO)) == -1)
 | 
			
		||||
		fatal("dup failed");
 | 
			
		||||
	imsg_compose(&client_ibuf,
 | 
			
		||||
	    MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
 | 
			
		||||
	client_update_event();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Forward entire environment to server. */
 | 
			
		||||
@@ -322,6 +322,7 @@ void
 | 
			
		||||
client_write_server(enum msgtype type, void *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
 | 
			
		||||
	client_update_event();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Update client event based on whether it needs to read or read and write. */
 | 
			
		||||
@@ -421,6 +422,23 @@ lost_server:
 | 
			
		||||
	event_loopexit(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Callback for client stdin read events. */
 | 
			
		||||
/* ARGSUSED */
 | 
			
		||||
void
 | 
			
		||||
client_stdin_callback(unused int fd, unused short events, unused void *data1)
 | 
			
		||||
{
 | 
			
		||||
	struct msg_stdin_data	data;
 | 
			
		||||
 | 
			
		||||
	data.size = read(STDIN_FILENO, data.data, sizeof data.data);
 | 
			
		||||
	if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	client_write_server(MSG_STDIN, &data, sizeof data);
 | 
			
		||||
	if (data.size <= 0)
 | 
			
		||||
		event_del(&client_stdin);
 | 
			
		||||
	client_update_event();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dispatch imsgs when in wait state (before MSG_READY). */
 | 
			
		||||
int
 | 
			
		||||
client_dispatch_wait(void *data)
 | 
			
		||||
@@ -429,11 +447,10 @@ client_dispatch_wait(void *data)
 | 
			
		||||
	ssize_t			n, datalen;
 | 
			
		||||
	struct msg_shell_data	shelldata;
 | 
			
		||||
	struct msg_exit_data	exitdata;
 | 
			
		||||
	struct msg_stdout_data	stdoutdata;
 | 
			
		||||
	struct msg_stderr_data	stderrdata;
 | 
			
		||||
	const char             *shellcmd = data;
 | 
			
		||||
 | 
			
		||||
	if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
 | 
			
		||||
		fatalx("imsg_read failed");
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
 | 
			
		||||
			fatalx("imsg_get failed");
 | 
			
		||||
@@ -441,6 +458,7 @@ client_dispatch_wait(void *data)
 | 
			
		||||
			return (0);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		log_debug("got %d from server", imsg.hdr.type);
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
@@ -457,14 +475,30 @@ client_dispatch_wait(void *data)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_READY size");
 | 
			
		||||
 | 
			
		||||
			event_del(&client_stdin);
 | 
			
		||||
			client_attached = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_STDOUT:
 | 
			
		||||
			if (datalen != sizeof stdoutdata)
 | 
			
		||||
				fatalx("bad MSG_STDOUT");
 | 
			
		||||
			memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
 | 
			
		||||
 | 
			
		||||
			fwrite(stdoutdata.data, stdoutdata.size, 1, stdout);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_STDERR:
 | 
			
		||||
			if (datalen != sizeof stderrdata)
 | 
			
		||||
				fatalx("bad MSG_STDERR");
 | 
			
		||||
			memcpy(&stderrdata, imsg.data, sizeof stderrdata);
 | 
			
		||||
 | 
			
		||||
			fwrite(stderrdata.data, stderrdata.size, 1, stderr);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_VERSION:
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_VERSION size");
 | 
			
		||||
 | 
			
		||||
			log_warnx("protocol version mismatch (client %u, "
 | 
			
		||||
			    "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
 | 
			
		||||
			fprintf(stderr, "protocol version mismatch "
 | 
			
		||||
			    "(client %u, server %u)\n", PROTOCOL_VERSION,
 | 
			
		||||
			    imsg.hdr.peerid);
 | 
			
		||||
			client_exitval = 1;
 | 
			
		||||
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user