=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/server-client.c,v retrieving revision 1.351 retrieving revision 1.352 diff -u -r1.351 -r1.352 --- src/usr.bin/tmux/server-client.c 2020/05/26 08:41:47 1.351 +++ src/usr.bin/tmux/server-client.c 2020/06/01 09:43:01 1.352 @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.351 2020/05/26 08:41:47 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.352 2020/06/01 09:43:01 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -58,6 +58,9 @@ static void server_client_dispatch_read_done(struct client *, struct imsg *); +/* Maximum data allowed to be held for a pane for a control client. */ +#define SERVER_CLIENT_PANE_LIMIT 16777216 + /* Compare client windows. */ static int server_client_window_cmp(struct client_window *cw1, @@ -80,7 +83,7 @@ n = 0; TAILQ_FOREACH(c, &clients, entry) { - if (c->session != NULL && (~c->flags & CLIENT_DETACHING)) + if (c->session != NULL && (~c->flags & CLIENT_UNATTACHEDFLAGS)) n++; } return (n); @@ -386,7 +389,7 @@ { struct session *s = c->session; - if (s == NULL || (c->flags & CLIENT_DETACHING)) + if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) return; tty_stop_tty(&c->tty); @@ -400,12 +403,14 @@ { struct session *s = c->session; - if (s == NULL || (c->flags & CLIENT_DETACHING)) + if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) return; - c->flags |= CLIENT_DETACHING; - notify_client("client-detached", c); - proc_send(c->peer, msgtype, -1, s->name, strlen(s->name) + 1); + c->flags |= CLIENT_EXIT; + + c->exit_type = CLIENT_EXIT_DETACH; + c->exit_msgtype = msgtype; + c->exit_session = xstrdup(s->name); } /* Execute command to replace a client. */ @@ -1507,12 +1512,12 @@ u_int attached_clients = 0; /* - * Work out the minimum acknowledged size. This is the most that can be - * removed from the buffer. + * Work out the minimum used size. This is the most that can be removed + * from the buffer. */ - minimum = wp->offset.acknowledged; - if (wp->pipe_fd != -1 && wp->pipe_offset.acknowledged < minimum) - minimum = wp->pipe_offset.acknowledged; + minimum = wp->offset.used; + if (wp->pipe_fd != -1 && wp->pipe_offset.used < minimum) + minimum = wp->pipe_offset.used; TAILQ_FOREACH(c, &clients, entry) { if (c->session == NULL) continue; @@ -1530,11 +1535,13 @@ if (!flag) off = 0; - log_debug("%s: %s has %zu bytes used, %zu bytes acknowledged " - "for %%%u", __func__, c->name, wpo->used, wpo->acknowledged, - wp->id); - if (wpo->acknowledged < minimum) - minimum = wpo->acknowledged; + log_debug("%s: %s has %zu bytes used for %%%u", __func__, + c->name, wpo->used - wp->base_offset, wp->id); + if (wpo->used - wp->base_offset > SERVER_CLIENT_PANE_LIMIT) { + control_flush(c); + c->flags |= CLIENT_EXIT; + } else if (wpo->used < minimum) + minimum = wpo->used; } if (attached_clients == 0) off = 0; @@ -1543,8 +1550,8 @@ goto out; /* Drain the buffer. */ - log_debug("%s: %%%u has %zu minimum (of %zu) bytes acknowledged", - __func__, wp->id, minimum, EVBUFFER_LENGTH(evb)); + log_debug("%s: %%%u has %zu minimum (of %zu) bytes used", __func__, + wp->id, minimum, EVBUFFER_LENGTH(evb)); evbuffer_drain(evb, minimum); /* @@ -1553,20 +1560,15 @@ */ if (wp->base_offset > SIZE_MAX - minimum) { log_debug("%s: %%%u base offset has wrapped", __func__, wp->id); - wp->offset.acknowledged -= wp->base_offset; wp->offset.used -= wp->base_offset; - if (wp->pipe_fd != -1) { - wp->pipe_offset.acknowledged -= wp->base_offset; + if (wp->pipe_fd != -1) wp->pipe_offset.used -= wp->base_offset; - } TAILQ_FOREACH(c, &clients, entry) { if (c->session == NULL || (~c->flags & CLIENT_CONTROL)) continue; wpo = control_pane_offset(c, wp, &flag); - if (wpo != NULL && !flag) { - wpo->acknowledged -= wp->base_offset; + if (wpo != NULL && !flag) wpo->used -= wp->base_offset; - } } wp->base_offset = minimum; } else @@ -1579,6 +1581,7 @@ * clients, all of which are control clients which are not able to * accept any more data. */ + log_debug("%s: pane %%%u is %s", __func__, wp->id, off ? "off" : "on"); if (off) bufferevent_disable(wp->event, EV_READ); else @@ -1770,12 +1773,16 @@ server_client_check_exit(struct client *c) { struct client_file *cf; + const char *name = c->exit_session; - if (~c->flags & CLIENT_EXIT) + if ((c->flags & CLIENT_EXITED) || (~c->flags & CLIENT_EXIT)) return; - if (c->flags & CLIENT_EXITED) - return; + if (c->flags & CLIENT_CONTROL) { + control_flush(c); + if (!control_all_done(c)) + return; + } RB_FOREACH(cf, client_files, &c->files) { if (EVBUFFER_LENGTH(cf->buffer) != 0) return; @@ -1783,8 +1790,20 @@ if (c->flags & CLIENT_ATTACHED) notify_client("client-detached", c); - proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval); c->flags |= CLIENT_EXITED; + + switch (c->exit_type) { + case CLIENT_EXIT_RETURN: + proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval); + break; + case CLIENT_EXIT_SHUTDOWN: + proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0); + break; + case CLIENT_EXIT_DETACH: + proc_send(c->peer, c->exit_msgtype, -1, name, strlen(name) + 1); + break; + } + free(c->exit_session); } /* Redraw timer callback. */ @@ -1996,7 +2015,6 @@ case MSG_EXITING: if (datalen != 0) fatalx("bad MSG_EXITING size"); - c->session = NULL; tty_close(&c->tty); proc_send(c->peer, MSG_EXITED, -1, NULL, 0); @@ -2050,7 +2068,7 @@ if (~c->flags & CLIENT_ATTACHED) c->flags |= CLIENT_EXIT; - else if (~c->flags & CLIENT_DETACHING) + else if (~c->flags & CLIENT_EXIT) tty_send_requests(&c->tty); return (CMD_RETURN_NORMAL); } @@ -2372,7 +2390,7 @@ else c->flags |= flag; if (flag == CLIENT_CONTROL_NOOUTPUT) - control_free_offsets(c); + control_reset_offsets(c); } free(copy); }