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