Hi Catalin,<br>
<br>
Thanks for looking at that - the last patch looks sensible, I&#39;ll give it a good test. There are a lot of subtle scenarios in channel closing (and variations between OSes). <br>
<br>
Cheers,<br>
Matt<br>
<br>
Catalin Patulea &lt;cat@vv.carleton.ca&gt; wrote:<br>
&gt;Hm, that broke channel-close-by-child-exit. One more try, where we<br>
&gt;check for the child exiting and close writefd as a result. If writefd<br>
&gt;is the last remaining open pipe to the child, then we also close the<br>
&gt;channel as a whole.<br>
&gt;<br>
&gt;On Wed, Jul 17, 2013 at 3:25 PM, Catalin Patulea &lt;cat@vv.carleton.ca&gt;<br>
&gt;wrote:<br>
&gt;&gt; Attached patch should fix both, and use hard tabs so should apply<br>
&gt;easily.<br>
&gt;&gt;<br>
&gt;&gt; Rather than replacing readfd with writefd, *both* are checked for<br>
&gt;&gt; FD_CLOSED before closing the entire channel. Then each direction can<br>
&gt;&gt; be initially closed independently.<br>
&gt;&gt;<br>
&gt;&gt; On Wed, Jul 17, 2013 at 7:57 PM, Catalin Patulea &lt;cat@vv.carleton.ca&gt;<br>
&gt;wrote:<br>
&gt;&gt;&gt; dbclient handling of remote EOF/local not at EOF also appears<br>
&gt;broken:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; openssh:<br>
&gt;&gt;&gt; $ ssh -v root@1.2.3.4 &#39;exec cat &gt;/dev/null 2&gt;/dev/null&#39;<br>
&gt;&gt;&gt; [...]<br>
&gt;&gt;&gt; debug1: Entering interactive session.<br>
&gt;&gt;&gt; debug1: Sending command: exec cat &gt;/dev/null 2&gt;/dev/null<br>
&gt;&gt;&gt; # remote has sent EOF by virtue of &amp;&gt;/dev/null, but local-&gt;remote<br>
&gt;&gt;&gt; # direction still active<br>
&gt;&gt;&gt; foo  # local sends<br>
&gt;&gt;&gt; bar<br>
&gt;&gt;&gt; ^D  # local EOF, channel tears down<br>
&gt;&gt;&gt; debug1: client_input_channel_req: channel 1 rtype exit-status reply<br>
&gt;0<br>
&gt;&gt;&gt; debug1: channel 1: free: client-session, nchannels 2<br>
&gt;&gt;&gt; &lt;exit&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Note &#39;exec&#39; is required to replace shell and prevent it from holding<br>
&gt;a<br>
&gt;&gt;&gt; ref to the stdout pipe.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; dropbear:<br>
&gt;&gt;&gt; $ ./dbclient -v root@lun.nanobit.org &#39;exec cat &gt;/dev/null<br>
&gt;2&gt;/dev/null&#39;<br>
&gt;&gt;&gt; [...]<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330457: process_packet: packet type = 96, <br>
&gt;len 5<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330499: enter recv_msg_channel_eof<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330513: CLOSE some fd 1<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330526: sending close, readfd is closed<br>
&gt;&gt;&gt; # remote EOF should *not* cause entire channel teardown;<br>
&gt;&gt;&gt; # local may still have something to write (&quot;foo bar&quot; from openssh<br>
&gt;&gt;&gt; # example).<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330537: enter send_msg_channel_close<br>
&gt;0x1f78660<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330549: enter cli_tty_cleanup<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330560: leave cli_tty_cleanup: not in raw<br>
&gt;mode<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330606: CLOSE some fd 0<br>
&gt;&gt;&gt; TRACE  (31787) 1374079900.330618: CLOSE some fd 2<br>
&gt;&gt;&gt; &lt;exit&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; On Sat, Jul 13, 2013 at 12:51 PM, Catalin Patulea<br>
&gt;&lt;cat@vv.carleton.ca&gt; wrote:<br>
&gt;&gt;&gt;&gt; Maybe the check on common-channel.c:338 should be against writefd<br>
&gt;&gt;&gt;&gt; instead of readfd? This would get set by<br>
&gt;&gt;&gt;&gt; close_chan_fd(channel-&gt;writefd) once recv_eof happens.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; This patch indeed causes &#39;foo&#39; to surface after input EOF:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; diff -r 69cb561cc4c4 common-channel.c<br>
&gt;&gt;&gt;&gt; --- a/common-channel.c Sat Jul 13 11:53:24 2013 +0300<br>
&gt;&gt;&gt;&gt; +++ b/common-channel.c Sat Jul 13 12:50:41 2013 +0300<br>
&gt;&gt;&gt;&gt; @@ -335,7 +335,7 @@<br>
&gt;&gt;&gt;&gt;   }<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;   /* And if we can&#39;t receive any more data from them either, close<br>
&gt;up */<br>
&gt;&gt;&gt;&gt; - if (channel-&gt;readfd == FD_CLOSED<br>
&gt;&gt;&gt;&gt; + if (channel-&gt;writefd == FD_CLOSED<br>
&gt;&gt;&gt;&gt;   &amp;&amp; (ERRFD_IS_WRITE(channel) || channel-&gt;errfd == FD_CLOSED)<br>
&gt;&gt;&gt;&gt;   &amp;&amp; !channel-&gt;sent_close<br>
&gt;&gt;&gt;&gt;   &amp;&amp; close_allowed<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; On Sat, Jul 13, 2013 at 12:31 PM, Catalin Patulea<br>
&gt;&lt;cat@vv.carleton.ca&gt; wrote:<br>
&gt;&gt;&gt;&gt;&gt; Hi,<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; I&#39;m seeing a difference in how dbclient handles EOF on input<br>
&gt;compared<br>
&gt;&gt;&gt;&gt;&gt; to openssh client. openssh client propagates input EOF to the<br>
&gt;remote<br>
&gt;&gt;&gt;&gt;&gt; command, but continues pumping command stdout. dbclient seems to<br>
&gt;abort<br>
&gt;&gt;&gt;&gt;&gt; before flushing the stdout buffer.<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; In the following examples, <a href="http://1.2.3.4">1.2.3.4</a> is an openwrt router running<br>
&gt;&gt;&gt;&gt;&gt; dropbear server. The remote command is designed to wait for EOF,<br>
&gt;then<br>
&gt;&gt;&gt;&gt;&gt; output something to stdout.<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; openssh client:<br>
&gt;&gt;&gt;&gt;&gt; $ ssh root@1.2.3.4 &#39;cat; echo foo&#39;<br>
&gt;&gt;&gt;&gt;&gt; ^D<br>
&gt;&gt;&gt;&gt;&gt; foo<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; dbclient:<br>
&gt;&gt;&gt;&gt;&gt; $ ./dbclient root@1.2.3.4 &#39;cat; echo foo&#39;<br>
&gt;&gt;&gt;&gt;&gt; ^D<br>
&gt;&gt;&gt;&gt;&gt; &lt;no output&gt;<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; I build dropbear with DEBUG_TRACE and these are the last few<br>
&gt;lines:<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): empty queue dequeing<br>
&gt;&gt;&gt;&gt;&gt; ^D<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): send normal readfd<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): enter send_msg_channel_data<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): enter send_msg_channel_data isextended 0 fd 0<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): maxlen 16375<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): CLOSE some fd 0<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): leave send_msg_channel_data: len 0 read err 17 or EOF<br>
&gt;for fd 0<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): enter send_msg_channel_eof<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): leave send_msg_channel_eof<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): sending close, readfd is closed<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): enter send_msg_channel_close 0xcbfdc0<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): enter cli_tty_cleanup<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): leave cli_tty_cleanup: not in raw mode<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): CLOSE some fd -1<br>
&gt;&gt;&gt;&gt;&gt; TRACE (...): CLOSE some fd 2<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; I tried reading through the relevant sections of channel-common.c<br>
&gt;but<br>
&gt;&gt;&gt;&gt;&gt; I could use some guidance/background. Is this behaviour<br>
&gt;intentional?<br>
&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt; Catalin<br>