aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/ssh.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-03-03 19:05:50 +0100
committerEelco Dolstra <edolstra@gmail.com>2017-03-03 19:05:50 +0100
commit577ebeaefb71020f0d6b79488602fd56ba2c1863 (patch)
treecffee660e5d378419d4e15a5269095666e42640e /src/libstore/ssh.cc
parent7f62be1bcd2a228076a6c39eb435ad1931bb66e4 (diff)
Improve SSH handling
* Unify SSH code in SSHStore and LegacySSHStore. * Fix a race starting the SSH master. We now wait synchronously for the SSH master to finish starting. This prevents the SSH clients from starting their own connections. * Don't use a master if max-connections == 1. * Add a "max-connections" store parameter. * Add a "compress" store parameter.
Diffstat (limited to 'src/libstore/ssh.cc')
-rw-r--r--src/libstore/ssh.cc93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc
new file mode 100644
index 000000000..7c3de4a48
--- /dev/null
+++ b/src/libstore/ssh.cc
@@ -0,0 +1,93 @@
+#include "ssh.hh"
+
+namespace nix {
+
+std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
+{
+ startMaster();
+
+ Pipe in, out;
+ in.create();
+ out.create();
+
+ auto conn = std::make_unique<Connection>();
+ conn->sshPid = startProcess([&]() {
+ restoreSignals();
+
+ close(in.writeSide.get());
+ close(out.readSide.get());
+
+ if (dup2(in.readSide.get(), STDIN_FILENO) == -1)
+ throw SysError("duping over stdin");
+ if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
+ throw SysError("duping over stdout");
+
+ Strings args = { "ssh", host.c_str(), "-x", "-a" };
+ if (!keyFile.empty())
+ args.insert(args.end(), {"-i", keyFile});
+ if (compress)
+ args.push_back("-C");
+ if (useMaster)
+ args.insert(args.end(), {"-S", socketPath});
+ args.push_back(command);
+ execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
+
+ throw SysError("executing ‘%s’ on ‘%s’", command, host);
+ });
+
+
+ in.readSide = -1;
+ out.writeSide = -1;
+
+ conn->out = std::move(out.readSide);
+ conn->in = std::move(in.writeSide);
+
+ return conn;
+}
+
+void SSHMaster::startMaster()
+{
+ if (!useMaster || sshMaster != -1) return;
+
+ tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));
+
+ socketPath = (Path) *tmpDir + "/ssh.sock";
+
+ Pipe out;
+ out.create();
+
+ sshMaster = startProcess([&]() {
+ restoreSignals();
+
+ close(out.readSide.get());
+
+ if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1)
+ throw SysError("duping over stdout");
+
+ Strings args =
+ { "ssh", host.c_str(), "-M", "-N", "-S", socketPath
+ , "-o", "LocalCommand=echo started"
+ , "-o", "PermitLocalCommand=yes"
+ };
+ if (!keyFile.empty())
+ args.insert(args.end(), {"-i", keyFile});
+ if (compress)
+ args.push_back("-C");
+
+ execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
+
+ throw SysError("starting SSH master");
+ });
+
+ out.writeSide = -1;
+
+ std::string reply;
+ try {
+ reply = readLine(out.readSide.get());
+ } catch (EndOfFile & e) { }
+
+ if (reply != "started")
+ throw Error("failed to start SSH master connection to ‘%s’", host);
+}
+
+}