nix/perl/lib/Nix/SSH.pm

111 lines
2.3 KiB
Perl
Raw Normal View History

package Nix::SSH;
use utf8;
use strict;
use File::Temp qw(tempdir);
use IPC::Open2;
our @ISA = qw(Exporter);
our @EXPORT = qw(
2014-07-24 14:24:57 +00:00
@globalSshOpts
2014-07-24 10:24:25 +00:00
readN readInt readString readStrings
writeInt writeString writeStrings
connectToRemoteNix
);
2014-07-24 14:24:57 +00:00
our @globalSshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
sub readN {
my ($bytes, $from) = @_;
my $res = "";
while ($bytes > 0) {
my $s;
my $n = sysread($from, $s, $bytes);
die "I/O error reading from remote side\n" if !defined $n;
die "got EOF while expecting $bytes bytes from remote side\n" if !$n;
$bytes -= $n;
$res .= $s;
}
return $res;
}
sub readInt {
my ($from) = @_;
return unpack("L<x4", readN(8, $from));
}
2014-07-24 10:24:25 +00:00
sub readString {
my ($from) = @_;
my $len = readInt($from);
my $s = readN($len, $from);
readN(8 - $len % 8, $from) if $len % 8; # skip padding
return $s;
}
sub readStrings {
my ($from) = @_;
my $n = readInt($from);
my @res;
push @res, readString($from) while $n--;
return @res;
}
sub writeInt {
my ($n, $to) = @_;
syswrite($to, pack("L<x4", $n)) or die;
}
sub writeString {
my ($s, $to) = @_;
my $len = length $s;
my $req .= pack("L<x4", $len);
$req .= $s;
$req .= "\000" x (8 - $len % 8) if $len % 8;
syswrite($to, $req) or die;
}
sub writeStrings {
my ($ss, $to) = @_;
writeInt(scalar(@{$ss}), $to);
writeString($_, $to) foreach @{$ss};
}
sub connectToRemoteNix {
2014-07-11 22:09:43 +00:00
my ($sshHost, $sshOpts, $extraFlags) = @_;
$extraFlags ||= "";
# Start nix-store --serve on the remote host.
my ($from, $to);
# FIXME: don't start a shell, start ssh directly.
2014-07-24 14:24:57 +00:00
my $pid = open2($from, $to, "exec ssh -x -a $sshHost @globalSshOpts @{$sshOpts} nix-store --serve --write $extraFlags");
# Do the handshake.
my $magic;
eval {
my $SERVE_MAGIC_1 = 0x390c9deb; # FIXME
my $clientVersion = 0x200;
syswrite($to, pack("L<x4L<x4", $SERVE_MAGIC_1, $clientVersion)) or die;
$magic = readInt($from);
};
die "unable to connect to '$sshHost'\n" if $@;
die "did not get valid handshake from remote host\n" if $magic != 0x5452eecb;
my $serverVersion = readInt($from);
die "unsupported server version\n" if $serverVersion < 0x200 || $serverVersion >= 0x300;
return ($from, $to, $pid);
}
1;