add TerminationTimeout timeout options

This commit is contained in:
Syping 2020-09-19 00:19:39 +02:00
parent b34482ae97
commit 2af86f0524
4 changed files with 64 additions and 11 deletions

View file

@ -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<int>::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;
}
}

View file

@ -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();

View file

@ -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);

View file

@ -39,7 +39,24 @@
#ifdef Q_OS_UNIX
void catchUnixSignals(std::initializer_list<int> 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);