From 2af86f05248422f1977e7f6c77c34d4d5ac856e6 Mon Sep 17 00:00:00 2001 From: Syping Date: Sat, 19 Sep 2020 00:19:39 +0200 Subject: [PATCH] add TerminationTimeout timeout options --- SMSubProcess.cpp | 17 ++++++++++------ SMSubProcess.h | 3 ++- SMSubServer.cpp | 5 +++++ main.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp index 587908f..de77f96 100644 --- a/SMSubProcess.cpp +++ b/SMSubProcess.cpp @@ -21,16 +21,21 @@ #include "SMSubProcess.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.setArguments(arguments); process.setWorkingDirectory(workingDirectory); + + // stdout and stderr in same IO stream process.setProcessChannelMode(QProcess::MergedChannels); - QObject::connect(&process, SIGNAL(readyRead()), this, SLOT(readyRead())); - QObject::connect(&process, SIGNAL(finished(int)), this, SLOT(processExit(int))); - QObject::connect(&process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); + // Connect process signal handlers + QObject::connect(&process, &QProcess::readyRead, this, &SMSubProcess::readyRead); + QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError); + QObject::connect(&process, QOverload::of(&QProcess::finished), this, &SMSubProcess::processExit); } void SMSubProcess::start() @@ -69,10 +74,10 @@ void SMSubProcess::processError(QProcess::ProcessError error) void SMSubProcess::aboutToQuit() { - // Main process terminated + // Main process terminated, terminate subprocess with set timeout if (process.state() == QProcess::Running) { process.terminate(); - if (!process.waitForFinished(60000)) { + if (!process.waitForFinished(termTimeout)) { QTextStream(stderr) << "Failed to terminate process!" << endl; } } diff --git a/SMSubProcess.h b/SMSubProcess.h index fa98e06..c03bfeb 100644 --- a/SMSubProcess.h +++ b/SMSubProcess.h @@ -26,11 +26,12 @@ class SMSubProcess : public QObject { Q_OBJECT 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(); private: QProcess process; + int termTimeout; public slots: void aboutToQuit(); diff --git a/SMSubServer.cpp b/SMSubServer.cpp index d411284..d5f843e 100644 --- a/SMSubServer.cpp +++ b/SMSubServer.cpp @@ -55,6 +55,8 @@ void SMSubServer::readyRead() bool isAuthenticated = socket->property("Authenticated").toBool(); while (socket->canReadLine()) { const QByteArray readData = socket->readLine().trimmed(); + + // Only allow commands being sent if authenticated if (likely(isAuthenticated)) { if (readData.startsWith("+dbg")) { socket->setProperty("ReceiveDbgMsg", true); @@ -103,7 +105,9 @@ void SMSubServer::readyRead() } } else { + // Authenticate when token is valid, otherwise disconnect if (unlikely(tokens.contains(QString::fromUtf8(readData)))) { + // Set client as authenticated and add it to vector socket->setProperty("Authenticated", true); socket->write("Login successful!\n"); isAuthenticated = true; @@ -159,6 +163,7 @@ void SMSubServer::writeOutput(const QByteArray &output) void SMSubServer::registerToken(const QString &token) { + // Register temporary token for a secure remote connection tokens << token; QTimer::singleShot(30000, [this, token]() { tokens.removeAll(token); diff --git a/main.cpp b/main.cpp index 4f68766..4ef7316 100644 --- a/main.cpp +++ b/main.cpp @@ -39,7 +39,24 @@ #ifdef Q_OS_UNIX void catchUnixSignals(std::initializer_list quitSignals) { 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(); }; @@ -62,10 +79,10 @@ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setApplicationName("Server Manager Subprocess"); - a.setApplicationVersion("0.2"); + a.setApplicationVersion("0.2.1"); #ifdef Q_OS_UNIX - catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); + catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM}); #endif QCommandLineParser commandLineParser; @@ -95,6 +112,9 @@ int main(int argc, char *argv[]) #endif commandLineParser.addOption(subprocessRemoteSocket); + QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout"); + commandLineParser.addOption(processTimeout); + commandLineParser.process(a); if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) { @@ -102,6 +122,17 @@ int main(int argc, char *argv[]) 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 workingDirectory; 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(); } } @@ -217,7 +259,7 @@ int main(int argc, char *argv[]) localSettings.canRegister = false; } - SMSubProcess subProcess(executable, argumentList, workingDirectory); + SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout); QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput); QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput);