SSHMaster: Make thread-safe

This commit is contained in:
Eelco Dolstra 2017-03-03 19:28:27 +01:00
parent d3eb1cf3bb
commit 8490ee37a6
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
2 changed files with 29 additions and 17 deletions

View file

@ -4,7 +4,7 @@ namespace nix {
std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command) std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
{ {
startMaster(); Path socketPath = startMaster();
Pipe in, out; Pipe in, out;
in.create(); in.create();
@ -27,7 +27,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
args.insert(args.end(), {"-i", keyFile}); args.insert(args.end(), {"-i", keyFile});
if (compress) if (compress)
args.push_back("-C"); args.push_back("-C");
if (useMaster) if (socketPath != "")
args.insert(args.end(), {"-S", socketPath}); args.insert(args.end(), {"-S", socketPath});
args.push_back(command); args.push_back(command);
execvp(args.begin()->c_str(), stringsToCharPtrs(args).data()); execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
@ -45,18 +45,22 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
return conn; return conn;
} }
void SSHMaster::startMaster() Path SSHMaster::startMaster()
{ {
if (!useMaster || sshMaster != -1) return; if (!useMaster) return "";
tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700)); auto state(state_.lock());
socketPath = (Path) *tmpDir + "/ssh.sock"; if (state->sshMaster != -1) return state->socketPath;
state->tmpDir = std::make_unique<AutoDelete>(createTempDir("", "nix", true, true, 0700));
state->socketPath = (Path) *state->tmpDir + "/ssh.sock";
Pipe out; Pipe out;
out.create(); out.create();
sshMaster = startProcess([&]() { state->sshMaster = startProcess([&]() {
restoreSignals(); restoreSignals();
close(out.readSide.get()); close(out.readSide.get());
@ -65,7 +69,7 @@ void SSHMaster::startMaster()
throw SysError("duping over stdout"); throw SysError("duping over stdout");
Strings args = Strings args =
{ "ssh", host.c_str(), "-M", "-N", "-S", socketPath { "ssh", host.c_str(), "-M", "-N", "-S", state->socketPath
, "-o", "LocalCommand=echo started" , "-o", "LocalCommand=echo started"
, "-o", "PermitLocalCommand=yes" , "-o", "PermitLocalCommand=yes"
}; };
@ -88,6 +92,8 @@ void SSHMaster::startMaster()
if (reply != "started") if (reply != "started")
throw Error("failed to start SSH master connection to %s", host); throw Error("failed to start SSH master connection to %s", host);
return state->socketPath;
} }
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "util.hh" #include "util.hh"
#include "sync.hh"
namespace nix { namespace nix {
@ -8,13 +9,19 @@ class SSHMaster
{ {
private: private:
std::string host; const std::string host;
std::string keyFile; const std::string keyFile;
bool useMaster; const bool useMaster;
bool compress; const bool compress;
Pid sshMaster;
std::unique_ptr<AutoDelete> tmpDir; struct State
Path socketPath; {
Pid sshMaster;
std::unique_ptr<AutoDelete> tmpDir;
Path socketPath;
};
Sync<State> state_;
public: public:
@ -34,8 +41,7 @@ public:
std::unique_ptr<Connection> startCommand(const std::string & command); std::unique_ptr<Connection> startCommand(const std::string & command);
void startMaster(); Path startMaster();
}; };
} }