Skip Menu |

This queue is for tickets about the Net-SSH2 CPAN distribution.

Report information
The Basics
Id: 31083
Status: resolved
Priority: 0/
Queue: Net-SSH2

People
Owner: Nobody in particular
Requestors: george.king [...] tropos.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.18
Fixed in: (no value)



Subject: channel->read problems with exec and shell
I have encountered two problems with reading output from channels. The first is that shell channels return undef from reads. the diamond operator successfully reads from shell channels, but ext_data('merge') does not appear to work in this case. The second is that exec channels hang when reading via the diamond operator, but work fine with explicit read commands. ext_data('merge') works here. Attached are files that demonstrate the problem. SSH2Runs.pl should successfully execute and demonstrate the ext_data('merge') issue. SSH2Hangs.pl demonstrates the read undef problem, followed by the read hang. I am not sure if this is a Net::SSH2 problem or a libssh2 problem, but I thought I'd start here. I've also noticed that the placement of a $channel->blocking(0) call immediately after the creation of a channel is critical if the channel is to be used for a shell. Perhaps this hint could be added, to the documentation. These issues are occurring on Fedora 8 / x86. Please let me know if I can provide any assistance. I'm not familiar with xs bindings but I have a serious interest in making this module robust.
Subject: SSH2Hangs.pl
#!/usr/bin/perl use strict; use warnings; require 'SSH2Wrapper.pl'; my $ssh; my $channel; Net::SSH2->debug(1); if (1) { print "***** Test Single Shell With Read *****\n"; $ssh = wrapConnect(); $channel = $ssh->channel() or die 'could not create channel'; $channel->blocking(0); # the placement of this call is critical $channel->shell(); print $channel "pwd\n"; print "** BROKEN: channel->read returns undef!: **\n"; printOutputSeperate($channel); print $channel "ls zzzzzzzzz\n"; print "** BROKEN: channel->read returns undef!: **\n"; printOutputSeperate($channel); undef $ssh; undef $channel; } if (1) { print "***** Test Multiple Channel Execs With Diamond *****\n"; $ssh = wrapConnect(); $channel = $ssh->channel() or die 'could not create channel'; # $channel->ext_data('normal'); # default $channel->exec('pwd'); print "** BROKEN: channel->read hangs on poll!: **\n"; printOutputDiamond($channel); print "I NEVER GET HERE!!\n"; # $channel = $ssh->channel() or die 'could not create channel'; # $channel->ext_data('merge'); $channel->exec('ls zzzzzzzzz'); print "** BROKEN: channel->read hangs on poll!: **\n"; printOutputDiamond($channel); print "I REALLY NEVER GET HERE!!\n"; }
Subject: SSH2Wrapper.pl
#!/usr/bin/perl use strict; use warnings; use Net::SSH2; my @poll_events = qw( in pri ext out ); my @poll_revents = qw( err hup session_closed nval ex channel_closed listener_closed ); sub wrapConnect { my $ssh = Net::SSH2->new(); $ssh->connect('10.245.2.11') or die 'connect failed'; $ssh->auth_publickey('root', '/home/george/.ssh/id_rsa.pub', '/home/george/.ssh/id_rsa') or die 'Authentication failed'; return $ssh; } sub printOutputSeperate($) { my ($channel) = @_; my $buffer; my $string = ''; while ($channel->read($buffer, 512) > 0) { $string .= $buffer; } print "STDOUT: $string\n"; $string = ''; while ($channel->read($buffer, 512, 1) > 0) { $string .= $buffer; } print "STDERR: $string\n"; print "EXIT: " . $channel->exit_status() . "\n"; } sub printOutputDiamond($) { my ($channel) = @_; my $string = ''; $string .= $_ while (<$channel>); print "HANDLE OUT: $string\n"; print "EXIT: " . $channel->exit_status() . "\n"; } 1;
Subject: SSH2Runs.pl
#!/usr/bin/perl use strict; use warnings; require 'SSH2Wrapper.pl'; my $ssh; my $channel; Net::SSH2->debug(1); if (1) { print "***** Test Single Shell With Diamond *****\n"; $ssh = wrapConnect(); $channel = $ssh->channel() or die 'could not create channel'; $channel->blocking(0); # the placement of this call is critical $channel->ext_data('merge'); # merge is broken for shell $channel->shell(); print $channel "pwd\n"; print "** stdout works: **\n"; printOutputDiamond($channel); print $channel "ls zzzzzzzzz\n"; print "** BROKEN: merged output should show stderr and exit status 1: **\n"; printOutputDiamond($channel); undef $ssh; undef $channel; } if (1) { print "***** Test Multiple Channel Execs With Read *****\n"; $ssh = wrapConnect(); $channel = $ssh->channel() or die 'could not create channel'; # $channel->ext_data('normal'); # default $channel->exec('pwd'); print "** stdout works: **\n"; printOutputSeperate($channel); $channel = $ssh->channel() or die 'could not create channel'; # $channel->ext_data('merge'); # merge does work here $channel->exec('ls zzzzzzzzz'); print "** seperate stderr works: **\n"; printOutputSeperate($channel); }
These bugs have already been fixed in the development version. Only one exec/shell/tcpip/etc. call is possible per Channel. There is no way in the libssh2 API to detect when some channel has already been used in order to throw an error.