1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Server prep: support stderr output on channels.

The vtable method underneath sshfwd_write now takes an is_stderr
parameter, and in SSH-2, this is implemented by having separate stdout
and stderr bufchains in each outgoing channel, and counting the size
of both for the purposes of measuring backlog and so forth.

To avoid making _most_ call sites more verbose, the usual macro
wrapper hasn't changed its API; it just sets is_stderr=FALSE. To use
the new feature, there's an sshfwd_write_ext macro that exposes the
extra parameter.
This commit is contained in:
Simon Tatham 2018-10-20 21:41:28 +01:00
parent 61976b417e
commit 445030b3ea
5 changed files with 40 additions and 17 deletions

View File

@ -397,7 +397,8 @@ static void ssh1mainchan_hint_channel_is_simple(SshChannel *sc)
{
}
static int ssh1mainchan_write(SshChannel *sc, const void *data, int len)
static int ssh1mainchan_write(
SshChannel *sc, int is_stderr, const void *data, int len)
{
struct ssh1_connection_state *s =
container_of(sc, struct ssh1_connection_state, mainchan_sc);

View File

@ -89,7 +89,8 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = {
ssh1_set_wants_user_input,
};
static int ssh1channel_write(SshChannel *c, const void *buf, int len);
static int ssh1channel_write(
SshChannel *c, int is_stderr, const void *buf, int len);
static void ssh1channel_write_eof(SshChannel *c);
static void ssh1channel_initiate_close(SshChannel *c, const char *err);
static void ssh1channel_unthrottle(SshChannel *c, int bufsize);
@ -581,7 +582,8 @@ static void ssh1channel_unthrottle(SshChannel *sc, int bufsize)
}
}
static int ssh1channel_write(SshChannel *sc, const void *buf, int len)
static int ssh1channel_write(
SshChannel *sc, int is_stderr, const void *buf, int len)
{
struct ssh1_channel *c = container_of(sc, struct ssh1_channel, sc);
struct ssh1_connection_state *s = c->connlayer;

View File

@ -116,7 +116,8 @@ static char *ssh2_channel_open_failure_error_text(PktIn *pktin)
return dupprintf("%s [%.*s]", reason_code_string, PTRLEN_PRINTF(reason));
}
static int ssh2channel_write(SshChannel *c, const void *buf, int len);
static int ssh2channel_write(
SshChannel *c, int is_stderr, const void *buf, int len);
static void ssh2channel_write_eof(SshChannel *c);
static void ssh2channel_initiate_close(SshChannel *c, const char *err);
static void ssh2channel_unthrottle(SshChannel *c, int bufsize);
@ -215,6 +216,7 @@ struct outstanding_channel_request {
static void ssh2_channel_free(struct ssh2_channel *c)
{
bufchain_clear(&c->outbuffer);
bufchain_clear(&c->errbuffer);
while (c->chanreq_head) {
struct outstanding_channel_request *chanreq = c->chanreq_head;
c->chanreq_head = c->chanreq_head->next;
@ -741,6 +743,7 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s)
* stuff.
*/
bufchain_clear(&c->outbuffer);
bufchain_clear(&c->errbuffer);
/*
* Send outgoing EOF.
@ -980,7 +983,7 @@ static void ssh2_channel_try_eof(struct ssh2_channel *c)
assert(c->pending_eof); /* precondition for calling us */
if (c->halfopen)
return; /* can't close: not even opened yet */
if (bufchain_size(&c->outbuffer) > 0)
if (bufchain_size(&c->outbuffer) > 0 || bufchain_size(&c->errbuffer) > 0)
return; /* can't send EOF: pending outgoing data */
c->pending_eof = FALSE; /* we're about to send it */
@ -1001,19 +1004,31 @@ static int ssh2_try_send(struct ssh2_channel *c)
PktOut *pktout;
int bufsize;
while (c->remwindow > 0 && bufchain_size(&c->outbuffer) > 0) {
while (c->remwindow > 0 &&
(bufchain_size(&c->outbuffer) > 0 ||
bufchain_size(&c->errbuffer) > 0)) {
int len;
void *data;
bufchain_prefix(&c->outbuffer, &data, &len);
bufchain *buf = (bufchain_size(&c->errbuffer) > 0 ?
&c->errbuffer : &c->outbuffer);
bufchain_prefix(buf, &data, &len);
if ((unsigned)len > c->remwindow)
len = c->remwindow;
if ((unsigned)len > c->remmaxpkt)
len = c->remmaxpkt;
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA);
put_uint32(pktout, c->remoteid);
if (buf == &c->errbuffer) {
pktout = ssh_bpp_new_pktout(
s->ppl.bpp, SSH2_MSG_CHANNEL_EXTENDED_DATA);
put_uint32(pktout, c->remoteid);
put_uint32(pktout, SSH2_EXTENDED_DATA_STDERR);
} else {
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_CHANNEL_DATA);
put_uint32(pktout, c->remoteid);
}
put_string(pktout, data, len);
pq_push(s->ppl.out_pq, pktout);
bufchain_consume(&c->outbuffer, len);
bufchain_consume(buf, len);
c->remwindow -= len;
}
@ -1021,7 +1036,7 @@ static int ssh2_try_send(struct ssh2_channel *c)
* After having sent as much data as we can, return the amount
* still buffered.
*/
bufsize = bufchain_size(&c->outbuffer);
bufsize = bufchain_size(&c->outbuffer) + bufchain_size(&c->errbuffer);
/*
* And if there's no data pending but we need to send an EOF, send
@ -1155,6 +1170,7 @@ void ssh2_channel_init(struct ssh2_channel *c)
c->chanreq_head = NULL;
c->throttle_state = UNTHROTTLED;
bufchain_init(&c->outbuffer);
bufchain_init(&c->errbuffer);
c->sc.vt = &ssh2channel_vtable;
c->sc.cl = &s->cl;
c->localid = alloc_channel_id(s->channels, struct ssh2_channel);
@ -1264,11 +1280,12 @@ static void ssh2channel_unthrottle(SshChannel *sc, int bufsize)
}
}
static int ssh2channel_write(SshChannel *sc, const void *buf, int len)
static int ssh2channel_write(
SshChannel *sc, int is_stderr, const void *buf, int len)
{
struct ssh2_channel *c = container_of(sc, struct ssh2_channel, sc);
assert(!(c->closes & CLOSES_SENT_EOF));
bufchain_add(&c->outbuffer, buf, len);
bufchain_add(is_stderr ? &c->errbuffer : &c->outbuffer, buf, len);
return ssh2_try_send(c);
}
@ -1521,7 +1538,8 @@ static int ssh2_stdin_backlog(ConnectionLayer *cl)
if (!s->mainchan)
return 0;
c = container_of(s->mainchan_sc, struct ssh2_channel, sc);
return s->mainchan ? bufchain_size(&c->outbuffer) : 0;
return s->mainchan ?
bufchain_size(&c->outbuffer) + bufchain_size(&c->errbuffer) : 0;
}
static void ssh2_throttle_all_channels(ConnectionLayer *cl, int throttled)

View File

@ -94,7 +94,7 @@ struct ssh2_channel {
*/
int throttled_by_backlog;
bufchain outbuffer;
bufchain outbuffer, errbuffer;
unsigned remwindow, remmaxpkt;
/* locwindow is signed so we can cope with excess data. */
int locwindow, locmaxwin;

View File

@ -104,7 +104,7 @@ Channel *zombiechan_new(void);
*/
struct SshChannelVtable {
int (*write)(SshChannel *c, const void *, int);
int (*write)(SshChannel *c, int is_stderr, const void *, int);
void (*write_eof)(SshChannel *c);
void (*initiate_close)(SshChannel *c, const char *err);
void (*unthrottle)(SshChannel *c, int bufsize);
@ -160,7 +160,9 @@ struct SshChannel {
ConnectionLayer *cl;
};
#define sshfwd_write(c, buf, len) ((c)->vt->write(c, buf, len))
#define sshfwd_write(c, buf, len) ((c)->vt->write(c, FALSE, buf, len))
#define sshfwd_write_ext(c, stderr, buf, len) \
((c)->vt->write(c, stderr, buf, len))
#define sshfwd_write_eof(c) ((c)->vt->write_eof(c))
#define sshfwd_initiate_close(c, err) ((c)->vt->initiate_close(c, err))
#define sshfwd_unthrottle(c, bufsize) ((c)->vt->unthrottle(c, bufsize))