summaryrefslogtreecommitdiffstats
path: root/server-client.c
diff options
context:
space:
mode:
authornicm <nicm>2015-11-14 09:41:06 +0000
committernicm <nicm>2015-11-14 09:41:06 +0000
commitc56b81a2ce815f6d289232f20bb6e07cfd0e36ec (patch)
tree7a018a8f9d4354684ad5748e4d218fd8d3273fc5 /server-client.c
parent908e6bb68f127f2bdf0c15ac25dde9ccc06e9104 (diff)
Push stdout and stderr to clients more aggressively, and add an event to
continue if the send fails.
Diffstat (limited to 'server-client.c')
-rw-r--r--server-client.c90
1 files changed, 87 insertions, 3 deletions
diff --git a/server-client.c b/server-client.c
index fedc93bd..645492d1 100644
--- a/server-client.c
+++ b/server-client.c
@@ -1035,9 +1035,6 @@ server_client_dispatch(struct imsg *imsg, void *arg)
server_client_dispatch_shell(c);
break;
}
-
- server_push_stdout(c);
- server_push_stderr(c);
}
/* Handle command message. */
@@ -1214,3 +1211,90 @@ server_client_dispatch_shell(struct client *c)
proc_kill_peer(c->peer);
}
+
+/* Event callback to push more stdout data if any left. */
+static void
+server_client_stdout_cb(unused int fd, unused short events, void *arg)
+{
+ struct client *c = arg;
+
+ if (~c->flags & CLIENT_DEAD)
+ server_client_push_stdout(c);
+ server_client_unref(c);
+}
+
+/* Push stdout to client if possible. */
+void
+server_client_push_stdout(struct client *c)
+{
+ 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);
+
+ 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);
+ }
+}
+
+/* Event callback to push more stderr data if any left. */
+static void
+server_client_stderr_cb(unused int fd, unused short events, void *arg)
+{
+ 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);
+ 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);
+ }
+}