- Merged OpenBSD IPv6 patch:
   - [sshd.c sshd.8 sshconnect.c ssh.h ssh.c servconf.h servconf.c scp.1]
     [scp.c packet.h packet.c login.c log.c canohost.c channels.c]
     [hostfile.c sshd_config]
     ipv6 support: mostly gethostbyname->getaddrinfo/getnameinfo, new
     features: sshd allows multiple ListenAddress and Port options. note
     that libwrap is not IPv6-ready. (based on patches from
     fujiwara@rcac.tdi.co.jp)
   - [ssh.c canohost.c]
     more hints (hints.ai_socktype=SOCK_STREAM) for getaddrinfo,
     from itojun@
   - [channels.c]
     listen on _all_ interfaces for X11-Fwd (hints.ai_flags = AI_PASSIVE)
   - [packet.h]
     allow auth-kerberos for IPv4 only
   - [scp.1 sshd.8 servconf.h scp.c]
     document -4, -6, and 'ssh -L 2022/::1/22'
   - [ssh.c]
     'ssh @host' is illegal (null user name), from
     karsten@gedankenpolizei.de
   - [sshconnect.c]
     better error message
   - [sshd.c]
     allow auth-kerberos for IPv4 only
 - Big IPv6 merge:
   - Cleanup overrun in sockaddr copying on RHL 6.1
   - Replacements for getaddrinfo, getnameinfo, etc based on versions
     from patch from KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
   - Replacement for missing structures on systems that lack IPv6
   - record_login needed to know about AF_INET6 addresses
   - Borrowed more code from OpenBSD: rresvport_af and requisites
diff --git a/nchan.c b/nchan.c
index 23d180c..0c8066f 100644
--- a/nchan.c
+++ b/nchan.c
@@ -28,7 +28,7 @@
  */
 
 #include "includes.h"
-RCSID("$Id: nchan.c,v 1.4 1999/12/06 00:47:29 damien Exp $");
+RCSID("$Id: nchan.c,v 1.5 2000/01/14 04:45:50 damien Exp $");
 
 #include "ssh.h"
 
@@ -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);
 	}
 }