diff options
Diffstat (limited to 'third_party/nix/perl/lib/Nix/SSH.pm')
-rw-r--r-- | third_party/nix/perl/lib/Nix/SSH.pm | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/third_party/nix/perl/lib/Nix/SSH.pm b/third_party/nix/perl/lib/Nix/SSH.pm new file mode 100644 index 000000000000..490ba0ea991e --- /dev/null +++ b/third_party/nix/perl/lib/Nix/SSH.pm @@ -0,0 +1,110 @@ +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; |