diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2017-03-03 19:05:50 +0100 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2017-03-03 19:05:50 +0100 |
commit | 577ebeaefb71020f0d6b79488602fd56ba2c1863 (patch) | |
tree | cffee660e5d378419d4e15a5269095666e42640e /src/libstore/ssh.cc | |
parent | 7f62be1bcd2a228076a6c39eb435ad1931bb66e4 (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.cc | 93 |
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); +} + +} |