aboutsummaryrefslogtreecommitdiff
path: root/server-fn.c
diff options
context:
space:
mode:
authorTiago Cunha <tcunha@gmx.com>2012-05-22 20:56:35 +0000
committerTiago Cunha <tcunha@gmx.com>2012-05-22 20:56:35 +0000
commitffab6dbc9a14b515be3d67d02f8618e93cf5aee6 (patch)
tree9ad9dfc3bcc8e7133192c700835621dc9c35259e /server-fn.c
parent04bf0d8efc25d7e40fc034db0f2546cf8a09cfda (diff)
downloadrtmux-ffab6dbc9a14b515be3d67d02f8618e93cf5aee6.tar.gz
rtmux-ffab6dbc9a14b515be3d67d02f8618e93cf5aee6.tar.bz2
rtmux-ffab6dbc9a14b515be3d67d02f8618e93cf5aee6.zip
Sync OpenBSD patchset 1114:
Instead of passing stdin/stdout/stderr file descriptors over imsg and handling them in the server, handle them in the client and pass buffers over imsg. This is much tidier for some upcoming changes and the performance hit isn't critical. The tty fd is still passed to the server as before. This bumps the tmux protocol version so new clients and old servers are incompatible.
Diffstat (limited to 'server-fn.c')
-rw-r--r--server-fn.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/server-fn.c b/server-fn.c
index dd79461c..9f51a9e7 100644
--- a/server-fn.c
+++ b/server-fn.c
@@ -46,17 +46,21 @@ server_fill_environ(struct session *s, struct environ *env)
environ_set(env, "TMUX", var);
}
-void
+int
server_write_client(
struct client *c, enum msgtype type, const void *buf, size_t len)
{
struct imsgbuf *ibuf = &c->ibuf;
+ int error;
if (c->flags & CLIENT_BAD)
- return;
+ return (-1);
log_debug("writing %d to client %d", type, c->ibuf.fd);
- imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1, (void *) buf, len);
- server_update_event(c);
+ error = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, -1,
+ (void *) buf, len);
+ if (error == 1)
+ server_update_event(c);
+ return (error == 1 ? 0 : -1);
}
void
@@ -502,3 +506,71 @@ server_update_event(struct client *c)
event_set(&c->event, c->ibuf.fd, events, server_client_callback, c);
event_add(&c->event, NULL);
}
+
+/* Push stdout to client if possible. */
+void
+server_push_stdout(struct client *c)
+{
+ struct msg_stdout_data data;
+ size_t size;
+
+ size = EVBUFFER_LENGTH(c->stdout_data);
+ if (size == 0)
+ return;
+ if (size > sizeof data.data)
+ size = sizeof data.data;
+
+ memcpy(data.data, EVBUFFER_DATA(c->stdout_data), size);
+ data.size = size;
+
+ if (server_write_client(c, MSG_STDOUT, &data, sizeof data) == 0)
+ evbuffer_drain(c->stdout_data, size);
+}
+
+/* Push stderr to client if possible. */
+void
+server_push_stderr(struct client *c)
+{
+ struct msg_stderr_data data;
+ size_t size;
+
+ size = EVBUFFER_LENGTH(c->stderr_data);
+ if (size == 0)
+ return;
+ if (size > sizeof data.data)
+ size = sizeof data.data;
+
+ memcpy(data.data, EVBUFFER_DATA(c->stderr_data), size);
+ data.size = size;
+
+ if (server_write_client(c, MSG_STDERR, &data, sizeof data) == 0)
+ evbuffer_drain(c->stderr_data, size);
+}
+
+/* Set stdin callback. */
+int
+server_set_stdin_callback(struct client *c, void (*cb)(struct client *, int,
+ void *), void *cb_data, char **cause)
+{
+ if (c == NULL) {
+ *cause = xstrdup("no client with stdin");
+ return (-1);
+ }
+ if (c->flags & CLIENT_TERMINAL) {
+ *cause = xstrdup("stdin is a tty");
+ return (-1);
+ }
+ if (c->stdin_callback != NULL) {
+ *cause = xstrdup("stdin in use");
+ return (-1);
+ }
+
+ c->stdin_callback_data = cb_data;
+ c->stdin_callback = cb;
+
+ c->references++;
+
+ if (c->stdin_closed)
+ c->stdin_callback (c, 1, c->stdin_callback_data);
+ return (0);
+}