aboutsummaryrefslogtreecommitdiff
path: root/server-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'server-client.c')
-rw-r--r--server-client.c213
1 files changed, 86 insertions, 127 deletions
diff --git a/server-client.c b/server-client.c
index bd256cb8..e6e4d8a9 100644
--- a/server-client.c
+++ b/server-client.c
@@ -50,6 +50,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
@@ -197,16 +203,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;
@@ -225,6 +221,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);
@@ -266,6 +264,7 @@ void
server_client_lost(struct client *c)
{
struct message_entry *msg, *msg1;
+ struct client_file *cf;
c->flags |= CLIENT_DEAD;
@@ -273,8 +272,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);
@@ -288,11 +289,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);
@@ -1560,17 +1556,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);
@@ -1709,11 +1705,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;
@@ -1740,21 +1735,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");
@@ -1806,6 +1786,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;
}
}
@@ -1824,7 +1813,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;
@@ -1964,19 +1953,11 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
log_debug("client %p name is %s", c, c->name);
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);
@@ -2016,91 +1997,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. */