summaryrefslogtreecommitdiffstats
path: root/client.c
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2009-08-11 17:18:35 +0000
committerNicholas Marriott <nicm@openbsd.org>2009-08-11 17:18:35 +0000
commitf0635717b3e840a72a962a2014b18d84fac4c83a (patch)
tree579ab8805cc7d6784fb6c567dad3322a7b2a976e /client.c
parent60db6e3df471142e4ee7773b9b4e9b0135d61dfc (diff)
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.
Diffstat (limited to 'client.c')
-rw-r--r--client.c72
1 files changed, 44 insertions, 28 deletions
diff --git a/client.c b/client.c
index 4e756981..a56af84e 100644
--- a/client.c
+++ b/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)
- return (0);
- memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
- if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
+ if ((n = imsg_get(&cctx->ibuf, &imsg)) == -1)
+ fatalx("imsg_get failed");
+ if (n == 0)
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);
}
}