After reading the ssh2 module source, I think the close function is buggy in a way that causes the second issue. The first issue is probably fundamental because of how the module leaks the ssh abstraction to the stream level. (I'm using master to compare with.) At ssh2_fopen_wrappers.c+132, it does checks for EOF at the read level, but does nothing with this information. I suspect that this should be send_eof to close stdin. On the following line, it frees the channel. I don't see any libssh2_channel_close code in the stream closing function. There is no EOF sending code anywhere else as far as I could read. Annoyingly, this does mean that if fixed, this would probably mean closing the main stdio stream will close both stdin and stdout, requiring redirecting stdout into stderr to read it. The bidirectional stream doesn't really have any semantics to close stdin without closing stdout; I suspect there'd have to be another ssh2-specific function to close stdin by sending EOF. (Oh, and I did bump up to Fedora's 7.4.11 package. Didn't change anything, obviously.) `On Wed, 2020-10-28 at 15:16 -0300, Calvin Buckley wrote: > I've been having issues trying to use a command over ssh2_exec. The > command takes input over standard input, waits for it to be closed, > then writes back to standard output. Unfortunate, the ssh2 API seems > deficient in multiple ways: > > First, the stream returned by ssh2_exec is for /both/ standard input > and error. Closing means theoretically closing them both. This isn't > /too/ bad, because I believe my program doesn't use standard error, > so > I just reassign the FDs at the shell level so that standard output is > now on the separate standard error stream. > > Second, closing the stream doesn't actually seem to close standard > input. The program (and cat, for the example below) still seems to > think it should read from standard input and thus keeps standard > output > (well, error) open. > > This is annoying because it effectively means stream_get_contents is > useless for me, because it'll block forever or with non-blocking, > spit > out a bunch of spurious zeros as it gets nothing constantly. cat will > write back after the flush, but not immediately (some spurious zero > reads, then a read with data, then more spurious), and my program > relies on having standard input closed before it'll write. > > It appears others have tried to deal with this, but failed: > https://stackoverflow.com/questions/19898351/php-close-input-channel-of-bidirectional-stream-from-ssh2-exec > > > As with that person, I would /really/ not want to create a temporary > file on the remote server if I can get away with it. > > I'm using PHP 7.4.8 w/ the PECL SSH2 extension that's shipped by > Fedora. > > -- code -- > > <?php > > $server = "redact"; > $user = "redact"; > $password = "redact"; > > // no error handling in the sample program (real one does) > $conn = ssh2_connect($server, 22); > ssh2_auth_password($conn, $user, $password); > > // redirect stdout to stderr, because closing stdin also closes > stdout > // use cat as a surrogate (the program I'm calling takes all of stdin > // and writes back to stdout on stdin EOF; cat will have to do to > show > // the broken behaviour) > $ssh_stdio = ssh2_exec($conn, "cat 1>&2"); > $ssh_stderr = ssh2_fetch_stream($ssh_stdio, SSH2_STREAM_STDERR); > stream_set_blocking($ssh_stdio, true); > stream_set_blocking($ssh_stderr, true); > $written = fwrite($ssh_stdio, "the quick brown fox"); > // attempt to close stdin (using stderr afterwards, explained above) > fflush($ssh_stdio); > fclose($ssh_stdio); > // stderr blocking behaviour: > // blocking: blocks forever because cat doesn't know it closed? > // non-blocking: gets an empty string because cat hasn't written > // back in time > $out = stream_get_contents($ssh_stderr); > var_dump($out); >