add TerminationTimeout timeout options
This commit is contained in:
parent
b34482ae97
commit
2af86f0524
4 changed files with 64 additions and 11 deletions
|
@ -21,16 +21,21 @@
|
||||||
#include "SMSubProcess.h"
|
#include "SMSubProcess.h"
|
||||||
#include "smsub.h"
|
#include "smsub.h"
|
||||||
|
|
||||||
SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory)
|
SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout) :
|
||||||
|
termTimeout(termTimeout)
|
||||||
{
|
{
|
||||||
|
// Set process executable, arguments and working directory
|
||||||
process.setProgram(executable);
|
process.setProgram(executable);
|
||||||
process.setArguments(arguments);
|
process.setArguments(arguments);
|
||||||
process.setWorkingDirectory(workingDirectory);
|
process.setWorkingDirectory(workingDirectory);
|
||||||
|
|
||||||
|
// stdout and stderr in same IO stream
|
||||||
process.setProcessChannelMode(QProcess::MergedChannels);
|
process.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
|
||||||
QObject::connect(&process, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
// Connect process signal handlers
|
||||||
QObject::connect(&process, SIGNAL(finished(int)), this, SLOT(processExit(int)));
|
QObject::connect(&process, &QProcess::readyRead, this, &SMSubProcess::readyRead);
|
||||||
QObject::connect(&process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
|
QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError);
|
||||||
|
QObject::connect(&process, QOverload<int>::of(&QProcess::finished), this, &SMSubProcess::processExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMSubProcess::start()
|
void SMSubProcess::start()
|
||||||
|
@ -69,10 +74,10 @@ void SMSubProcess::processError(QProcess::ProcessError error)
|
||||||
|
|
||||||
void SMSubProcess::aboutToQuit()
|
void SMSubProcess::aboutToQuit()
|
||||||
{
|
{
|
||||||
// Main process terminated
|
// Main process terminated, terminate subprocess with set timeout
|
||||||
if (process.state() == QProcess::Running) {
|
if (process.state() == QProcess::Running) {
|
||||||
process.terminate();
|
process.terminate();
|
||||||
if (!process.waitForFinished(60000)) {
|
if (!process.waitForFinished(termTimeout)) {
|
||||||
QTextStream(stderr) << "Failed to terminate process!" << endl;
|
QTextStream(stderr) << "Failed to terminate process!" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,12 @@ class SMSubProcess : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
SMSubProcess(const QString &executable, const QStringList &arguments, const QString& workingDirectory);
|
SMSubProcess(const QString &executable, const QStringList &arguments, const QString& workingDirectory, const int &termTimeout = 60000);
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QProcess process;
|
QProcess process;
|
||||||
|
int termTimeout;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
|
@ -55,6 +55,8 @@ void SMSubServer::readyRead()
|
||||||
bool isAuthenticated = socket->property("Authenticated").toBool();
|
bool isAuthenticated = socket->property("Authenticated").toBool();
|
||||||
while (socket->canReadLine()) {
|
while (socket->canReadLine()) {
|
||||||
const QByteArray readData = socket->readLine().trimmed();
|
const QByteArray readData = socket->readLine().trimmed();
|
||||||
|
|
||||||
|
// Only allow commands being sent if authenticated
|
||||||
if (likely(isAuthenticated)) {
|
if (likely(isAuthenticated)) {
|
||||||
if (readData.startsWith("+dbg")) {
|
if (readData.startsWith("+dbg")) {
|
||||||
socket->setProperty("ReceiveDbgMsg", true);
|
socket->setProperty("ReceiveDbgMsg", true);
|
||||||
|
@ -103,7 +105,9 @@ void SMSubServer::readyRead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Authenticate when token is valid, otherwise disconnect
|
||||||
if (unlikely(tokens.contains(QString::fromUtf8(readData)))) {
|
if (unlikely(tokens.contains(QString::fromUtf8(readData)))) {
|
||||||
|
// Set client as authenticated and add it to vector
|
||||||
socket->setProperty("Authenticated", true);
|
socket->setProperty("Authenticated", true);
|
||||||
socket->write("Login successful!\n");
|
socket->write("Login successful!\n");
|
||||||
isAuthenticated = true;
|
isAuthenticated = true;
|
||||||
|
@ -159,6 +163,7 @@ void SMSubServer::writeOutput(const QByteArray &output)
|
||||||
|
|
||||||
void SMSubServer::registerToken(const QString &token)
|
void SMSubServer::registerToken(const QString &token)
|
||||||
{
|
{
|
||||||
|
// Register temporary token for a secure remote connection
|
||||||
tokens << token;
|
tokens << token;
|
||||||
QTimer::singleShot(30000, [this, token]() {
|
QTimer::singleShot(30000, [this, token]() {
|
||||||
tokens.removeAll(token);
|
tokens.removeAll(token);
|
||||||
|
|
50
main.cpp
50
main.cpp
|
@ -39,7 +39,24 @@
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
void catchUnixSignals(std::initializer_list<int> quitSignals) {
|
||||||
auto handler = [](int sig) -> void {
|
auto handler = [](int sig) -> void {
|
||||||
QTextStream(stderr) << "Received Unix signal: " << sig << endl;
|
QString unixSignal;
|
||||||
|
switch (sig) {
|
||||||
|
case SIGINT:
|
||||||
|
unixSignal = QLatin1String("SIGINT");
|
||||||
|
break;
|
||||||
|
case SIGHUP:
|
||||||
|
unixSignal = QLatin1String("SIGHUP");
|
||||||
|
break;
|
||||||
|
case SIGQUIT:
|
||||||
|
unixSignal = QLatin1String("SIGQUIT");
|
||||||
|
break;
|
||||||
|
case SIGTERM:
|
||||||
|
unixSignal = QLatin1String("SIGTERM");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unixSignal = QString::number(sig);
|
||||||
|
}
|
||||||
|
QTextStream(stderr) << "Received Unix signal: " << unixSignal << endl;
|
||||||
QCoreApplication::quit();
|
QCoreApplication::quit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,10 +79,10 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication a(argc, argv);
|
QCoreApplication a(argc, argv);
|
||||||
a.setApplicationName("Server Manager Subprocess");
|
a.setApplicationName("Server Manager Subprocess");
|
||||||
a.setApplicationVersion("0.2");
|
a.setApplicationVersion("0.2.1");
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP});
|
catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QCommandLineParser commandLineParser;
|
QCommandLineParser commandLineParser;
|
||||||
|
@ -95,6 +112,9 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
commandLineParser.addOption(subprocessRemoteSocket);
|
commandLineParser.addOption(subprocessRemoteSocket);
|
||||||
|
|
||||||
|
QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout");
|
||||||
|
commandLineParser.addOption(processTimeout);
|
||||||
|
|
||||||
commandLineParser.process(a);
|
commandLineParser.process(a);
|
||||||
|
|
||||||
if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) {
|
if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) {
|
||||||
|
@ -102,6 +122,17 @@ int main(int argc, char *argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool timeoutSet = false;
|
||||||
|
int termTimeout = 60000;
|
||||||
|
if (unlikely(commandLineParser.isSet(processTimeout))) {
|
||||||
|
bool ok;
|
||||||
|
const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok);
|
||||||
|
if (ok) {
|
||||||
|
termTimeout = _termTimeout;
|
||||||
|
timeoutSet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString executable;
|
QString executable;
|
||||||
QString workingDirectory;
|
QString workingDirectory;
|
||||||
QStringList argumentList;
|
QStringList argumentList;
|
||||||
|
@ -158,6 +189,17 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(!timeoutSet && jsonObject.contains("TerminationTimeout"))) {
|
||||||
|
const QJsonValue jsonTimeout = jsonObject.value("TerminationTimeout");
|
||||||
|
if (unlikely(!jsonTimeout.isDouble())) {
|
||||||
|
termTimeout = qRound(jsonTimeout.toDouble());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QTextStream(stderr) << "Termination Timeout is not a number in manifest, aborting!" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
manifestFile.close();
|
manifestFile.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,7 +259,7 @@ int main(int argc, char *argv[])
|
||||||
localSettings.canRegister = false;
|
localSettings.canRegister = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SMSubProcess subProcess(executable, argumentList, workingDirectory);
|
SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout);
|
||||||
|
|
||||||
QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput);
|
QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput);
|
||||||
QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
|
QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);
|
||||||
|
|
Loading…
Reference in a new issue