mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Switch tmux to use imsg. This is the last major change to make the
client-server protocol more resilient and make the protocol versioning work properly. In future, the only things requiring a protocol version bump will be changes in the message structs, and (when both client and server have this change) mixing different versions should nicely report an error message. As a side effect this also makes the code tidier, fixes a problem with the way errors reported during server startup were handled, and supports fd passing (which will be used in future). Looked over by eric@, thanks. Please note that mixing a client with this change with an older server or vice versa may cause tmux to crash or hang - tmux should be completely exited before upgrading.
This commit is contained in:
		
							
								
								
									
										72
									
								
								client.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								client.c
									
									
									
									
									
								
							@@ -92,16 +92,13 @@ server_started:
 | 
			
		||||
		fatal("fcntl failed");
 | 
			
		||||
	if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1)
 | 
			
		||||
		fatal("fcntl failed");
 | 
			
		||||
	cctx->srv_fd = fd;
 | 
			
		||||
	cctx->srv_in = buffer_create(BUFSIZ);
 | 
			
		||||
	cctx->srv_out = buffer_create(BUFSIZ);
 | 
			
		||||
	imsg_init(&cctx->ibuf, fd);
 | 
			
		||||
 | 
			
		||||
	if (cmdflags & CMD_SENDENVIRON)
 | 
			
		||||
		client_send_environ(cctx);
 | 
			
		||||
	if (isatty(STDIN_FILENO)) {
 | 
			
		||||
		if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
 | 
			
		||||
			fatal("ioctl(TIOCGWINSZ)");
 | 
			
		||||
		data.version = PROTOCOL_VERSION;
 | 
			
		||||
		data.flags = flags;
 | 
			
		||||
		data.sx = ws.ws_col;
 | 
			
		||||
		data.sy = ws.ws_row;
 | 
			
		||||
@@ -153,6 +150,7 @@ int
 | 
			
		||||
client_main(struct client_ctx *cctx)
 | 
			
		||||
{
 | 
			
		||||
	struct pollfd	 pfd;
 | 
			
		||||
	int		 nfds;
 | 
			
		||||
 | 
			
		||||
	siginit();
 | 
			
		||||
 | 
			
		||||
@@ -173,24 +171,33 @@ client_main(struct client_ctx *cctx)
 | 
			
		||||
			sigcont = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pfd.fd = cctx->srv_fd;
 | 
			
		||||
		pfd.fd = cctx->ibuf.fd;
 | 
			
		||||
		pfd.events = POLLIN;
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_out) > 0)
 | 
			
		||||
		if (cctx->ibuf.w.queued > 0)
 | 
			
		||||
			pfd.events |= POLLOUT;
 | 
			
		||||
 | 
			
		||||
		if (poll(&pfd, 1, INFTIM) == -1) {
 | 
			
		||||
		if ((nfds = poll(&pfd, 1, INFTIM)) == -1) {
 | 
			
		||||
			if (errno == EAGAIN || errno == EINTR)
 | 
			
		||||
				continue;
 | 
			
		||||
			fatal("poll failed");
 | 
			
		||||
		}
 | 
			
		||||
		if (nfds == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0) {
 | 
			
		||||
			cctx->exittype = CCTX_DIED;
 | 
			
		||||
			break;
 | 
			
		||||
		if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
 | 
			
		||||
			fatalx("socket error");
 | 
			
		||||
 | 
			
		||||
		if (pfd.revents & POLLIN) {
 | 
			
		||||
			if (client_msg_dispatch(cctx) != 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (client_msg_dispatch(cctx) != 0)
 | 
			
		||||
			break;
 | 
			
		||||
		if (pfd.revents & POLLOUT) {
 | 
			
		||||
			if (msgbuf_write(&cctx->ibuf.w) < 0) {
 | 
			
		||||
				cctx->exittype = CCTX_DIED;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 	if (sigterm) {
 | 
			
		||||
@@ -235,54 +242,61 @@ client_handle_winch(struct client_ctx *cctx)
 | 
			
		||||
int
 | 
			
		||||
client_msg_dispatch(struct client_ctx *cctx)
 | 
			
		||||
{
 | 
			
		||||
	struct hdr		 hdr;
 | 
			
		||||
	struct imsg		 imsg;
 | 
			
		||||
	struct msg_print_data	 printdata;
 | 
			
		||||
	ssize_t			 n, datalen;
 | 
			
		||||
 | 
			
		||||
	if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) {
 | 
			
		||||
		cctx->exittype = CCTX_DIED;
 | 
			
		||||
		return (-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
 | 
			
		||||
		if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
 | 
			
		||||
			fatalx("imsg_get failed");
 | 
			
		||||
		if (n == 0)
 | 
			
		||||
			return (0);
 | 
			
		||||
		memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
 | 
			
		||||
		if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
 | 
			
		||||
			return (0);
 | 
			
		||||
		buffer_remove(cctx->srv_in, sizeof hdr);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		switch (hdr.type) {
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_DETACH:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_DETACH size");
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_DETACH;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			if (hdr.size != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			buffer_read(cctx->srv_in, &printdata, sizeof printdata);
 | 
			
		||||
			if (datalen != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_ERROR size");
 | 
			
		||||
			memcpy(&printdata, imsg.data, sizeof printdata);
 | 
			
		||||
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
			cctx->errstr = xstrdup(printdata.msg);
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXIT size");
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_EXIT;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_EXITED:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXITED size");
 | 
			
		||||
 | 
			
		||||
			imsg_free(&imsg);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_SHUTDOWN size");
 | 
			
		||||
 | 
			
		||||
			client_write_server(cctx, MSG_EXITING, NULL, 0);
 | 
			
		||||
			cctx->exittype = CCTX_SHUTDOWN;
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_SUSPEND:
 | 
			
		||||
			if (hdr.size != 0)
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_SUSPEND size");
 | 
			
		||||
 | 
			
		||||
			client_suspend();
 | 
			
		||||
@@ -290,5 +304,7 @@ client_msg_dispatch(struct client_ctx *cctx)
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected message");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imsg_free(&imsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user