diff options
Diffstat (limited to 'server-client.c')
-rw-r--r-- | server-client.c | 213 |
1 files changed, 86 insertions, 127 deletions
diff --git a/server-client.c b/server-client.c index f3731ae9..743ced40 100644 --- a/server-client.c +++ b/server-client.c @@ -48,6 +48,12 @@ static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch_command(struct client *, struct imsg *); static void server_client_dispatch_identify(struct client *, struct imsg *); static void server_client_dispatch_shell(struct client *); +static void server_client_dispatch_write_ready(struct client *, + struct imsg *); +static void server_client_dispatch_read_data(struct client *, + struct imsg *); +static void server_client_dispatch_read_done(struct client *, + struct imsg *); /* Number of attached clients. */ u_int @@ -195,16 +201,6 @@ server_client_create(int fd) TAILQ_INIT(&c->queue); - c->stdin_data = evbuffer_new(); - if (c->stdin_data == NULL) - fatalx("out of memory"); - c->stdout_data = evbuffer_new(); - if (c->stdout_data == NULL) - fatalx("out of memory"); - c->stderr_data = evbuffer_new(); - if (c->stderr_data == NULL) - fatalx("out of memory"); - c->tty.fd = -1; c->title = NULL; @@ -223,6 +219,8 @@ server_client_create(int fd) c->prompt_buffer = NULL; c->prompt_index = 0; + RB_INIT(&c->files); + c->flags |= CLIENT_FOCUSED; c->keytable = key_bindings_get_table("root", 1); @@ -264,6 +262,7 @@ void server_client_lost(struct client *c) { struct message_entry *msg, *msg1; + struct client_file *cf; c->flags |= CLIENT_DEAD; @@ -271,8 +270,10 @@ server_client_lost(struct client *c) status_prompt_clear(c); status_message_clear(c); - if (c->stdin_callback != NULL) - c->stdin_callback(c, 1, c->stdin_callback_data); + RB_FOREACH(cf, client_files, &c->files) { + cf->error = EINTR; + file_fire_done(cf); + } TAILQ_REMOVE(&clients, c, entry); log_debug("lost client %p", c); @@ -286,11 +287,6 @@ server_client_lost(struct client *c) free(c->ttyname); free(c->term); - evbuffer_free(c->stdin_data); - evbuffer_free(c->stdout_data); - if (c->stderr_data != c->stdout_data) - evbuffer_free(c->stderr_data); - status_free(c); free(c->title); @@ -1558,17 +1554,17 @@ server_client_click_timer(__unused int fd, __unused short events, void *data) static void server_client_check_exit(struct client *c) { + struct client_file *cf; + if (~c->flags & CLIENT_EXIT) return; if (c->flags & CLIENT_EXITED) return; - if (EVBUFFER_LENGTH(c->stdin_data) != 0) - return; - if (EVBUFFER_LENGTH(c->stdout_data) != 0) - return; - if (EVBUFFER_LENGTH(c->stderr_data) != 0) - return; + RB_FOREACH(cf, client_files, &c->files) { + if (EVBUFFER_LENGTH(cf->buffer) != 0) + return; + } if (c->flags & CLIENT_ATTACHED) notify_client("client-detached", c); @@ -1707,11 +1703,10 @@ server_client_set_title(struct client *c) static void server_client_dispatch(struct imsg *imsg, void *arg) { - struct client *c = arg; - struct msg_stdin_data stdindata; - const char *data; - ssize_t datalen; - struct session *s; + struct client *c = arg; + const char *data; + ssize_t datalen; + struct session *s; if (c->flags & CLIENT_DEAD) return; @@ -1738,21 +1733,6 @@ server_client_dispatch(struct imsg *imsg, void *arg) case MSG_COMMAND: server_client_dispatch_command(c, imsg); break; - case MSG_STDIN: - if (datalen != sizeof stdindata) - fatalx("bad MSG_STDIN size"); - memcpy(&stdindata, data, sizeof stdindata); - - if (c->stdin_callback == NULL) - break; - if (stdindata.size <= 0) - c->stdin_closed = 1; - else { - evbuffer_add(c->stdin_data, stdindata.data, - stdindata.size); - } - c->stdin_callback(c, c->stdin_closed, c->stdin_callback_data); - break; case MSG_RESIZE: if (datalen != 0) fatalx("bad MSG_RESIZE size"); @@ -1804,6 +1784,15 @@ server_client_dispatch(struct imsg *imsg, void *arg) server_client_dispatch_shell(c); break; + case MSG_WRITE_READY: + server_client_dispatch_write_ready(c, imsg); + break; + case MSG_READ: + server_client_dispatch_read_data(c, imsg); + break; + case MSG_READ_DONE: + server_client_dispatch_read_done(c, imsg); + break; } } @@ -1822,7 +1811,7 @@ server_client_command_done(struct cmdq_item *item, __unused void *data) static void server_client_dispatch_command(struct client *c, struct imsg *imsg) { - struct msg_command_data data; + struct msg_command data; char *buf; size_t len; int argc; @@ -1966,19 +1955,11 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg) #endif if (c->flags & CLIENT_CONTROL) { - c->stdin_callback = control_callback; - - evbuffer_free(c->stderr_data); - c->stderr_data = c->stdout_data; - - if (c->flags & CLIENT_CONTROLCONTROL) - evbuffer_add_printf(c->stdout_data, "\033P1000p"); - proc_send(c->peer, MSG_STDIN, -1, NULL, 0); - - c->tty.fd = -1; - close(c->fd); c->fd = -1; + + control_start(c); + c->tty.fd = -1; } else if (c->fd != -1) { if (tty_init(&c->tty, c, c->fd, c->term) != 0) { close(c->fd); @@ -2018,91 +1999,69 @@ server_client_dispatch_shell(struct client *c) proc_kill_peer(c->peer); } -/* Event callback to push more stdout data if any left. */ +/* Handle write ready message. */ static void -server_client_stdout_cb(__unused int fd, __unused short events, void *arg) +server_client_dispatch_write_ready(struct client *c, struct imsg *imsg) { - struct client *c = arg; - - if (~c->flags & CLIENT_DEAD) - server_client_push_stdout(c); - server_client_unref(c); + struct msg_write_ready *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + + if (msglen != sizeof *msg) + fatalx("bad MSG_WRITE_READY size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) + return; + if (msg->error != 0) { + cf->error = msg->error; + file_fire_done(cf); + } else + file_push(cf); } -/* Push stdout to client if possible. */ -void -server_client_push_stdout(struct client *c) +/* Handle read data message. */ +static void +server_client_dispatch_read_data(struct client *c, struct imsg *imsg) { - struct msg_stdout_data data; - size_t sent, left; - - left = EVBUFFER_LENGTH(c->stdout_data); - while (left != 0) { - sent = left; - if (sent > sizeof data.data) - sent = sizeof data.data; - memcpy(data.data, EVBUFFER_DATA(c->stdout_data), sent); - data.size = sent; - - if (proc_send(c->peer, MSG_STDOUT, -1, &data, sizeof data) != 0) - break; - evbuffer_drain(c->stdout_data, sent); + struct msg_read_data *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + void *bdata = msg->data; + size_t bsize = msg->size; + + if (msglen != sizeof *msg) + fatalx("bad MSG_READ_DATA size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) + return; - left = EVBUFFER_LENGTH(c->stdout_data); - log_debug("%s: client %p, sent %zu, left %zu", __func__, c, - sent, left); - } - if (left != 0) { - c->references++; - event_once(-1, EV_TIMEOUT, server_client_stdout_cb, c, NULL); - log_debug("%s: client %p, queued", __func__, c); + log_debug("%s: file %d read %zu bytes", c->name, cf->stream, bsize); + if (cf->error == 0) { + if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { + cf->error = ENOMEM; + file_fire_done(cf); + } else + file_fire_read(cf); } } -/* Event callback to push more stderr data if any left. */ +/* Handle read done message. */ static void -server_client_stderr_cb(__unused int fd, __unused short events, void *arg) +server_client_dispatch_read_done(struct client *c, struct imsg *imsg) { - struct client *c = arg; - - if (~c->flags & CLIENT_DEAD) - server_client_push_stderr(c); - server_client_unref(c); -} - -/* Push stderr to client if possible. */ -void -server_client_push_stderr(struct client *c) -{ - struct msg_stderr_data data; - size_t sent, left; - - if (c->stderr_data == c->stdout_data) { - server_client_push_stdout(c); + struct msg_read_done *msg = imsg->data; + size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; + struct client_file find, *cf; + + if (msglen != sizeof *msg) + fatalx("bad MSG_READ_DONE size"); + find.stream = msg->stream; + if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) return; - } - - left = EVBUFFER_LENGTH(c->stderr_data); - while (left != 0) { - sent = left; - if (sent > sizeof data.data) - sent = sizeof data.data; - memcpy(data.data, EVBUFFER_DATA(c->stderr_data), sent); - data.size = sent; - - if (proc_send(c->peer, MSG_STDERR, -1, &data, sizeof data) != 0) - break; - evbuffer_drain(c->stderr_data, sent); - left = EVBUFFER_LENGTH(c->stderr_data); - log_debug("%s: client %p, sent %zu, left %zu", __func__, c, - sent, left); - } - if (left != 0) { - c->references++; - event_once(-1, EV_TIMEOUT, server_client_stderr_cb, c, NULL); - log_debug("%s: client %p, queued", __func__, c); - } + log_debug("%s: file %d read done", c->name, cf->stream); + cf->error = msg->error; + file_fire_done(cf); } /* Add to client message log. */ |