wiliv has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to see how IPC::PerlSSH behaves in case the underlying ssh connection gets disconnected.

It seems to terminate my program even escaping an eval block...

use IPC::PerlSSH; eval { my $ips = IPC::PerlSSH->new( Host => "somehost" ); print $ips->eval("1")."\n"; <>; # allow me to cut ssh connection print $ips->eval("2")."\n"; }; if ($@) { print "error: $@"; } print "done\n";

Normally the program runs as expected:

$ perl test_ipc_perlssh.pl 1 [pressed enter] 2 done $

Now when I kill the sshd on the remote host during the <>

$ perl test_ipc_perlssh.pl 1 [killed sshd on remote] Connection to somehost closed by remote host. [pressed enter] $

Not getting "2" means it didn't survive the connection cut, ok.

But why don't I get "done" or perhaps "error:" ? It seems to exit my program.

I had the exact same issue with GRID::Machine. I want to use GRID::Machine (or IPC::PerlSSH) in a daemon...

Any hints ?

Replies are listed 'Best First'.
Re: SSH disconnect and IPC::PerlSSH (or GRID::Machine)
by ig (Vicar) on Aug 31, 2009 at 19:16 UTC

    IPC::PerlSSH uses IPC::Open2 to spawn an ssh process with pipes for input and output. When you kill the ssh server on the remote host this sub-process terminates. Then, when the second $ips->eval() runs it attempts to write to the pipe, which fails and generates a SIGPIPE signal to the parent process (your script). You don't have a handler for SIGPIPE and the default action is to terminate your process, but with Deferred Signals (Safe Signals) this signal is deferred until the read from STDIN completes. As soon as the read completes, your process is terminated, without continuing to test the error returned from the eval or printing "done".

    Try adding a signal handler for SIGPIPE.

    use strict; use warnings; use IPC::PerlSSH; eval { $SIG{PIPE} = sub { die "pipe dreams"; }; my $ips = IPC::PerlSSH->new( Host => "localhost" ); print $ips->eval("1")."\n"; <>; # allow me to cut ssh connection print $ips->eval("2")."\n"; }; if ($@) { print "error: $@"; } print "done\n";