possible clue on tcp forwarding problems
Markus Friedl
markus.friedl at informatik.uni-erlangen.de
Fri Jan 7 23:35:12 EST 2000
hi, this should fix the lockup during tcp-fwding and
other channel-related bugs. -markus
-------------- next part --------------
Index: channels.c
===================================================================
RCS file: /home/markus/cvs/ssh/channels.c,v
retrieving revision 1.36
diff -u -r1.36 channels.c
--- channels.c 2000/01/04 07:52:03 1.36
+++ channels.c 2000/01/07 12:29:22
@@ -533,10 +533,19 @@
for (i = 0; i < channels_alloc; i++) {
ch = &channels[i];
+
/* We are only interested in channels that can have buffered incoming data. */
- if (ch->type != SSH_CHANNEL_OPEN &&
- ch->type != SSH_CHANNEL_INPUT_DRAINING)
- continue;
+ if (compat13) {
+ if (ch->type != SSH_CHANNEL_OPEN &&
+ ch->type != SSH_CHANNEL_INPUT_DRAINING)
+ continue;
+ } else {
+ if (ch->type != SSH_CHANNEL_OPEN)
+ continue;
+ if (ch->istate != CHAN_INPUT_OPEN &&
+ ch->istate != CHAN_INPUT_WAIT_DRAIN)
+ continue;
+ }
/* Get the amount of buffered data for this channel. */
len = buffer_len(&ch->input);
@@ -576,25 +585,33 @@
void
channel_input_data(int payload_len)
{
- int channel;
+ int id;
char *data;
unsigned int data_len;
+ Channel *ch;
/* Get the channel number and verify it. */
- channel = packet_get_int();
- if (channel < 0 || channel >= channels_alloc ||
- channels[channel].type == SSH_CHANNEL_FREE)
- packet_disconnect("Received data for nonexistent channel %d.", channel);
+ id = packet_get_int();
+ if (id < 0 || id >= channels_alloc)
+ packet_disconnect("Received data for nonexistent channel %d.", id);
+ ch = &channels[id];
+ if (ch->type == SSH_CHANNEL_FREE)
+ packet_disconnect("Received data for free channel %d.", ch->self);
+
/* Ignore any data for non-open channels (might happen on close) */
- if (channels[channel].type != SSH_CHANNEL_OPEN &&
- channels[channel].type != SSH_CHANNEL_X11_OPEN)
+ if (ch->type != SSH_CHANNEL_OPEN &&
+ ch->type != SSH_CHANNEL_X11_OPEN)
+ return;
+
+ /* same for protocol 1.5 if output end is no longer open */
+ if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN)
return;
/* Get the data. */
data = packet_get_string(&data_len);
packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA);
- buffer_append(&channels[channel].output, data, data_len);
+ buffer_append(&ch->output, data, data_len);
xfree(data);
}
@@ -611,23 +628,11 @@
for (i = 0; i < channels_alloc; i++) {
ch = &channels[i];
- switch (ch->type) {
- case SSH_CHANNEL_X11_LISTENER:
- case SSH_CHANNEL_PORT_LISTENER:
- case SSH_CHANNEL_AUTH_SOCKET:
- continue;
- case SSH_CHANNEL_OPEN:
+ if (ch->type == SSH_CHANNEL_OPEN) {
if (buffer_len(&ch->input) > packet_get_maxsize())
return 0;
if (buffer_len(&ch->output) > packet_get_maxsize())
return 0;
- continue;
- case SSH_CHANNEL_INPUT_DRAINING:
- case SSH_CHANNEL_OUTPUT_DRAINING:
- case SSH_CHANNEL_X11_OPEN:
- case SSH_CHANNEL_FREE:
- default:
- continue;
}
}
return 1;
@@ -854,9 +859,11 @@
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING:
- snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n",
- c->self, c->remote_name,
- c->type, c->remote_id, c->istate, c->ostate);
+ snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n",
+ c->self, c->remote_name,
+ c->type, c->remote_id,
+ c->istate, buffer_len(&c->input),
+ c->ostate, buffer_len(&c->output));
buffer_append(&buffer, buf, strlen(buf));
continue;
default:
Index: nchan.c
===================================================================
RCS file: /home/markus/cvs/ssh/nchan.c,v
retrieving revision 1.9
diff -u -r1.9 nchan.c
--- nchan.c 1999/12/02 20:10:05 1.9
+++ nchan.c 2000/01/07 12:30:37
@@ -41,7 +41,7 @@
static void chan_send_oclose(Channel *c);
static void chan_shutdown_write(Channel *c);
static void chan_shutdown_read(Channel *c);
-static void chan_delele_if_full_closed(Channel *c);
+static void chan_delete_if_full_closed(Channel *c);
/*
* EVENTS update channel input/output states execute ACTIONS
@@ -55,19 +55,25 @@
case CHAN_INPUT_WAIT_OCLOSE:
debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
c->istate = CHAN_INPUT_CLOSED;
- chan_delele_if_full_closed(c);
break;
case CHAN_INPUT_OPEN:
debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
chan_shutdown_read(c);
chan_send_ieof(c);
c->istate = CHAN_INPUT_CLOSED;
- chan_delele_if_full_closed(c);
break;
+ case CHAN_INPUT_WAIT_DRAIN:
+ /* both local read_failed and remote write_failed */
+ log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
+ debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
+ chan_send_ieof(c);
+ c->istate = CHAN_INPUT_CLOSED;
+ break;
default:
error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
- break;
+ return;
}
+ chan_delete_if_full_closed(c);
}
void
chan_read_failed(Channel *c)
@@ -115,7 +121,7 @@
case CHAN_OUTPUT_WAIT_IEOF:
debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
c->ostate = CHAN_OUTPUT_CLOSED;
- chan_delele_if_full_closed(c);
+ chan_delete_if_full_closed(c);
break;
default:
error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
@@ -135,7 +141,7 @@
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
chan_send_oclose(c);
c->ostate = CHAN_OUTPUT_CLOSED;
- chan_delele_if_full_closed(c);
+ chan_delete_if_full_closed(c);
break;
default:
error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
@@ -154,7 +160,7 @@
debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
chan_send_oclose(c);
c->ostate = CHAN_OUTPUT_CLOSED;
- chan_delele_if_full_closed(c);
+ chan_delete_if_full_closed(c);
break;
default:
error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
@@ -213,14 +219,14 @@
{
debug("channel %d: shutdown_read", c->self);
if (shutdown(c->sock, SHUT_RD) < 0)
- error("chan_shutdown_read failed for #%d/fd%d: %.100s",
- c->self, c->sock, strerror(errno));
+ error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
+ c->self, c->sock, c->istate, c->ostate, strerror(errno));
}
static void
-chan_delele_if_full_closed(Channel *c)
+chan_delete_if_full_closed(Channel *c)
{
if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
- debug("channel %d: closing", c->self);
+ debug("channel %d: full closed", c->self);
channel_free(c->self);
}
}
More information about the openssh-unix-dev
mailing list