LINUX.ORG.RU

двунаправленный канал через ssh на perl


0

0

Хочу сделать сабж, чтобы можно было определить отсутствие связи и прочие проблемы, произошедшие с ssh.
Однонаправленный вариант работает нормально ($proga на сервере получает данные):
$pid = open(RECV, "| -");
$SIG{ALRM} = sub { die "whoops, program pipe broke" };
if($pid)
{
print RECV "blablabla" || die ("Can't send data!\n");
close(RECV) || die ("SSH exited $?");
exit 0;
}
else
{#child
($EUID, $EGID) = ($UID, $GID);
exec("/usr/bin/ssh $user\@$server $proga 2>/dev/null") || die "can't exec program: $!";
}
Самый страшный двунаправленный вариант, который придумался - вот такой (данные получает шелл пользователя $user):
pipe(PR, CW);
pipe(CR, PW);
$pid = fork();
$SIG{ALRM} = sub { dielog("ssh pipe broke"); };
if ($pid)
{#parent
close PR; close PW;
print CW "blablabla" || dielog("can't send data");
close(CW) || dielog("ssh exited $?");
close(CR) || dielog("ssh exited $?") ;
waitpid($pid,0);
exit 0;
}
else
{#child
dielog("cannot fork: $!") unless defined $pid;
close CR; close CW;
open(STDOUT,">&PW"); close PW;
open(STDIN,"<&PR"); close PR;
($EUID, $EGID) = ($UID, $GID);
my $server = "$ssh $user\@server 2>/dev/null";
exec($server) || dielog("can't exec $server: $!");
}
Вот этот вариант успешно завершается даже при попытке послать данные на несуществующий сервер (левый ip-шник).
Что я делаю не так? Существует ли более элегантное решение? Мне важно, чтобы скрипт прерывался при любых проблемах со связью.


"Мне важно, чтобы скрипт прерывался при любых проблемах со связью."

чего делаешь, делаешь двух чайлдов, один пингует, другой держит связь. Как только пинг не проходит, тутже убиваешь пингующим того, кто связь держит и пингуешь дальше. Если пингуется в парент даешь сигнал через сокет, чтобы он форкнул того, кто держит связь. ssh тут не поможет никак.

vilfred ☆☆
()
Ответ на: комментарий от vilfred

Постоянно связь держать не нужно. Этот скрипт по крону время от времени запускается, передает некую инфу, а потом завершается.
Я вообще сделал, что при запуске он проверяет, не запущена ли его предыдущия копия (которая не успела передать), и грохает ее (предыдущую копию). Получается таймаут на передачу, равный периоду запуска скрипта.
Почему не отлавливаются ошибки аварийного завершения ssh'и (например когда несуществующий хост указываешь), невозможности установления соединения?

Gelin
() автор топика
Ответ на: комментарий от Gelin

может быть имеет смысл сделать в ssh перенаправление stderror в stdout... а отлавливать в перле SIGKILL или SIGERROR это не так то просто для нефоркнутой перлом проги... имхо. Если сделить в прогу вызов exec, то прога без измененичя pid становиться другой прогой(perldoc -f exec), а если отслеживать форкнутые процессы может и можно. Вобщем, тебе, по видимому самому нужно тут.

vilfred ☆☆
()

Решил задачку. Вот вариант, который меня устраивает:
use FileHandle;
use IPC::Open2;
use POSIX ":sys_wait_h";
my $server = "$ssh $user\@$server 2>/dev/null";
$SIG{ALRM} = sub { dielog("SIGALRM ssh pipe broke"); };
$SIG{PIPE} = sub { dielog("SIGPIPE ssh pipe broke"); };
$SIG{CHLD} = sub { while (waitpid(-1,WNOHANG) > 0) { dielog("child ssh exited $?") if $?>0; }; };
$pid = open2(*RECV,*SEND,$server) || dielog("can't exec $server");
SEND->autoflush(1);
print SEND "blablabla" || dielog("can't send data"); #передаем
close(SEND) || dielog("ssh exited $?");
$buf = <RECV>; #принимаем
close(RECV) || dielog("ssh exited $?");
waitpid($pid,0);
Здесь нет задачи особенно синхронизировать прием/передачу - все происходит последовательно.
Сильно подозреваю, что можно обойтись и без обработчиков SIGALRM и SIGPIPE, но пусть будут на всякий случай.

Gelin
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.