nix-gh/perl/lib/Nix/SSH.pm

111 lines
2.3 KiB
Perl
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package Nix::SSH;
use utf8;
use strict;
use File::Temp qw(tempdir);
use IPC::Open2;
our @ISA = qw(Exporter);
our @EXPORT = qw(
@globalSshOpts
readN readInt readString readStrings
writeInt writeString writeStrings
connectToRemoteNix
);
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));
}
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 {
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.
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;