The Linux implementation of TCP sockets has a bug which causes shutdown(sock, SHUT_RD) to fail spuriously (ENOTCONN) if the write side of the socket has already been shut down. If you are using SSH port forwarding to tunnel HTTP through a firewall, nchan.c will tickle this bug once for every HTTP exchange. You will therefore get lots of useless, annoying error messages: channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected Here's a complete debugging trace of one such forwarded channel. This is SSH1 protocol; I haven't got the setup to do SSH2 yet. The remote server is 2.0.12 F-SECURE SSH on Solaris 2.6; I am using openssh 2.1.1p4 with kernel 2.2.16. debug: channel 2: new [listen port 3128 for webcache.example.com port 3128, connect from localhost port 1817] debug: channel 2: rcvd ieof debug: channel 2: output open -> drain debug: channel 2: obuf empty debug: channel 2: output drain -> closed debug: channel 2: send oclose debug: channel 2: close_write debug: channel 2: read<=0 rfd 7 len 0 debug: channel 2: read failed debug: channel 2: input open -> drain debug: channel 2: close_read channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected debug: channel 2: input: no drain shortcut debug: channel 2: ibuf empty debug: channel 2: input drain -> wait_oclose debug: channel 2: send ieof debug: channel 2: rcvd oclose debug: channel 2: input wait_oclose -> closed debug: channel 2: full closed I'd appreciate it if the appended patch could be applied. It causes ssh to recognize the bug and not emit the error message. [I've reported the bug to the kernel developers but they do not seem interested in fixing it.] zw --- openssh-2.1.1p4.orig/nchan.c Thu Jun 22 04:32:31 2000 +++ openssh-2.1.1p4/nchan.c Sun Jul 23 09:42:23 2000 @@ -483,7 +483,12 @@ return; debug("channel %d: close_read", c->self); if (c->sock != -1) { - if (shutdown(c->sock, SHUT_RD) < 0) + /* shutdown(sock, SHUT_READ) may return ENOTCONN if the + write side has been closed already. */ + if (shutdown(c->sock, SHUT_RD) < 0 + && (errno != ENOTCONN + || c->ostate == CHAN_OUTPUT_OPEN + || c->ostate == CHAN_OUTPUT_WAIT_DRAIN)) error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s", c->self, c->sock, c->istate, c->ostate, strerror(errno)); } else {
On Sun, 23 Jul 2000, Zack Weinberg wrote:> The Linux implementation of TCP sockets has a bug which causes > shutdown(sock, SHUT_RD) to fail spuriously (ENOTCONN) if the write > side of the socket has already been shut down. If you are using SSH > port forwarding to tunnel HTTP through a firewall, nchan.c will tickle > this bug once for every HTTP exchange. You will therefore get lots of > useless, annoying error messages:[snip]> I'd appreciate it if the appended patch could be applied. It causes > ssh to recognize the bug and not emit the error message.Applied - thanks.> [I've reported the bug to the kernel developers but they do not seem > interested in fixing it.]Can you give me a pointer to some discussion on this? -d -- | "Bombay is 250ms from New York in the new world order" - Alan Cox | Damien Miller - http://www.mindrot.org/ | Email: djm at mindrot.org (home) -or- djm at ibs.com.au (work)
hp-ux 10.20 and 11 seem to have a similar issue in that shutdown(sock, SHUT_RD) return EINVAL when the write side has been previously closed. you can dup this with: ssh -R 2300:bar:23 foo telnet 0 2300 Dec 22 22:04:18 jenny sshd[21722]: error: channel 1: chan_shutdown_read: shutdown() failed for fd13 [i1 o128]: Invalid argument regarding the patch below, why do we test for this: + || c->ostate == CHAN_OUTPUT_OPEN + || c->ostate == CHAN_OUTPUT_WAIT_DRAIN)) vs. just checking for ENOTCONN? On Sun, 23 Jul 2000, Zack Weinberg wrote: : The Linux implementation of TCP sockets has a bug which causes : shutdown(sock, SHUT_RD) to fail spuriously (ENOTCONN) if the write : side of the socket has already been shut down. If you are using SSH : port forwarding to tunnel HTTP through a firewall, nchan.c will tickle : this bug once for every HTTP exchange. You will therefore get lots of : useless, annoying error messages: : : channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected : : Here's a complete debugging trace of one such forwarded channel. This : is SSH1 protocol; I haven't got the setup to do SSH2 yet. The remote : server is 2.0.12 F-SECURE SSH on Solaris 2.6; I am using openssh : 2.1.1p4 with kernel 2.2.16. : : debug: channel 2: new [listen port 3128 for webcache.example.com port 3128, connect from localhost port 1817] : debug: channel 2: rcvd ieof : debug: channel 2: output open -> drain : debug: channel 2: obuf empty : debug: channel 2: output drain -> closed : debug: channel 2: send oclose : debug: channel 2: close_write : debug: channel 2: read<=0 rfd 7 len 0 : debug: channel 2: read failed : debug: channel 2: input open -> drain : debug: channel 2: close_read : channel 2: chan_shutdown_read: shutdown() failed for fd7 [i1 o128]: Transport endpoint is not connected : debug: channel 2: input: no drain shortcut : debug: channel 2: ibuf empty : debug: channel 2: input drain -> wait_oclose : debug: channel 2: send ieof : debug: channel 2: rcvd oclose : debug: channel 2: input wait_oclose -> closed : debug: channel 2: full closed : : I'd appreciate it if the appended patch could be applied. It causes : ssh to recognize the bug and not emit the error message. : : [I've reported the bug to the kernel developers but they do not seem : interested in fixing it.] : : zw : : --- openssh-2.1.1p4.orig/nchan.c Thu Jun 22 04:32:31 2000 : +++ openssh-2.1.1p4/nchan.c Sun Jul 23 09:42:23 2000 : @@ -483,7 +483,12 @@ : return; : debug("channel %d: close_read", c->self); : if (c->sock != -1) { : - if (shutdown(c->sock, SHUT_RD) < 0) : + /* shutdown(sock, SHUT_READ) may return ENOTCONN if the : + write side has been closed already. */ : + if (shutdown(c->sock, SHUT_RD) < 0 : + && (errno != ENOTCONN : + || c->ostate == CHAN_OUTPUT_OPEN : + || c->ostate == CHAN_OUTPUT_WAIT_DRAIN)) : error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s", : c->self, c->sock, c->istate, c->ostate, strerror(errno)); : } else { :