From 5c731636b1c12b2073b68ab38c5a14d487a52ae4 Mon Sep 17 00:00:00 2001
From: Atlante45 <clement.brisset@gmail.com>
Date: Thu, 29 Jun 2017 11:44:05 -0700
Subject: [PATCH] Sandbox restarts crashed processes

---
 assignment-client/src/AssignmentClientApp.cpp | 35 +++++--------------
 assignment-client/src/AssignmentClientApp.h   |  1 -
 .../src/AssignmentClientMonitor.cpp           |  4 +--
 domain-server/src/DomainServer.cpp            | 13 +++++++
 libraries/shared/src/SharedUtil.cpp           | 21 +++++++++++
 libraries/shared/src/SharedUtil.h             |  3 ++
 server-console/src/main.js                    |  6 ++--
 server-console/src/modules/hf-process.js      |  8 +++++
 8 files changed, 58 insertions(+), 33 deletions(-)

diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp
index bc03808c1e..bd656ceb09 100644
--- a/assignment-client/src/AssignmentClientApp.cpp
+++ b/assignment-client/src/AssignmentClientApp.cpp
@@ -9,8 +9,12 @@
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
 //
 
-#include <QCommandLineParser>
-#include <QThread>
+#include "AssignmentClientApp.h"
+
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QDir>
+#include <QtCore/QStandardPaths>
+#include <QtCore/QThread>
 
 #include <LogHandler.h>
 #include <SharedUtil.h>
@@ -20,30 +24,6 @@
 #include "Assignment.h"
 #include "AssignmentClient.h"
 #include "AssignmentClientMonitor.h"
-#include "AssignmentClientApp.h"
-#include <QtCore/QDir>
-#include <QtCore/QStandardPaths>
-
-#ifdef WIN32
-VOID CALLBACK parentDiedCallback(PVOID lpParameter, BOOLEAN timerOrWaitFired) {
-    if (!timerOrWaitFired && qApp) {
-        qDebug() << "Parent process died, quitting";
-        qApp->quit();
-    }
-}
-
-void watchParentProcess(int parentPID) {
-    DWORD processID = parentPID;
-    HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
-
-    HANDLE newHandle;
-    RegisterWaitForSingleObject(&newHandle, procHandle, parentDiedCallback, NULL, INFINITE, WT_EXECUTEONLYONCE);
-}
-#else
-void watchParentProcess(int parentPID) {
-    qWarning() << "Parent PID option not implemented on this plateform";
-}
-#endif // WIN32
 
 AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
     QCoreApplication(argc, argv)
@@ -107,7 +87,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
     const QCommandLineOption logDirectoryOption(ASSIGNMENT_LOG_DIRECTORY, "directory to store logs", "log-directory");
     parser.addOption(logDirectoryOption);
 
-    const QCommandLineOption parentPIDOption(ASSIGNMENT_PARENT_PID, "PID of the parent process", "parent-pid");
+    const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
     parser.addOption(parentPIDOption);
 
     if (!parser.parse(QCoreApplication::arguments())) {
@@ -231,6 +211,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
         int parentPID = parser.value(parentPIDOption).toInt(&ok);
 
         if (ok) {
+            qDebug() << "Parent process PID is" << parentPID;
             watchParentProcess(parentPID);
         }
     }
diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h
index a7c8cdb54d..37d3b9cc1d 100644
--- a/assignment-client/src/AssignmentClientApp.h
+++ b/assignment-client/src/AssignmentClientApp.h
@@ -27,7 +27,6 @@ const QString ASSIGNMENT_MAX_FORKS_OPTION = "max";
 const QString ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION = "monitor-port";
 const QString ASSIGNMENT_HTTP_STATUS_PORT = "http-status-port";
 const QString ASSIGNMENT_LOG_DIRECTORY = "log-directory";
-const QString ASSIGNMENT_PARENT_PID = "parent-pid";
 
 class AssignmentClientApp : public QCoreApplication {
     Q_OBJECT
diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp
index 568a29c8b1..070034d54b 100644
--- a/assignment-client/src/AssignmentClientMonitor.cpp
+++ b/assignment-client/src/AssignmentClientMonitor.cpp
@@ -131,7 +131,6 @@ void AssignmentClientMonitor::aboutToQuit() {
 void AssignmentClientMonitor::spawnChildClient() {
     QProcess* assignmentClient = new QProcess(this);
 
-
     // unparse the parts of the command-line that the child cares about
     QStringList _childArguments;
     if (_assignmentPool != "") {
@@ -159,9 +158,8 @@ void AssignmentClientMonitor::spawnChildClient() {
     // for now they simply talk to us on localhost
     _childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION);
     _childArguments.append(QString::number(DependencyManager::get<NodeList>()->getLocalSockAddr().getPort()));
-    
 
-    _childArguments.append("--" + ASSIGNMENT_PARENT_PID);
+    _childArguments.append("--" + PARENT_PID_OPTION);
     _childArguments.append(QString::number(QCoreApplication::applicationPid()));
 
     QString nowString, stdoutFilenameTemp, stderrFilenameTemp, stdoutPathTemp, stderrPathTemp;
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 8e3d04897b..095613a473 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -221,6 +221,8 @@ void DomainServer::parseCommandLine() {
     const QCommandLineOption masterConfigOption("master-config", "Deprecated config-file option");
     parser.addOption(masterConfigOption);
 
+    const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
+    parser.addOption(parentPIDOption);
 
     if (!parser.parse(QCoreApplication::arguments())) {
         qWarning() << parser.errorText() << endl;
@@ -249,6 +251,17 @@ void DomainServer::parseCommandLine() {
         _overrideDomainID = true;
         qDebug() << "domain-server ID is" << _overridingDomainID;
     }
+
+
+    if (parser.isSet(parentPIDOption)) {
+        bool ok = false;
+        int parentPID = parser.value(parentPIDOption).toInt(&ok);
+
+        if (ok) {
+            qDebug() << "Parent process PID is" << parentPID;
+            watchParentProcess(parentPID);
+        }
+    }
 }
 
 DomainServer::~DomainServer() {
diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp
index a68d27e620..58b8aead45 100644
--- a/libraries/shared/src/SharedUtil.cpp
+++ b/libraries/shared/src/SharedUtil.cpp
@@ -1076,3 +1076,24 @@ void setMaxCores(uint8_t maxCores) {
     SetProcessAffinityMask(process, newProcessAffinity);
 #endif
 }
+
+#ifdef Q_OS_WIN
+VOID CALLBACK parentDiedCallback(PVOID lpParameter, BOOLEAN timerOrWaitFired) {
+    if (!timerOrWaitFired && qApp) {
+        qDebug() << "Parent process died, quitting";
+        qApp->quit();
+    }
+}
+
+void watchParentProcess(int parentPID) {
+    DWORD processID = parentPID;
+    HANDLE procHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
+
+    HANDLE newHandle;
+    RegisterWaitForSingleObject(&newHandle, procHandle, parentDiedCallback, NULL, INFINITE, WT_EXECUTEONLYONCE);
+}
+#else
+void watchParentProcess(int parentPID) {
+    qWarning() << "Parent PID option not implemented on this plateform";
+}
+#endif // Q_OS_WIN
\ No newline at end of file
diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h
index 0f30842f47..681418a263 100644
--- a/libraries/shared/src/SharedUtil.h
+++ b/libraries/shared/src/SharedUtil.h
@@ -235,4 +235,7 @@ const QString& getInterfaceSharedMemoryName();
 
 void setMaxCores(uint8_t maxCores);
 
+const QString PARENT_PID_OPTION = "parent-pid";
+void watchParentProcess(int parentPID);
+
 #endif // hifi_SharedUtil_h
diff --git a/server-console/src/main.js b/server-console/src/main.js
index 95fb0d81b2..9cbdc38f47 100644
--- a/server-console/src/main.js
+++ b/server-console/src/main.js
@@ -892,10 +892,12 @@ function onContentLoaded() {
     deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX);
 
     if (dsPath && acPath) {
-        domainServer = new Process('domain-server', dsPath, ["--get-temp-name"], logPath);
+        domainServer = new Process('domain-server', dsPath, ['--get-temp-name',
+                                                             '--parent-pid', process.pid], logPath);
         acMonitor = new ACMonitorProcess('ac-monitor', acPath, ['-n7',
                                                                 '--log-directory', logPath,
-                                                                '--http-status-port', httpStatusPort], httpStatusPort, logPath);
+                                                                '--http-status-port', httpStatusPort,
+                                                                '--parent-pid', process.pid], httpStatusPort, logPath);
         homeServer = new ProcessGroup('home', [domainServer, acMonitor]);
         logWindow = new LogWindow(acMonitor, domainServer);
 
diff --git a/server-console/src/modules/hf-process.js b/server-console/src/modules/hf-process.js
index 3c1200fecc..1de0630a0a 100644
--- a/server-console/src/modules/hf-process.js
+++ b/server-console/src/modules/hf-process.js
@@ -267,7 +267,15 @@ Process.prototype = extend(Process.prototype, {
             clearTimeout(this.stoppingTimeoutID);
             this.stoppingTimeoutID = null;
         }
+        // Grab current state berofe updating it.
+        var unexpectedShutdown = this.state != ProcessStates.STOPPING;
         this.updateState(ProcessStates.STOPPED);
+
+        if (unexpectedShutdown) {
+            log.warn("Child stopped unexpectedly, restarting.");
+            this.start();
+            return;
+        }
     }
 });