version 1.351, 2020/05/26 08:41:47 |
version 1.352, 2020/06/01 09:43:01 |
|
|
static void server_client_dispatch_read_done(struct client *, |
static void server_client_dispatch_read_done(struct client *, |
struct imsg *); |
struct imsg *); |
|
|
|
/* Maximum data allowed to be held for a pane for a control client. */ |
|
#define SERVER_CLIENT_PANE_LIMIT 16777216 |
|
|
/* Compare client windows. */ |
/* Compare client windows. */ |
static int |
static int |
server_client_window_cmp(struct client_window *cw1, |
server_client_window_cmp(struct client_window *cw1, |
|
|
|
|
n = 0; |
n = 0; |
TAILQ_FOREACH(c, &clients, entry) { |
TAILQ_FOREACH(c, &clients, entry) { |
if (c->session != NULL && (~c->flags & CLIENT_DETACHING)) |
if (c->session != NULL && (~c->flags & CLIENT_UNATTACHEDFLAGS)) |
n++; |
n++; |
} |
} |
return (n); |
return (n); |
|
|
{ |
{ |
struct session *s = c->session; |
struct session *s = c->session; |
|
|
if (s == NULL || (c->flags & CLIENT_DETACHING)) |
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) |
return; |
return; |
|
|
tty_stop_tty(&c->tty); |
tty_stop_tty(&c->tty); |
|
|
{ |
{ |
struct session *s = c->session; |
struct session *s = c->session; |
|
|
if (s == NULL || (c->flags & CLIENT_DETACHING)) |
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) |
return; |
return; |
|
|
c->flags |= CLIENT_DETACHING; |
c->flags |= CLIENT_EXIT; |
notify_client("client-detached", c); |
|
proc_send(c->peer, msgtype, -1, s->name, strlen(s->name) + 1); |
c->exit_type = CLIENT_EXIT_DETACH; |
|
c->exit_msgtype = msgtype; |
|
c->exit_session = xstrdup(s->name); |
} |
} |
|
|
/* Execute command to replace a client. */ |
/* Execute command to replace a client. */ |
|
|
u_int attached_clients = 0; |
u_int attached_clients = 0; |
|
|
/* |
/* |
* Work out the minimum acknowledged size. This is the most that can be |
* Work out the minimum used size. This is the most that can be removed |
* removed from the buffer. |
* from the buffer. |
*/ |
*/ |
minimum = wp->offset.acknowledged; |
minimum = wp->offset.used; |
if (wp->pipe_fd != -1 && wp->pipe_offset.acknowledged < minimum) |
if (wp->pipe_fd != -1 && wp->pipe_offset.used < minimum) |
minimum = wp->pipe_offset.acknowledged; |
minimum = wp->pipe_offset.used; |
TAILQ_FOREACH(c, &clients, entry) { |
TAILQ_FOREACH(c, &clients, entry) { |
if (c->session == NULL) |
if (c->session == NULL) |
continue; |
continue; |
|
|
if (!flag) |
if (!flag) |
off = 0; |
off = 0; |
|
|
log_debug("%s: %s has %zu bytes used, %zu bytes acknowledged " |
log_debug("%s: %s has %zu bytes used for %%%u", __func__, |
"for %%%u", __func__, c->name, wpo->used, wpo->acknowledged, |
c->name, wpo->used - wp->base_offset, wp->id); |
wp->id); |
if (wpo->used - wp->base_offset > SERVER_CLIENT_PANE_LIMIT) { |
if (wpo->acknowledged < minimum) |
control_flush(c); |
minimum = wpo->acknowledged; |
c->flags |= CLIENT_EXIT; |
|
} else if (wpo->used < minimum) |
|
minimum = wpo->used; |
} |
} |
if (attached_clients == 0) |
if (attached_clients == 0) |
off = 0; |
off = 0; |
|
|
goto out; |
goto out; |
|
|
/* Drain the buffer. */ |
/* Drain the buffer. */ |
log_debug("%s: %%%u has %zu minimum (of %zu) bytes acknowledged", |
log_debug("%s: %%%u has %zu minimum (of %zu) bytes used", __func__, |
__func__, wp->id, minimum, EVBUFFER_LENGTH(evb)); |
wp->id, minimum, EVBUFFER_LENGTH(evb)); |
evbuffer_drain(evb, minimum); |
evbuffer_drain(evb, minimum); |
|
|
/* |
/* |
|
|
*/ |
*/ |
if (wp->base_offset > SIZE_MAX - minimum) { |
if (wp->base_offset > SIZE_MAX - minimum) { |
log_debug("%s: %%%u base offset has wrapped", __func__, wp->id); |
log_debug("%s: %%%u base offset has wrapped", __func__, wp->id); |
wp->offset.acknowledged -= wp->base_offset; |
|
wp->offset.used -= wp->base_offset; |
wp->offset.used -= wp->base_offset; |
if (wp->pipe_fd != -1) { |
if (wp->pipe_fd != -1) |
wp->pipe_offset.acknowledged -= wp->base_offset; |
|
wp->pipe_offset.used -= wp->base_offset; |
wp->pipe_offset.used -= wp->base_offset; |
} |
|
TAILQ_FOREACH(c, &clients, entry) { |
TAILQ_FOREACH(c, &clients, entry) { |
if (c->session == NULL || (~c->flags & CLIENT_CONTROL)) |
if (c->session == NULL || (~c->flags & CLIENT_CONTROL)) |
continue; |
continue; |
wpo = control_pane_offset(c, wp, &flag); |
wpo = control_pane_offset(c, wp, &flag); |
if (wpo != NULL && !flag) { |
if (wpo != NULL && !flag) |
wpo->acknowledged -= wp->base_offset; |
|
wpo->used -= wp->base_offset; |
wpo->used -= wp->base_offset; |
} |
|
} |
} |
wp->base_offset = minimum; |
wp->base_offset = minimum; |
} else |
} else |
|
|
* clients, all of which are control clients which are not able to |
* clients, all of which are control clients which are not able to |
* accept any more data. |
* accept any more data. |
*/ |
*/ |
|
log_debug("%s: pane %%%u is %s", __func__, wp->id, off ? "off" : "on"); |
if (off) |
if (off) |
bufferevent_disable(wp->event, EV_READ); |
bufferevent_disable(wp->event, EV_READ); |
else |
else |
|
|
server_client_check_exit(struct client *c) |
server_client_check_exit(struct client *c) |
{ |
{ |
struct client_file *cf; |
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; |
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) { |
RB_FOREACH(cf, client_files, &c->files) { |
if (EVBUFFER_LENGTH(cf->buffer) != 0) |
if (EVBUFFER_LENGTH(cf->buffer) != 0) |
return; |
return; |
|
|
|
|
if (c->flags & CLIENT_ATTACHED) |
if (c->flags & CLIENT_ATTACHED) |
notify_client("client-detached", c); |
notify_client("client-detached", c); |
proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval); |
|
c->flags |= CLIENT_EXITED; |
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. */ |
/* Redraw timer callback. */ |
|
|
case MSG_EXITING: |
case MSG_EXITING: |
if (datalen != 0) |
if (datalen != 0) |
fatalx("bad MSG_EXITING size"); |
fatalx("bad MSG_EXITING size"); |
|
|
c->session = NULL; |
c->session = NULL; |
tty_close(&c->tty); |
tty_close(&c->tty); |
proc_send(c->peer, MSG_EXITED, -1, NULL, 0); |
proc_send(c->peer, MSG_EXITED, -1, NULL, 0); |
|
|
|
|
if (~c->flags & CLIENT_ATTACHED) |
if (~c->flags & CLIENT_ATTACHED) |
c->flags |= CLIENT_EXIT; |
c->flags |= CLIENT_EXIT; |
else if (~c->flags & CLIENT_DETACHING) |
else if (~c->flags & CLIENT_EXIT) |
tty_send_requests(&c->tty); |
tty_send_requests(&c->tty); |
return (CMD_RETURN_NORMAL); |
return (CMD_RETURN_NORMAL); |
} |
} |
|
|
else |
else |
c->flags |= flag; |
c->flags |= flag; |
if (flag == CLIENT_CONTROL_NOOUTPUT) |
if (flag == CLIENT_CONTROL_NOOUTPUT) |
control_free_offsets(c); |
control_reset_offsets(c); |
} |
} |
free(copy); |
free(copy); |
} |
} |