summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@openbsd.org>2012-05-21 18:27:42 +0000
committerNicholas Marriott <nicm@openbsd.org>2012-05-21 18:27:42 +0000
commit7a4679a17f827efaebb5dac5059f4b8bba69c4cf (patch)
tree03e87bbf9af9f6e8a957caedad6ec1b37f306e98
parentac7e2f13e999c1f24b58f7db868c7faeeb0a3c0e (diff)
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.
-rw-r--r--client.c64
-rw-r--r--cmd-load-buffer.c51
-rw-r--r--cmd-save-buffer.c3
-rw-r--r--server-client.c159
-rw-r--r--server-fn.c80
-rw-r--r--tmux.h41
6 files changed, 213 insertions, 185 deletions
diff --git a/client.c b/client.c
index 113083fd..4ebcf2ad 100644
--- a/client.c
+++ b/client.c
@@ -35,6 +35,7 @@
struct imsgbuf client_ibuf;
struct event client_event;
+struct event client_stdin;
enum {
CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED,
@@ -56,6 +57,7 @@ void client_send_environ(void);
void client_write_server(enum msgtype, void *, size_t);
void client_update_event(void);
void client_signal(int, short, void *);
+void client_stdin_callback(int, short, void *);
void client_callback(int, short, void *);
int client_dispatch_attached(void);
int client_dispatch_wait(void *);
@@ -227,6 +229,11 @@ client_main(int argc, char **argv, int flags)
imsg_init(&client_ibuf, fd);
event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
+ /* Create stdin handler. */
+ setblocking(STDIN_FILENO, 0);
+ event_set(&client_stdin, STDIN_FILENO, EV_READ|EV_PERSIST,
+ client_stdin_callback, NULL);
+
/* Establish signal handlers. */
set_signals(client_signal);
@@ -255,6 +262,7 @@ client_main(int argc, char **argv, int flags)
/* Set the event and dispatch. */
client_update_event();
+ event_add (&client_stdin, NULL);
event_dispatch();
/* Print the exit message, if any, and exit. */
@@ -266,6 +274,7 @@ client_main(int argc, char **argv, int flags)
if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP);
}
+ setblocking(STDIN_FILENO, 1);
return (client_exitval);
}
@@ -287,20 +296,11 @@ client_send_identify(int flags)
strlcpy(data.term, term, sizeof data.term) >= sizeof data.term)
*data.term = '\0';
- if ((fd = dup(STDOUT_FILENO)) == -1)
- fatal("dup failed");
- imsg_compose(&client_ibuf,
- MSG_STDOUT, PROTOCOL_VERSION, -1, fd, NULL, 0);
-
- if ((fd = dup(STDERR_FILENO)) == -1)
- fatal("dup failed");
- imsg_compose(&client_ibuf,
- MSG_STDERR, PROTOCOL_VERSION, -1, fd, NULL, 0);
-
if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed");
imsg_compose(&client_ibuf,
MSG_IDENTIFY, PROTOCOL_VERSION, -1, fd, &data, sizeof data);
+ client_update_event();
}
/* Forward entire environment to server. */
@@ -322,6 +322,7 @@ void
client_write_server(enum msgtype type, void *buf, size_t len)
{
imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, -1, buf, len);
+ client_update_event();
}
/* Update client event based on whether it needs to read or read and write. */
@@ -421,6 +422,23 @@ lost_server:
event_loopexit(NULL);
}
+/* Callback for client stdin read events. */
+/* ARGSUSED */
+void
+client_stdin_callback(unused int fd, unused short events, unused void *data1)
+{
+ struct msg_stdin_data data;
+
+ data.size = read(STDIN_FILENO, data.data, sizeof data.data);
+ if (data.size < 0 && (errno == EINTR || errno == EAGAIN))
+ return;
+
+ client_write_server(MSG_STDIN, &data, sizeof data);
+ if (data.size <= 0)
+ event_del(&client_stdin);
+ client_update_event();
+}
+
/* Dispatch imsgs when in wait state (before MSG_READY). */
int
client_dispatch_wait(void *data)
@@ -429,11 +447,10 @@ client_dispatch_wait(void *data)
ssize_t n, datalen;
struct msg_shell_data shelldata;
struct msg_exit_data exitdata;
+ struct msg_stdout_data stdoutdata;
+ struct msg_stderr_data stderrdata;
const char *shellcmd = data;
- if ((n = imsg_read(&client_ibuf)) == -1 || n == 0)
- fatalx("imsg_read failed");
-
for (;;) {
if ((n = imsg_get(&client_ibuf, &imsg)) == -1)
fatalx("imsg_get failed");
@@ -441,6 +458,7 @@ client_dispatch_wait(void *data)
return (0);
datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ log_debug("got %d from server", imsg.hdr.type);
switch (imsg.hdr.type) {
case MSG_EXIT:
case MSG_SHUTDOWN:
@@ -457,14 +475,30 @@ client_dispatch_wait(void *data)
if (datalen != 0)
fatalx("bad MSG_READY size");
+ event_del(&client_stdin);
client_attached = 1;
break;
+ case MSG_STDOUT:
+ if (datalen != sizeof stdoutdata)
+ fatalx("bad MSG_STDOUT");
+ memcpy(&stdoutdata, imsg.data, sizeof stdoutdata);
+
+ fwrite(stdoutdata.data, stdoutdata.size, 1, stdout);
+ break;
+ case MSG_STDERR:
+ if (datalen != sizeof stderrdata)
+ fatalx("bad MSG_STDERR");
+ memcpy(&stderrdata, imsg.data, sizeof stderrdata);
+
+ fwrite(stderrdata.data, stderrdata.size, 1, stderr);
+ break;
case MSG_VERSION:
if (datalen != 0)
fatalx("bad MSG_VERSION size");
- log_warnx("protocol version mismatch (client %u, "
- "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid);
+ fprintf(stderr, "protocol version mismatch "
+ "(client %u, server %u)\n", PROTOCOL_VERSION,
+ imsg.hdr.peerid);
client_exitval = 1;
imsg_free(&imsg);
diff --git a/cmd-load-buffer.c b/cmd-load-buffer.c
index 09fddbf7..1e6b6024 100644
--- a/cmd-load-buffer.c
+++ b/cmd-load-buffer.c
@@ -31,7 +31,7 @@
*/
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
-void cmd_load_buffer_callback(struct client *, void *);
+void cmd_load_buffer_callback(struct client *, int, void *);
const struct cmd_entry cmd_load_buffer_entry = {
"load-buffer", "loadb",
@@ -54,8 +54,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
char *pdata, *new_pdata, *cause;
size_t psize;
u_int limit;
- int ch, buffer;
- int *buffer_ptr;
+ int ch, error, buffer, *buffer_ptr;
if (!args_has(args, 'b'))
buffer = -1;
@@ -70,27 +69,16 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
path = args->argv[0];
if (strcmp(path, "-") == 0) {
- if (c == NULL) {
- ctx->error(ctx, "%s: can't read from stdin", path);
- return (-1);
- }
- if (c->flags & CLIENT_TERMINAL) {
- ctx->error(ctx, "%s: stdin is a tty", path);
- return (-1);
- }
- if (c->stdin_fd == -1) {
- ctx->error(ctx, "%s: can't read from stdin", path);
- return (-1);
- }
-
buffer_ptr = xmalloc(sizeof *buffer_ptr);
*buffer_ptr = buffer;
- c->stdin_data = buffer_ptr;
- c->stdin_callback = cmd_load_buffer_callback;
-
- c->references++;
- bufferevent_enable(c->stdin_event, EV_READ);
+ error = server_set_stdin_callback (c, cmd_load_buffer_callback,
+ buffer_ptr, &cause);
+ if (error != 0) {
+ ctx->error(ctx, "%s: %s", path, cause);
+ xfree(cause);
+ return (-1);
+ }
return (1);
}
@@ -154,35 +142,36 @@ error:
}
void
-cmd_load_buffer_callback(struct client *c, void *data)
+cmd_load_buffer_callback(struct client *c, int closed, void *data)
{
int *buffer = data;
char *pdata;
size_t psize;
u_int limit;
- /*
- * Event callback has already checked client is not dead and reduced
- * its reference count. But tell it to exit.
- */
+ if (!closed)
+ return;
+ c->stdin_callback = NULL;
+
+ c->references--;
c->flags |= CLIENT_EXIT;
- psize = EVBUFFER_LENGTH(c->stdin_event->input);
+ psize = EVBUFFER_LENGTH(c->stdin_data);
if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
xfree(data);
return;
}
- bufferevent_read(c->stdin_event, pdata, psize);
+ memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize);
pdata[psize] = '\0';
+ evbuffer_drain(c->stdin_data, psize);
limit = options_get_number(&global_options, "buffer-limit");
if (*buffer == -1)
paste_add(&global_buffers, pdata, psize, limit);
else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
/* No context so can't use server_client_msg_error. */
- evbuffer_add_printf(
- c->stderr_event->output, "no buffer %d\n", *buffer);
- bufferevent_enable(c->stderr_event, EV_WRITE);
+ evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer);
+ server_push_stderr(c);
}
xfree(data);
diff --git a/cmd-save-buffer.c b/cmd-save-buffer.c
index 93ec4b0b..80f9d572 100644
--- a/cmd-save-buffer.c
+++ b/cmd-save-buffer.c
@@ -79,7 +79,8 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->error(ctx, "%s: can't write to stdout", path);
return (-1);
}
- bufferevent_write(c->stdout_event, pb->data, pb->size);
+ evbuffer_add(c->stdout_data, pb->data, pb->size);
+ server_push_stdout(c);
} else {
if (c != NULL)
wd = c->cwd;
diff --git a/server-client.c b/server-client.c
index 2cbb5bf3..25f17f06 100644
--- a/server-client.c
+++ b/server-client.c
@@ -35,9 +35,6 @@ void server_client_check_exit(struct client *);
void server_client_check_redraw(struct client *);
void server_client_set_title(struct client *);
void server_client_reset_state(struct client *);
-void server_client_in_callback(struct bufferevent *, short, void *);
-void server_client_out_callback(struct bufferevent *, short, void *);
-void server_client_err_callback(struct bufferevent *, short, void *);
int server_client_msg_dispatch(struct client *);
void server_client_msg_command(struct client *, struct msg_command_data *);
@@ -67,9 +64,9 @@ server_client_create(int fd)
fatal("gettimeofday failed");
memcpy(&c->activity_time, &c->creation_time, sizeof c->activity_time);
- c->stdin_event = NULL;
- c->stdout_event = NULL;
- c->stderr_event = NULL;
+ c->stdin_data = evbuffer_new ();
+ c->stdout_data = evbuffer_new ();
+ c->stderr_data = evbuffer_new ();
c->tty.fd = -1;
c->title = NULL;
@@ -144,24 +141,9 @@ server_client_lost(struct client *c)
if (c->flags & CLIENT_TERMINAL)
tty_free(&c->tty);
- if (c->stdin_event != NULL)
- bufferevent_free(c->stdin_event);
- if (c->stdin_fd != -1) {
- setblocking(c->stdin_fd, 1);
- close(c->stdin_fd);
- }
- if (c->stdout_event != NULL)
- bufferevent_free(c->stdout_event);
- if (c->stdout_fd != -1) {
- setblocking(c->stdout_fd, 1);
- close(c->stdout_fd);
- }
- if (c->stderr_event != NULL)
- bufferevent_free(c->stderr_event);
- if (c->stderr_fd != -1) {
- setblocking(c->stderr_fd, 1);
- close(c->stderr_fd);
- }
+ evbuffer_free (c->stdin_data);
+ evbuffer_free (c->stdout_data);
+ evbuffer_free (c->stderr_data);
status_free_jobs(&c->status_new);
status_free_jobs(&c->status_old);
@@ -240,6 +222,9 @@ server_client_callback(int fd, short events, void *data)
goto client_lost;
}
+ server_push_stdout(c);
+ server_push_stderr(c);
+
server_update_event(c);
return;
@@ -603,11 +588,11 @@ server_client_check_exit(struct client *c)
if (!(c->flags & CLIENT_EXIT))
return;
- if (c->stdout_fd != -1 && c->stdout_event != NULL &&
- EVBUFFER_LENGTH(c->stdout_event->output) != 0)
+ if (EVBUFFER_LENGTH(c->stdin_data) != 0)
+ return;
+ if (EVBUFFER_LENGTH(c->stdout_data) != 0)
return;
- if (c->stderr_fd != -1 && c->stderr_event != NULL &&
- EVBUFFER_LENGTH(c->stderr_event->output) != 0)
+ if (EVBUFFER_LENGTH(c->stderr_data) != 0)
return;
exitdata.retcode = c->retcode;
@@ -686,55 +671,6 @@ server_client_set_title(struct client *c)
xfree(title);
}
-/*
- * Error callback for client stdin. Caller must increase reference count when
- * enabling event!
- */
-void
-server_client_in_callback(
- unused struct bufferevent *bufev, unused short what, void *data)
-{
- struct client *c = data;
-
- c->references--;
- if (c->flags & CLIENT_DEAD)
- return;
-
- bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE);
- setblocking(c->stdin_fd, 1);
- close(c->stdin_fd);
- c->stdin_fd = -1;
-
- if (c->stdin_callback != NULL)
- c->stdin_callback(c, c->stdin_data);
-}
-
-/* Error callback for client stdout. */
-void
-server_client_out_callback(
- unused struct bufferevent *bufev, unused short what, unused void *data)
-{
- struct client *c = data;
-
- bufferevent_disable(c->stdout_event, EV_READ|EV_WRITE);
- setblocking(c->stdout_fd, 1);
- close(c->stdout_fd);
- c->stdout_fd = -1;
-}
-
-/* Error callback for client stderr. */
-void
-server_client_err_callback(
- unused struct bufferevent *bufev, unused short what, unused void *data)
-{
- struct client *c = data;
-
- bufferevent_disable(c->stderr_event, EV_READ|EV_WRITE);
- setblocking(c->stderr_fd, 1);
- close(c->stderr_fd);
- c->stderr_fd = -1;
-}
-
/* Dispatch message from client. */
int
server_client_msg_dispatch(struct client *c)
@@ -743,6 +679,7 @@ server_client_msg_dispatch(struct client *c)
struct msg_command_data commanddata;
struct msg_identify_data identifydata;
struct msg_environ_data environdata;
+ struct msg_stdin_data stdindata;
ssize_t n, datalen;
if ((n = imsg_read(&c->ibuf)) == -1 || n == 0)
@@ -778,42 +715,23 @@ server_client_msg_dispatch(struct client *c)
fatalx("MSG_IDENTIFY missing fd");
memcpy(&identifydata, imsg.data, sizeof identifydata);
- c->stdin_fd = imsg.fd;
- c->stdin_event = bufferevent_new(c->stdin_fd,
- NULL, NULL, server_client_in_callback, c);
- if (c->stdin_event == NULL)
- fatalx("failed to create stdin event");
- setblocking(c->stdin_fd, 0);
-
server_client_msg_identify(c, &identifydata, imsg.fd);
break;
- case MSG_STDOUT:
- if (datalen != 0)
- fatalx("bad MSG_STDOUT size");
- if (imsg.fd == -1)
- fatalx("MSG_STDOUT missing fd");
-
- c->stdout_fd = imsg.fd;
- c->stdout_event = bufferevent_new(c->stdout_fd,
- NULL, NULL, server_client_out_callback, c);
- if (c->stdout_event == NULL)
- fatalx("failed to create stdout event");
- setblocking(c->stdout_fd, 0);
-
- break;
- case MSG_STDERR:
- if (datalen != 0)
- fatalx("bad MSG_STDERR size");
- if (imsg.fd == -1)
- fatalx("MSG_STDERR missing fd");
-
- c->stderr_fd = imsg.fd;
- c->stderr_event = bufferevent_new(c->stderr_fd,
- NULL, NULL, server_client_err_callback, c);
- if (c->stderr_event == NULL)
- fatalx("failed to create stderr event");
- setblocking(c->stderr_fd, 0);
+ case MSG_STDIN:
+ if (datalen != sizeof stdindata)
+ fatalx("bad MSG_STDIN size");
+ memcpy(&stdindata, imsg.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)
@@ -880,10 +798,11 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stderr_event->output, fmt, ap);
+ evbuffer_add_vprintf(ctx->cmdclient->stderr_data, fmt, ap);
va_end(ap);
- bufferevent_write(ctx->cmdclient->stderr_event, "\n", 1);
+ evbuffer_add(ctx->cmdclient->stderr_data, "\n", 1);
+ server_push_stderr(ctx->cmdclient);
ctx->cmdclient->retcode = 1;
}
@@ -894,10 +813,11 @@ server_client_msg_print(struct cmd_ctx *ctx, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
+ evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
va_end(ap);
- bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
+ evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
+ server_push_stdout(ctx->cmdclient);
}
/* Callback to send print message to client, if not quiet. */
@@ -910,10 +830,11 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
return;
va_start(ap, fmt);
- evbuffer_add_vprintf(ctx->cmdclient->stdout_event->output, fmt, ap);
+ evbuffer_add_vprintf(ctx->cmdclient->stdout_data, fmt, ap);
va_end(ap);
- bufferevent_write(ctx->cmdclient->stdout_event, "\n", 1);
+ evbuffer_add(ctx->cmdclient->stdout_data, "\n", 1);
+ server_push_stdout(ctx->cmdclient);
}
/* Handle command message. */
@@ -970,8 +891,6 @@ void
server_client_msg_identify(
struct client *c, struct msg_identify_data *data, int fd)
{
- int tty_fd;
-
c->cwd = NULL;
data->cwd[(sizeof data->cwd) - 1] = '\0';
if (*data->cwd != '\0')
@@ -979,10 +898,8 @@ server_client_msg_identify(
if (!isatty(fd))
return;
- if ((tty_fd = dup(fd)) == -1)
- fatal("dup failed");
data->term[(sizeof data->term) - 1] = '\0';
- tty_init(&c->tty, tty_fd, data->term);
+ tty_init(&c->tty, fd, data->term);
if (data->flags & IDENTIFY_UTF8)
c->tty.flags |= TTY_UTF8;
if (data->flags & IDENTIFY_256COLOURS)
diff --git a/server-fn.c b/server-fn.c
index 600955af..791aab1c 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);
+}
diff --git a/tmux.h b/tmux.h
index 8c66bca5..96efb661 100644
--- a/tmux.h
+++ b/tmux.h
@@ -19,7 +19,7 @@
#ifndef TMUX_H
#define TMUX_H
-#define PROTOCOL_VERSION 6
+#define PROTOCOL_VERSION 7
#include <sys/param.h>
#include <sys/time.h>
@@ -369,7 +369,7 @@ enum msgtype {
MSG_EXITED,
MSG_EXITING,
MSG_IDENTIFY,
- MSG_PRINT,
+ MSG_STDIN,
MSG_READY,
MSG_RESIZE,
MSG_SHUTDOWN,
@@ -425,6 +425,21 @@ struct msg_exit_data {
int retcode;
};
+struct msg_stdin_data {
+ ssize_t size;
+ char data[BUFSIZ];
+};
+
+struct msg_stdout_data {
+ ssize_t size;
+ char data[BUFSIZ];
+};
+
+struct msg_stderr_data {
+ ssize_t size;
+ char data[BUFSIZ];
+};
+
/* Mode key commands. */
enum mode_key_cmd {
MODEKEY_NONE,
@@ -1161,16 +1176,12 @@ struct client {
struct tty tty;
- int stdin_fd;
- void *stdin_data;
- void (*stdin_callback)(struct client *, void *);
- struct bufferevent *stdin_event;
-
- int stdout_fd;
- struct bufferevent *stdout_event;
-
- int stderr_fd;
- struct bufferevent *stderr_event;
+ void (*stdin_callback)(struct client *, int, void *);
+ void *stdin_callback_data;
+ struct evbuffer *stdin_data;
+ int stdin_closed;
+ struct evbuffer *stdout_data;
+ struct evbuffer *stderr_data;
struct event repeat_timer;
@@ -1734,7 +1745,7 @@ void server_window_loop(void);
/* server-fn.c */
void server_fill_environ(struct session *, struct environ *);
-void server_write_client(
+int server_write_client(
struct client *, enum msgtype, const void *, size_t);
void server_write_session(
struct session *, enum msgtype, const void *, size_t);
@@ -1762,6 +1773,10 @@ void server_check_unattached (void);
void server_set_identify(struct client *);
void server_clear_identify(struct client *);
void server_update_event(struct client *);
+void server_push_stdout(struct client *);
+void server_push_stderr(struct client *);
+int server_set_stdin_callback(struct client *, void (*)(struct client *,
+ int, void *), void *, char **);
/* status.c */
int status_out_cmp(struct status_out *, struct status_out *);