- reyk@cvs.openbsd.org 2005/12/30 15:56:37
     [channels.c channels.h clientloop.c]
     add channel output filter interface.
     ok djm@, suggested by markus@
diff --git a/channels.c b/channels.c
index b431532..ed5903f 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.230 2005/12/28 22:46:06 stevesk Exp $");
+RCSID("$OpenBSD: channels.c,v 1.231 2005/12/30 15:56:36 reyk Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -58,8 +58,6 @@
 
 /* -- channel core */
 
-#define CHAN_RBUF	16*1024
-
 /*
  * Pointer to an array containing all allocated channels.  The array is
  * dynamically extended as needed.
@@ -301,6 +299,7 @@
 	c->confirm = NULL;
 	c->confirm_ctx = NULL;
 	c->input_filter = NULL;
+	c->output_filter = NULL;
 	debug("channel %d: new [%s]", found, remote_name);
 	return c;
 }
@@ -681,7 +680,8 @@
 	c->detach_close = 0;
 }
 void
-channel_register_filter(int id, channel_filter_fn *fn)
+channel_register_filter(int id, channel_infilter_fn *ifn,
+    channel_outfilter_fn *ofn)
 {
 	Channel *c = channel_lookup(id);
 
@@ -689,7 +689,8 @@
 		logit("channel_register_filter: %d: bad id", id);
 		return;
 	}
-	c->input_filter = fn;
+	c->input_filter = ifn;
+	c->output_filter = ofn;
 }
 
 void
@@ -1454,7 +1455,7 @@
 channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
 {
 	struct termios tio;
-	u_char *data;
+	u_char *data = NULL, *buf;
 	u_int dlen;
 	int len;
 
@@ -1462,11 +1463,22 @@
 	if (c->wfd != -1 &&
 	    FD_ISSET(c->wfd, writeset) &&
 	    buffer_len(&c->output) > 0) {
+		if (c->output_filter != NULL) {
+			if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
+				debug2("channel %d: filter stops", c->self);
+				chan_read_failed(c);
+			}
+		} else if (c->datagram) {
+			buf = data = buffer_get_string(&c->output, &dlen);
+		} else {
+			buf = data = buffer_ptr(&c->output);
+			dlen = buffer_len(&c->output);
+		}
+
 		if (c->datagram) {
-			data = buffer_get_string(&c->output, &dlen);
 			/* ignore truncated writes, datagrams might get lost */
 			c->local_consumed += dlen + 4;
-			len = write(c->wfd, data, dlen);
+			len = write(c->wfd, buf, dlen);
 			xfree(data);
 			if (len < 0 && (errno == EINTR || errno == EAGAIN))
 				return 1;
@@ -1486,7 +1498,8 @@
 		if (compat20 && c->wfd_isatty)
 			dlen = MIN(dlen, 8*1024);
 #endif
-		len = write(c->wfd, data, dlen);
+
+		len = write(c->wfd, buf, dlen);
 		if (len < 0 && (errno == EINTR || errno == EAGAIN))
 			return 1;
 		if (len <= 0) {
@@ -1503,14 +1516,14 @@
 			}
 			return -1;
 		}
-		if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {
+		if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
 			if (tcgetattr(c->wfd, &tio) == 0 &&
 			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
 				/*
 				 * Simulate echo to reduce the impact of
 				 * traffic analysis. We need to match the
 				 * size of a SSH2_MSG_CHANNEL_DATA message
-				 * (4 byte channel id + data)
+				 * (4 byte channel id + buf)
 				 */
 				packet_send_ignore(4 + len);
 				packet_send();