mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +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:
		
							
								
								
									
										112
									
								
								tmux.c
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								tmux.c
									
									
									
									
									
								
							@@ -60,6 +60,7 @@ __dead void	 usage(void);
 | 
			
		||||
char 		*makesockpath(const char *);
 | 
			
		||||
int		 prepare_unlock(enum msgtype *, void **, size_t *, int);
 | 
			
		||||
int		 prepare_cmd(enum msgtype *, void **, size_t *, int, char **);
 | 
			
		||||
int		 dispatch_imsg(struct client_ctx *, int *);
 | 
			
		||||
 | 
			
		||||
__dead void
 | 
			
		||||
usage(void)
 | 
			
		||||
@@ -260,14 +261,13 @@ main(int argc, char **argv)
 | 
			
		||||
 	struct cmd		*cmd;
 | 
			
		||||
	struct pollfd	 	 pfd;
 | 
			
		||||
	enum msgtype		 msg;
 | 
			
		||||
	struct hdr	 	 hdr;
 | 
			
		||||
	struct passwd		*pw;
 | 
			
		||||
	struct msg_print_data	 printdata;
 | 
			
		||||
	char			*s, *path, *label, *home, *cause, **var;
 | 
			
		||||
	char			 cwd[MAXPATHLEN];
 | 
			
		||||
	void			*buf;
 | 
			
		||||
	size_t			 len;
 | 
			
		||||
	int	 		 retcode, opt, flags, unlock, cmdflags = 0;
 | 
			
		||||
	int			 nfds;
 | 
			
		||||
 | 
			
		||||
	unlock = flags = 0;
 | 
			
		||||
	label = path = NULL;
 | 
			
		||||
@@ -493,58 +493,92 @@ main(int argc, char **argv)
 | 
			
		||||
 | 
			
		||||
	retcode = 0;
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		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 (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
	restart:
 | 
			
		||||
		if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
 | 
			
		||||
		if (nfds == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
 | 
			
		||||
		if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
 | 
			
		||||
			continue;
 | 
			
		||||
		buffer_remove(cctx.srv_in, sizeof hdr);
 | 
			
		||||
 | 
			
		||||
		switch (hdr.type) {
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			goto out;
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			retcode = 1;
 | 
			
		||||
			/* FALLTHROUGH */
 | 
			
		||||
		case MSG_PRINT:
 | 
			
		||||
			if (hdr.size < sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			buffer_read(cctx.srv_in, &printdata, sizeof printdata);
 | 
			
		||||
		if (pfd.revents & (POLLERR|POLLHUP|POLLNVAL))
 | 
			
		||||
			fatalx("socket error");
 | 
			
		||||
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
			log_info("%s", printdata.msg);
 | 
			
		||||
			goto restart;
 | 
			
		||||
		case MSG_READY:
 | 
			
		||||
			retcode = client_main(&cctx);
 | 
			
		||||
			goto out;
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected command");
 | 
			
		||||
                if (pfd.revents & POLLIN) {
 | 
			
		||||
			if (dispatch_imsg(&cctx, &retcode) != 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pfd.revents & POLLOUT) {
 | 
			
		||||
			if (msgbuf_write(&cctx.ibuf.w) < 0)
 | 
			
		||||
				fatalx("msgbuf_write failed");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	options_free(&global_s_options);
 | 
			
		||||
	options_free(&global_w_options);
 | 
			
		||||
 | 
			
		||||
	close(cctx.srv_fd);
 | 
			
		||||
	buffer_destroy(cctx.srv_in);
 | 
			
		||||
	buffer_destroy(cctx.srv_out);
 | 
			
		||||
 | 
			
		||||
	return (retcode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
dispatch_imsg(struct client_ctx *cctx, int *retcode)
 | 
			
		||||
{
 | 
			
		||||
	struct imsg		imsg;
 | 
			
		||||
	ssize_t			n, datalen;
 | 
			
		||||
	struct msg_print_data	printdata;
 | 
			
		||||
 | 
			
		||||
        if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0)
 | 
			
		||||
		fatalx("imsg_read failed");
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
 | 
			
		||||
			fatalx("imsg_get failed");
 | 
			
		||||
		if (n == 0)
 | 
			
		||||
			return (0);
 | 
			
		||||
		datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
 | 
			
		||||
 | 
			
		||||
		switch (imsg.hdr.type) {
 | 
			
		||||
		case MSG_EXIT:
 | 
			
		||||
		case MSG_SHUTDOWN:
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_EXIT size");
 | 
			
		||||
 | 
			
		||||
			return (-1);
 | 
			
		||||
		case MSG_ERROR:
 | 
			
		||||
			*retcode = 1;
 | 
			
		||||
			/* FALLTHROUGH */
 | 
			
		||||
		case MSG_PRINT:
 | 
			
		||||
			if (datalen != sizeof printdata)
 | 
			
		||||
				fatalx("bad MSG_PRINT size");
 | 
			
		||||
			memcpy(&printdata, imsg.data, sizeof printdata);
 | 
			
		||||
			printdata.msg[(sizeof printdata.msg) - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
			log_info("%s", printdata.msg);
 | 
			
		||||
			break;
 | 
			
		||||
		case MSG_READY:
 | 
			
		||||
			if (datalen != 0)
 | 
			
		||||
				fatalx("bad MSG_READY size");
 | 
			
		||||
 | 
			
		||||
			*retcode = client_main(cctx);
 | 
			
		||||
			return (-1);
 | 
			
		||||
		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);
 | 
			
		||||
			*retcode = 1;
 | 
			
		||||
			return (-1);
 | 
			
		||||
		default:
 | 
			
		||||
			fatalx("unexpected message");
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		imsg_free(&imsg);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user