about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-03-03T18·28+0100
committerEelco Dolstra <edolstra@gmail.com>2017-03-03T18·28+0100
commit8490ee37a6dbfb66e1b3dbaf88918bea044b143a (patch)
treef0a244e19a8b7412e93b1f487aa4c8d572ff19e4
parentd3eb1cf3bbf57a33ac2e71a19a150c077011ecd9 (diff)
SSHMaster: Make thread-safe
-rw-r--r--src/libstore/ssh.cc22
-rw-r--r--src/libstore/ssh.hh24
2 files changed, 29 insertions, 17 deletions
diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc
index 7c3de4a48271..4f88fa64dbd1 100644
--- a/src/libstore/ssh.cc
+++ b/src/libstore/ssh.cc
@@ -4,7 +4,7 @@ namespace nix {
 
 std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string & command)
 {
-    startMaster();
+    Path socketPath = startMaster();
 
     Pipe in, out;
     in.create();
@@ -27,7 +27,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
             args.insert(args.end(), {"-i", keyFile});
         if (compress)
             args.push_back("-C");
-        if (useMaster)
+        if (socketPath != "")
             args.insert(args.end(), {"-S", socketPath});
         args.push_back(command);
         execvp(args.begin()->c_str(), stringsToCharPtrs(args).data());
@@ -45,18 +45,22 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
     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;
     out.create();
 
-    sshMaster = startProcess([&]() {
+    state->sshMaster = startProcess([&]() {
         restoreSignals();
 
         close(out.readSide.get());
@@ -65,7 +69,7 @@ void SSHMaster::startMaster()
             throw SysError("duping over stdout");
 
         Strings args =
-            { "ssh", host.c_str(), "-M", "-N", "-S", socketPath
+            { "ssh", host.c_str(), "-M", "-N", "-S", state->socketPath
             , "-o", "LocalCommand=echo started"
             , "-o", "PermitLocalCommand=yes"
             };
@@ -88,6 +92,8 @@ void SSHMaster::startMaster()
 
     if (reply != "started")
         throw Error("failed to start SSH master connection to ‘%s’", host);
+
+    return state->socketPath;
 }
 
 }
diff --git a/src/libstore/ssh.hh b/src/libstore/ssh.hh
index 2d2b98370396..72238dad79ab 100644
--- a/src/libstore/ssh.hh
+++ b/src/libstore/ssh.hh
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "util.hh"
+#include "sync.hh"
 
 namespace nix {
 
@@ -8,13 +9,19 @@ class SSHMaster
 {
 private:
 
-    std::string host;
-    std::string keyFile;
-    bool useMaster;
-    bool compress;
-    Pid sshMaster;
-    std::unique_ptr<AutoDelete> tmpDir;
-    Path socketPath;
+    const std::string host;
+    const std::string keyFile;
+    const bool useMaster;
+    const bool compress;
+
+    struct State
+    {
+        Pid sshMaster;
+        std::unique_ptr<AutoDelete> tmpDir;
+        Path socketPath;
+    };
+
+    Sync<State> state_;
 
 public:
 
@@ -34,8 +41,7 @@ public:
 
     std::unique_ptr<Connection> startCommand(const std::string & command);
 
-    void startMaster();
-
+    Path startMaster();
 };
 
 }