diff --git a/CMakeLists.txt b/CMakeLists.txt index dea9e62..c83979b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -project(smsub LANGUAGES CXX VERSION 0.10.1) +project(smsub LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -18,18 +18,6 @@ else() find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) endif() find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network WebSockets REQUIRED) -set(SMSUB_LIBS Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::WebSockets) - -option(WITH_BOOST "Use Boost library" ON) -if(WITH_BOOST) - find_package(Boost COMPONENTS json REQUIRED) - list(APPEND SMSUB_LIBS - Boost::json - ) - list(APPEND SMSUB_DEFINES - BOOST_JSON - ) -endif() set(SMSUB_SOURCES main.cpp @@ -43,7 +31,11 @@ set(SMSUB_HEADERS SMSubServer.h ) -add_executable(smsub ${SMSUB_HEADERS} ${SMSUB_SOURCES}) -target_compile_definitions(smsub PRIVATE ${SMSUB_DEFINES}) -target_link_libraries(smsub PRIVATE ${SMSUB_LIBS}) +add_executable(smsub + ${SMSUB_HEADERS} + ${SMSUB_SOURCES} +) + +target_link_libraries(smsub PRIVATE Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::WebSockets) + install(TARGETS smsub DESTINATION bin) diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp index 9b19b51..9a67656 100644 --- a/SMSubProcess.cpp +++ b/SMSubProcess.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2024 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -18,79 +18,55 @@ #include #include -#include #include "SMSubProcess.h" #include "smsub.h" +#include -SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout, const bool buffReads, const bool keepAlive) : - termTimeout(termTimeout), buffReads(buffReads), keepAlive(keepAlive) +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); - // manage input channel - process.setInputChannelMode(QProcess::ManagedInputChannel); - - // stdout and stderr in same I/O stream + // stdout and stderr in same IO stream process.setProcessChannelMode(QProcess::MergedChannels); // Connect process signal handlers QObject::connect(&process, &QProcess::readyRead, this, &SMSubProcess::readyRead); QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError); - QObject::connect(&process, &QProcess::started, this, [=]() { - QTextStream(stderr) << "Subprocess started!" << smsub_endl; - emit statusUpdated(true, QDateTime::currentDateTimeUtc().toSecsSinceEpoch()); - }); QObject::connect(&process, QOverload::of(&QProcess::finished), this, [=](int exitCode) { - QTextStream(stderr) << "Subprocess exited!" << smsub_endl; // Exit with the same exit code as the process - emit statusUpdated(false, QDateTime::currentDateTimeUtc().toSecsSinceEpoch()); - if (!keepAlive) - QCoreApplication::exit(exitCode); + emit processStopped(); + QCoreApplication::exit(exitCode); }); } +void SMSubProcess::start() +{ + process.start(QIODevice::ReadWrite); +} + void SMSubProcess::readyRead() { -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl; -#endif // Read process output and emit event - if (buffReads) { - while (process.bytesAvailable()) { -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl; -#endif - const QByteArray readData = process.read(1024); - if (!readData.isEmpty()) - emit outputWritten(readData); - } - } - else { - while (process.canReadLine()) { -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl; -#endif - const QByteArray readData = process.readLine().trimmed(); - emit outputWritten(readData + '\n'); - } + while (process.canReadLine()) { + const QByteArray readData = process.readLine().trimmed(); + emit outputWritten(readData + '\n'); } } void SMSubProcess::processError(QProcess::ProcessError error) { // Handle process errors - if (Q_LIKELY(error == QProcess::FailedToStart)) { + if (likely(error == QProcess::FailedToStart)) { QTextStream(stderr) << "Process failed to start!" << smsub_endl; - if (!keepAlive) - QCoreApplication::exit(1); + QCoreApplication::exit(1); } else if (error == QProcess::UnknownError) { QTextStream(stderr) << "Unknown error occurred!" << smsub_endl; - if (!keepAlive) - QCoreApplication::exit(1); + QCoreApplication::exit(1); } } @@ -105,33 +81,24 @@ void SMSubProcess::aboutToQuit() } } -void SMSubProcess::startProcess() +void SMSubProcess::killProcess() { - // Start process as requested - if (process.state() == QProcess::NotRunning) - process.start(QIODevice::ReadWrite); + // Kill process as requested + if (process.state() == QProcess::Running) { + process.kill(); + } } void SMSubProcess::stopProcess() { // Terminate process as requested - if (process.state() == QProcess::Running) + if (process.state() == QProcess::Running) { process.terminate(); -} - -void SMSubProcess::killProcess() -{ - // Kill process as requested - if (process.state() == QProcess::Running) - process.kill(); + } } void SMSubProcess::writeInput(const QByteArray &input) { -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "Subprocess I/O IN!" << smsub_endl; -#endif // Write input from Unix/IPC socket to process - if (process.state() == QProcess::Running) - process.write(input); + process.write(input); } diff --git a/SMSubProcess.h b/SMSubProcess.h index 0402192..dedd81c 100644 --- a/SMSubProcess.h +++ b/SMSubProcess.h @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2024 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -26,19 +26,17 @@ class SMSubProcess : public QObject { Q_OBJECT public: - SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout = 60000, const bool buffReads = false, const bool keepAlive = false); + SMSubProcess(const QString &executable, const QStringList &arguments, const QString& workingDirectory, const int &termTimeout = 60000); + void start(); private: QProcess process; int termTimeout; - bool buffReads; - bool keepAlive; public slots: void aboutToQuit(); - void startProcess(); - void stopProcess(); void killProcess(); + void stopProcess(); void writeInput(const QByteArray &input); private slots: @@ -47,7 +45,8 @@ private slots: signals: void outputWritten(const QByteArray &output); - void statusUpdated(const bool status, const qint64 time); + void processStopped(); + }; #endif // SMSUBPROCESS_H diff --git a/SMSubServer.cpp b/SMSubServer.cpp index 6ea0b0f..962829a 100644 --- a/SMSubServer.cpp +++ b/SMSubServer.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2024 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -21,12 +21,6 @@ #include #include "SMSubServer.h" #include "smsub.h" -#ifdef BOOST_JSON -#include -#else -#include -#include -#endif SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &socket) : serverSettings(serverSettings) { @@ -38,31 +32,22 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc type = ServerType::Local; server = localServer; - status = false; - startTime = QDateTime::currentDateTimeUtc().toSecsSinceEpoch(); - stopTime = startTime; } SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings) { QWebSocketServer *webSocketServer = new QWebSocketServer(serverName, QWebSocketServer::NonSecureMode, this); -#if QT_VERSION >= 0x060400 - webSocketServer->setSupportedSubprotocols(QStringList() << "smsub" << "smsub_json"); -#endif webSocketServer->listen(QHostAddress::LocalHost, port); QObject::connect(webSocketServer, &QWebSocketServer::newConnection, this, &SMSubServer::newConnection); type = ServerType::WebSocket; server = webSocketServer; - status = false; - startTime = QDateTime::currentDateTimeUtc().toSecsSinceEpoch(); - stopTime = startTime; } bool SMSubServer::isListening() { - if (type == ServerType::Local) { + if (likely(type == ServerType::Local)) { return static_cast(server)->isListening(); } else if (type == ServerType::WebSocket) { @@ -74,13 +59,12 @@ bool SMSubServer::isListening() void SMSubServer::newConnection() { QObject *socket; - if (Q_LIKELY(type == ServerType::Local)) { + if (likely(type == ServerType::Local)) { QLocalSocket *localSocket = static_cast(server)->nextPendingConnection(); QObject::connect(localSocket, &QLocalSocket::readyRead, this, &SMSubServer::lsReadyRead); QObject::connect(localSocket, &QLocalSocket::disconnected, this, &SMSubServer::deleteSocket); localSocket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8()); socket = localSocket; - QTextStream(stderr) << "LocalSocket connected!" << smsub_endl; } else if (type == ServerType::WebSocket) { QWebSocket *webSocket = static_cast(server)->nextPendingConnection(); @@ -88,12 +72,6 @@ void SMSubServer::newConnection() QObject::connect(webSocket, &QWebSocket::disconnected, this, &SMSubServer::deleteSocket); webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8()); socket = webSocket; - QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerAddress().toString(), QString::number(webSocket->peerPort())) << smsub_endl; - -#if QT_VERSION >= 0x060400 - if (webSocket->subprotocol() == "smsub_json") - socket->setProperty("ReceiveJson", true); -#endif } else { // Just for being sure @@ -113,109 +91,57 @@ void SMSubServer::newConnection() bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message) { // Only allow commands being sent if authenticated - const bool isAuthenticated = isVariantTrue(socket->property("Authenticated")); - if (isAuthenticated) { - if (message == "+dbg") { + const bool isAuthenticated = socket->property("Authenticated").toBool(); + if (likely(isAuthenticated)) { + if (message.startsWith("+dbg")) { socket->setProperty("ReceiveDbgMsg", true); - debugOutput(socket, "Debug messages enabled!"); + sendMessage(socket, "Debug messages enabled!\n"); } - else if (message == "-dbg") { - debugOutput(socket, "Debug messages disabled!"); + else if (message.startsWith("-dbg")) { socket->setProperty("ReceiveDbgMsg", false); + sendMessage(socket, "Debug messages disabled!\n"); } - else if (message == "+json") { - socket->setProperty("ReceiveJson", true); - debugOutput(socket, "JSON output enabled!"); - } - else if (message == "-json") { - socket->setProperty("ReceiveJson", false); - debugOutput(socket, "JSON output disabled!"); - } - else if (message == "+log") { + else if (message.startsWith("+log")) { socket->setProperty("ReceiveLog", true); debugOutput(socket, "Log output enabled!"); } - else if (message == "-log") { + else if (message.startsWith("-log")) { socket->setProperty("ReceiveLog", false); debugOutput(socket, "Log output disabled!"); } - else if (message == "+status") { - socket->setProperty("ReceiveStatus", true); - debugOutput(socket, "Status updates enabled!"); - } - else if (message == "-status") { - socket->setProperty("ReceiveStatus", false); - debugOutput(socket, "Status updates disabled!"); - } - else if (message == "+reg") { - if (serverSettings->canRegister) { - QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128) + - QUuid::createUuid().toByteArray(QUuid::Id128); + else if (message.startsWith("+reg")) { + if (likely(serverSettings->canRegister)) { + QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128); authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals); - emit tokenRegistered(authUuid); + emit tokenRegistered(QString::fromUtf8(authUuid)); sendMessage(socket, "Token: " + authUuid + '\n'); } else { sendMessage(socket, "Permission denied!\n"); } } - else if (message == "status") { - if (isVariantTrue(socket->property("ReceiveJson"))) { -#ifdef BOOST_JSON - boost::json::object object; - object["type"] = "status"; - object["status"] = status; - object["start"] = startTime; - object["stop"] = stopTime; - const std::string json = boost::json::serialize(object) + '\n'; - sendMessage(socket, QByteArray::fromRawData(json.data(), json.size())); -#else - QJsonObject object; - object["type"] = "status"; - object["status"] = status; - object["start"] = startTime; - object["stop"] = stopTime; - sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n'); -#endif - } - else { - sendMessage(socket, QString("Status: %1\nLast Start: %2\nLast Stop: %3\n").arg(status ? "on" : "off", QString::number(startTime), QString::number(stopTime)).toUtf8()); - } - } - else if (message == "start") { - emit startRequested(); - debugOutput(socket, "Starting server!"); - } - else if (message == "stop") { - emit stopRequested(); - debugOutput(socket, "Stopping server!"); - } - else if (message == "kill") { + else if (message.startsWith("kill")) { emit killRequested(); debugOutput(socket, "Killing server!"); } - else if (message == "quit") { - QTimer::singleShot(0, qApp, &QCoreApplication::quit); - debugOutput(socket, "Qutting smsub!"); + else if (message.startsWith("stop")) { + emit stopRequested(); + debugOutput(socket, "Stopping server!"); } - else if (message == "wl") { - emit inputWritten("\n"); - debugOutput(socket, "Writing line!"); - } - else if (message.startsWith("wl ")) { + else if (message.startsWith("wl")) { const QByteArray writeData = message.mid(3); emit inputWritten(writeData + '\n'); - debugOutput(socket, "Writing line: " + writeData); + debugOutput(socket, "Write line \"" + writeData + "\"!"); } - else if (message.startsWith("w ")) { + else if (message.startsWith("w")) { const QByteArray writeData = message.mid(2); emit inputWritten(writeData); - debugOutput(socket, "Writing: " + writeData); + debugOutput(socket, "Write \"" + writeData + "\"!"); } } else { // Authenticate when token is valid, otherwise disconnect - if (tokens.contains(message)) { + if (unlikely(tokens.contains(QString::fromUtf8(message)))) { // Set client as authenticated and add it to vector socket->setProperty("Authenticated", true); sendMessage(socket, "Login successful!\n"); @@ -223,7 +149,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message) } else { // Stop receiving data and disconnect socket - if (type == ServerType::Local) { + if (likely(type == ServerType::Local)) { QLocalSocket *localSocket = static_cast(socket); QObject::disconnect(localSocket, &QLocalSocket::readyRead, this, &SMSubServer::lsReadyRead); localSocket->write("Incorrect token!\n"); @@ -242,18 +168,6 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message) return true; } -bool SMSubServer::isVariantTrue(const QVariant &variant) -{ -#if QT_VERSION >= 0x060000 - if (variant.typeId() == QMetaType::Bool) { -#else - if (variant.type() == QVariant::Bool) { -#endif - return variant.toBool(); - } - return false; -} - void SMSubServer::wsMessageReceived(const QByteArray &message) { QWebSocket *socket = static_cast(sender()); @@ -263,13 +177,7 @@ void SMSubServer::wsMessageReceived(const QByteArray &message) void SMSubServer::lsReadyRead() { QLocalSocket *socket = static_cast(sender()); -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "LocalSocket I/O RR!" << smsub_endl; -#endif while (socket->canReadLine()) { -#ifdef SMSUB_IODEBUG - QTextStream(stderr) << "LocalSocket I/O WL!" << smsub_endl; -#endif const QByteArray message = socket->readLine().trimmed(); if (!messageReceived(socket, message)) return; @@ -287,22 +195,10 @@ void SMSubServer::deleteSocket() void SMSubServer::debugOutput(QObject *socket, const QByteArray &message) { // Only send debug messages when the client opted-in - if (isVariantTrue(socket->property("ReceiveDbgMsg"))) { - if (isVariantTrue(socket->property("ReceiveJson"))) { -#ifdef BOOST_JSON - boost::json::object object; - object["type"] = "debug"; - object["message"] = message.toBase64(QByteArray::OmitTrailingEquals).constData(); - const std::string json = boost::json::serialize(object) + '\n'; - sendMessage(socket, QByteArray::fromRawData(json.data(), json.size())); -#else - QJsonObject object; - object["type"] = "debug"; - object["message"] = QString::fromUtf8(message.toBase64(QByteArray::OmitTrailingEquals)); - sendMessage(socket, QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n'); -#endif - } - else { + const QVariant variant = socket->property("ReceiveDbgMsg"); + if (unlikely(variant.type() == QVariant::Bool)) { + bool receiveDbgMsg = variant.toBool(); + if (likely(receiveDbgMsg)) { sendMessage(socket, message + '\n'); } } @@ -311,26 +207,11 @@ void SMSubServer::debugOutput(QObject *socket, const QByteArray &message) void SMSubServer::writeOutput(const QByteArray &output) { // Read process output when client opted-in for log - QByteArray json_output; for (auto it = sockets.constBegin(); it != sockets.constEnd(); it++) { - if (isVariantTrue((*it)->property("ReceiveLog"))) { - if (isVariantTrue((*it)->property("ReceiveJson"))) { - if (json_output.isEmpty()) { -#ifdef BOOST_JSON - boost::json::object object; - object["type"] = "log"; - object["message"] = output.toBase64(QByteArray::OmitTrailingEquals).constData(); - json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n'); -#else - QJsonObject object; - object["type"] = "log"; - object["message"] = QString::fromUtf8(output.toBase64(QByteArray::OmitTrailingEquals)); - json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n'; -#endif - } - sendMessage(*it, json_output); - } - else { + const QVariant variant = (*it)->property("ReceiveLog"); + if (unlikely(variant.type() == QVariant::Bool)) { + bool receiveLog = variant.toBool(); + if (likely(receiveLog)) { sendMessage(*it, output); } } @@ -339,7 +220,7 @@ void SMSubServer::writeOutput(const QByteArray &output) void SMSubServer::sendMessage(QObject *socket, const QByteArray &message) { - if (type == ServerType::Local) { + if (likely(type == ServerType::Local)) { QLocalSocket *localSocket = static_cast(socket); localSocket->write(message); } @@ -349,7 +230,7 @@ void SMSubServer::sendMessage(QObject *socket, const QByteArray &message) } } -void SMSubServer::registerToken(const QByteArray &token) +void SMSubServer::registerToken(const QString &token) { // Register temporary token for a secure remote connection tokens << token; @@ -357,41 +238,3 @@ void SMSubServer::registerToken(const QByteArray &token) tokens.removeAll(token); }); } - -void SMSubServer::statusUpdated(const bool status_, const qint64 time) -{ - status = status_; - status ? (startTime = time) : (stopTime = time); - - QByteArray output, json_output; - for (auto it = sockets.constBegin(); it != sockets.constEnd(); it++) { - if (isVariantTrue((*it)->property("ReceiveStatus"))) { - if (isVariantTrue((*it)->property("ReceiveJson"))) { - if (json_output.isEmpty()) { -#ifdef BOOST_JSON - boost::json::object object; - object["type"] = "status"; - object["status"] = status; - object["start"] = startTime; - object["stop"] = stopTime; - json_output = QByteArray::fromStdString(boost::json::serialize(object) + '\n'); -#else - QJsonObject object; - object["type"] = "status"; - object["status"] = status; - object["start"] = startTime; - object["stop"] = stopTime; - json_output = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n'; -#endif - } - sendMessage(*it, json_output); - } - else { - if (output.isEmpty()) { - output = QString("Status: %1\nLast Start: %2\nLast Stop: %3\n").arg(status ? "on" : "off", QString::number(startTime), QString::number(stopTime)).toUtf8(); - } - sendMessage(*it, json_output); - } - } - } -} diff --git a/SMSubServer.h b/SMSubServer.h index d7f452a..f5f9936 100644 --- a/SMSubServer.h +++ b/SMSubServer.h @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2024 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -44,8 +44,7 @@ public: public slots: void writeOutput(const QByteArray &output); - void registerToken(const QByteArray &token); - void statusUpdated(const bool status, const qint64 time); + void registerToken(const QString &token); private slots: void wsMessageReceived(const QByteArray &message); @@ -57,22 +56,17 @@ private: inline void debugOutput(QObject *socket, const QByteArray &message); inline void sendMessage(QObject *socket, const QByteArray &message); bool messageReceived(QObject *socket, const QByteArray &message); - inline bool isVariantTrue(const QVariant &variant); SMSubServerSettings *serverSettings; QVector sockets; - QVector tokens; - qint64 startTime; - qint64 stopTime; + QVector tokens; ServerType type; QObject *server; - bool status; signals: - void tokenRegistered(const QByteArray &token); + void tokenRegistered(const QString &password); void inputWritten(const QByteArray &input); - void startRequested(); - void stopRequested(); void killRequested(); + void stopRequested(); }; #endif // SMSUBSERVER_H diff --git a/main.cpp b/main.cpp index a3d8eee..1baf24b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2024 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -33,6 +33,7 @@ #ifdef Q_OS_UNIX #include #include "signal.h" +#include "unistd.h" #endif #ifdef Q_OS_UNIX @@ -134,18 +135,15 @@ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setApplicationName("Server Manager Subprocess"); - a.setApplicationVersion("0.10.1"); + a.setApplicationVersion("0.5"); #ifdef Q_OS_UNIX catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM}); #endif bool rportSet = false; - bool autoStart = true; - bool buffReads = false; - bool keepAlive = false; bool timeoutSet = false; - size_t termTimeout = 60000; + int termTimeout = 60000; quint16 rport; QString socket; QString rsocket; @@ -153,28 +151,24 @@ int main(int argc, char *argv[]) QString workingDirectory; QStringList argumentList; - const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE"); - const QByteArray envAutoStart = qgetenv("SMSUB_AUTOSTART"); - const QByteArray envBuffReads = qgetenv("SMSUB_BUFFERED_READS"); - const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE"); - const QByteArray envManifest = qgetenv("SMSUB_JSON"); - const QByteArray envExecutable = qgetenv("SMSUB_EXEC"); - const QByteArray envArguments = qgetenv("SMSUB_ARGS"); - const QByteArray envSocket = qgetenv("SMSUB_SOCK"); - const QByteArray envRemotePort = qgetenv("SMSUB_RPORT"); - const QByteArray envRemoteSocket = qgetenv("SMSUB_RSOCK"); - const QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT"); - const QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR"); + QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE"); + QByteArray envManifest = qgetenv("SMSUB_JSON"); + QByteArray envExecutable = qgetenv("SMSUB_EXEC"); + QByteArray envArguments = qgetenv("SMSUB_ARGS"); + QByteArray envSocket = qgetenv("SMSUB_SOCK"); + QByteArray envRemotePort = qgetenv("SMSUB_RPORT"); + QByteArray envRemoteSocket = qgetenv("SMSUB_RSOCK"); + QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT"); + QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR"); - if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true" || envEnvironmentMode.toLower() == "yes") { - if (envExecutable.isEmpty() && envArguments.isEmpty()) { + if (unlikely(envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true")) { + if (likely(envExecutable.isEmpty() && envArguments.isEmpty())) { QStringList arguments = a.arguments(); - arguments.removeFirst(); executable = arguments.takeFirst(); argumentList = arguments; } else { - if (!envExecutable.isEmpty()) { + if (likely(!envExecutable.isEmpty())) { executable = QString::fromUtf8(envExecutable); } else { @@ -182,7 +176,7 @@ int main(int argc, char *argv[]) return 1; } - if (!envArguments.isEmpty()) { + if (likely(!envArguments.isEmpty())) { argumentList = parseStringArguments(QString::fromUtf8(envArguments)); if (argumentList.empty()) { QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl; @@ -195,7 +189,7 @@ int main(int argc, char *argv[]) } } - if (!envTimeout.isEmpty()) { + if (unlikely(!envTimeout.isEmpty())) { bool ok; const int _termTimeout = envTimeout.toInt(&ok); if (ok) { @@ -208,32 +202,14 @@ int main(int argc, char *argv[]) } } - if (!envAutoStart.isEmpty()) { - if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") { - autoStart = false; - } - } - - if (!envBuffReads.isEmpty()) { - if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") { - buffReads = true; - } - } - - if (!envKeepAlive.isEmpty()) { - if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { - keepAlive = true; - } - } - - if (!envWorkDir.isEmpty()) { + if (unlikely(!envWorkDir.isEmpty())) { workingDirectory = QString::fromUtf8(envWorkDir); } else { workingDirectory = QFileInfo(executable).absolutePath(); } - if (!envSocket.isEmpty()) { + if (likely(!envSocket.isEmpty())) { socket = QString::fromUtf8(envSocket); } else { @@ -245,21 +221,20 @@ int main(int argc, char *argv[]) return 1; } - if (!envRemoteSocket.isEmpty()) { + if (unlikely(!envRemoteSocket.isEmpty())) { rsocket = QString::fromUtf8(envRemoteSocket); } - if (!envRemotePort.isEmpty()) { + if (unlikely(!envRemotePort.isEmpty())) { bool ok; - const quint16 _rport = envRemotePort.toUShort(&ok); - if (ok) { - rport = _rport; - rportSet = true; - } - else { + rport = envRemotePort.toUShort(&ok); + if (!ok) { QTextStream(stderr) << "WebSockets port is not valid in environment!" << smsub_endl; return 1; } + else { + rportSet = true; + } } } else { @@ -293,37 +268,31 @@ int main(int argc, char *argv[]) #endif commandLineParser.addOption(subprocessRemoteSocket); - QCommandLineOption processAutoStart("autostart", "SMSub autostart mode.", "autostart"); - commandLineParser.addOption(processAutoStart); - - QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode.", "keepalive"); - commandLineParser.addOption(processKeepAlive); - QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout"); commandLineParser.addOption(processTimeout); commandLineParser.process(a); - if (commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable) || + if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable) || !envManifest.isEmpty() && !envExecutable.isEmpty() || commandLineParser.isSet(processManifest) && !envExecutable.isEmpty() || - !envManifest.isEmpty() && commandLineParser.isSet(processExecutable)) { + !envManifest.isEmpty() && commandLineParser.isSet(processExecutable))) { QTextStream(stderr) << "You can't define a Process executable and a JSON process manifest at the same time!" << smsub_endl; return 1; } - if (commandLineParser.isSet(processManifest) && commandLineParser.isSet(processArguments) || + if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processArguments) || !envManifest.isEmpty() && !envArguments.isEmpty() || commandLineParser.isSet(processManifest) && !envArguments.isEmpty() || - !envManifest.isEmpty() && commandLineParser.isSet(processArguments)) { - QTextStream(stderr) << "You can't define Process arguments and a JSON process manifest at the same time!" << smsub_endl; + !envManifest.isEmpty() && commandLineParser.isSet(processArguments))) { + QTextStream(stderr) << "You can't define a Process arguments and a JSON process manifest at the same time!" << smsub_endl; return 1; } - if (commandLineParser.isSet(subprocessRemotePort) && commandLineParser.isSet(subprocessRemoteSocket) || + if (unlikely(commandLineParser.isSet(subprocessRemotePort) && commandLineParser.isSet(subprocessRemoteSocket) || !envRemotePort.isEmpty() && !envRemoteSocket.isEmpty() || commandLineParser.isSet(subprocessRemotePort) && !envRemoteSocket.isEmpty() || - !envRemotePort.isEmpty() && commandLineParser.isSet(subprocessRemoteSocket)) { + !envRemotePort.isEmpty() && commandLineParser.isSet(subprocessRemoteSocket))) { #ifdef Q_OS_WIN QTextStream(stderr) << "You can't define a WebSockets port and a IPC socket at same time!" << smsub_endl; #else @@ -332,9 +301,9 @@ int main(int argc, char *argv[]) return 1; } - if (commandLineParser.isSet(processTimeout)) { + if (unlikely(commandLineParser.isSet(processTimeout))) { bool ok; - const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok, 10); + const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok); if (ok) { termTimeout = _termTimeout; timeoutSet = true; @@ -344,9 +313,9 @@ int main(int argc, char *argv[]) return 1; } } - else if (!envTimeout.isEmpty()) { + else if (unlikely(!envTimeout.isEmpty())) { bool ok; - const int _termTimeout = envTimeout.toInt(&ok, 10); + const int _termTimeout = envTimeout.toInt(&ok); if (ok) { termTimeout = _termTimeout; timeoutSet = true; @@ -357,44 +326,14 @@ int main(int argc, char *argv[]) } } - if (commandLineParser.isSet(processExecutable)) { + if (unlikely(commandLineParser.isSet(processExecutable))) { executable = commandLineParser.value(processExecutable); } - else if (!envExecutable.isEmpty()) { + else if (unlikely(!envExecutable.isEmpty())) { executable = QString::fromUtf8(envExecutable); } - if (commandLineParser.isSet(processAutoStart)) { - const QString claAutoStart = commandLineParser.value(processAutoStart); - if (claAutoStart == "0" || claAutoStart.toLower() == "false" || claAutoStart.toLower() == "no") { - autoStart = false; - } - } - else if (!envAutoStart.isEmpty()) { - if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") { - autoStart = false; - } - } - - if (!envBuffReads.isEmpty()) { - if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") { - buffReads = true; - } - } - - if (commandLineParser.isSet(processKeepAlive)) { - const QString claKeepAlive = commandLineParser.value(processKeepAlive); - if (claKeepAlive == "1" || claKeepAlive.toLower() == "true" || claKeepAlive.toLower() == "yes") { - keepAlive = true; - } - } - else if (!envKeepAlive.isEmpty()) { - if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { - keepAlive = true; - } - } - - if (!envWorkDir.isEmpty()) { + if (unlikely(!envWorkDir.isEmpty())) { workingDirectory = QString::fromUtf8(envWorkDir); } else { @@ -402,23 +341,23 @@ int main(int argc, char *argv[]) } QString manifestPath; - if (commandLineParser.isSet(processManifest)) { + if (likely(commandLineParser.isSet(processManifest))) { manifestPath = commandLineParser.value(processManifest); } else if (!envManifest.isEmpty()) { manifestPath = QString::fromUtf8(envManifest); } - if (!manifestPath.isEmpty()) { + if (likely(!manifestPath.isEmpty())) { QFile manifestFile(manifestPath); - if (manifestFile.open(QIODevice::ReadOnly)) { + if (likely(manifestFile.open(QIODevice::ReadOnly))) { const QByteArray jsonData = manifestFile.readAll(); QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData); QJsonObject jsonObject = jsonDocument.object(); - if (jsonObject.contains("Executable")) { + if (likely(jsonObject.contains("Executable"))) { const QJsonValue jsonExecutable = jsonObject.value("Executable"); - if (!jsonExecutable.isString()) { + if (unlikely(!jsonExecutable.isString())) { QTextStream(stderr) << "Executable is not a string in manifest, aborting!" << smsub_endl; manifestFile.close(); return 1; @@ -431,29 +370,9 @@ int main(int argc, char *argv[]) return 1; } - if (jsonObject.contains("AutoStart")) { - const QJsonValue jsonAutoStart = jsonObject.value("AutoStart"); - if (!jsonAutoStart.isBool()) { - QTextStream(stderr) << "AutoStart is not a bool in manifest, aborting!" << smsub_endl; - manifestFile.close(); - return 1; - } - autoStart = jsonAutoStart.toBool(); - } - - if (jsonObject.contains("KeepAlive")) { - const QJsonValue jsonKeepAlive = jsonObject.value("KeepAlive"); - if (!jsonKeepAlive.isBool()) { - QTextStream(stderr) << "KeepAlive is not a bool in manifest, aborting!" << smsub_endl; - manifestFile.close(); - return 1; - } - keepAlive = jsonKeepAlive.toBool(); - } - - if (jsonObject.contains("WorkingDirectory")) { + if (likely(jsonObject.contains("WorkingDirectory"))) { const QJsonValue jsonWorkingDirectory = jsonObject.value("WorkingDirectory"); - if (!jsonWorkingDirectory.isString()) { + if (unlikely(!jsonWorkingDirectory.isString())) { QTextStream(stderr) << "Working Directory is not a string in manifest, aborting!" << smsub_endl; manifestFile.close(); return 1; @@ -461,9 +380,9 @@ int main(int argc, char *argv[]) workingDirectory = jsonWorkingDirectory.toString(); } - if (jsonObject.contains("Arguments")) { + if (likely(jsonObject.contains("Arguments"))) { const QJsonValue jsonArguments = jsonObject.value("Arguments"); - if (jsonArguments.isArray()) { + if (likely(jsonArguments.isArray())) { const QJsonArray jsonArray = jsonArguments.toArray(); for (auto it = jsonArray.constBegin(); it != jsonArray.constEnd(); it++) { argumentList << it->toString(); @@ -476,9 +395,9 @@ int main(int argc, char *argv[]) } } - if (!timeoutSet && jsonObject.contains("TerminationTimeout")) { + if (unlikely(!timeoutSet && jsonObject.contains("TerminationTimeout"))) { const QJsonValue jsonTimeout = jsonObject.value("TerminationTimeout"); - if (!jsonTimeout.isDouble()) { + if (unlikely(!jsonTimeout.isDouble())) { termTimeout = qRound(jsonTimeout.toDouble()); } else { @@ -490,14 +409,14 @@ int main(int argc, char *argv[]) manifestFile.close(); } } - else if (commandLineParser.isSet(processArguments)) { + else if (unlikely(commandLineParser.isSet(processArguments))) { argumentList = parseStringArguments(commandLineParser.value(processArguments)); if (argumentList.empty()) { QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl; return 1; } } - else if (!envArguments.isEmpty()) { + else if (unlikely(!envArguments.isEmpty())) { argumentList = parseStringArguments(QString::fromUtf8(envArguments)); if (argumentList.empty()) { QTextStream(stderr) << "Arguments can't be parsed properly!" << smsub_endl; @@ -505,7 +424,7 @@ int main(int argc, char *argv[]) } } - if (commandLineParser.isSet(subprocessSocket)) { + if (likely(commandLineParser.isSet(subprocessSocket))) { socket = commandLineParser.value(subprocessSocket); } else if (!envSocket.isEmpty()) { @@ -520,35 +439,33 @@ int main(int argc, char *argv[]) return 1; } - if (commandLineParser.isSet(subprocessRemoteSocket)) { + if (unlikely(commandLineParser.isSet(subprocessRemoteSocket))) { rsocket = commandLineParser.value(subprocessRemoteSocket); } - else if (!envRemoteSocket.isEmpty()) { + else if (unlikely(!envRemoteSocket.isEmpty())) { rsocket = QString::fromUtf8(envRemoteSocket); } - if (commandLineParser.isSet(subprocessRemotePort)) { + if (unlikely(commandLineParser.isSet(subprocessRemotePort))) { bool ok; - const quint16 _rport = commandLineParser.value(subprocessRemotePort).toUShort(&ok); - if (ok) { - rport = _rport; - rportSet = true; - } - else { + rport = commandLineParser.value(subprocessRemotePort).toUShort(&ok); + if (!ok) { QTextStream(stderr) << "WebSockets port is not valid in arguments!" << smsub_endl; return 1; } + else { + rportSet = true; + } } else if (!envRemotePort.isEmpty()) { bool ok; - const quint16 _rport = envRemotePort.toUShort(&ok); - if (ok) { - rport = _rport; - rportSet = true; + rport = envRemotePort.toUShort(&ok); + if (!ok) { + QTextStream(stderr) << "WebSockets port is not valid in environment!" << smsub_endl; + return 1; } else { - QTextStream(stderr) << "WebSockets port is not valid in arguments!" << smsub_endl; - return 1; + rportSet = true; } } } @@ -557,7 +474,7 @@ int main(int argc, char *argv[]) localSettings.isLocal = true; SMSubServer subLocal(&localSettings, socket); - if (!subLocal.isListening()) { + if (unlikely(!subLocal.isListening())) { #ifdef Q_OS_WIN QTextStream(stderr) << "Failed to start local IPC socket!" << smsub_endl; #else @@ -566,15 +483,15 @@ int main(int argc, char *argv[]) return 1; } - SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, buffReads, keepAlive); + SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout); SMSubServerSettings remoteSettings; remoteSettings.canRegister = false; remoteSettings.isLocal = false; - if (!rsocket.isEmpty()) { + if (unlikely(!rsocket.isEmpty())) { SMSubServer *subRemote = new SMSubServer(&remoteSettings, rsocket); - if (!subRemote->isListening()) { + if (unlikely(!subRemote->isListening())) { #ifdef Q_OS_WIN QTextStream(stderr) << "Failed to start remote IPC socket!" << smsub_endl; #else @@ -585,43 +502,34 @@ int main(int argc, char *argv[]) localSettings.canRegister = true; QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken); QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput); - QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated); QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); - QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); } - else if (rportSet) { + else if (unlikely(rportSet)) { SMSubServer *subRemote = new SMSubServer(&remoteSettings, QString(), rport); - if (!subRemote->isListening()) { + if (unlikely(!subRemote->isListening())) { QTextStream(stderr) << "Failed to start remote WebSockets server!" << smsub_endl; return 1; } localSettings.canRegister = true; QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken); QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput); - QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated); QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); - QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); } else { localSettings.canRegister = false; } QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput); - QObject::connect(&subProcess, &SMSubProcess::statusUpdated, &subLocal, &SMSubServer::statusUpdated); QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(&subLocal, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); - QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit); - if (autoStart) - subProcess.startProcess(); - - QTextStream(stderr) << QString("SMSub Version %1 initialized!").arg(QCoreApplication::applicationVersion()) << smsub_endl; + subProcess.start(); return a.exec(); } diff --git a/smsub.h b/smsub.h index 9b93a6b..d05e8bc 100644 --- a/smsub.h +++ b/smsub.h @@ -1,6 +1,6 @@ /***************************************************************************** * smsub Server Manager Subprocess -* Copyright (C) 2020-2023 Syping +* Copyright (C) 2020-2021 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -20,7 +20,23 @@ #define SMSUB_H #include -#if QT_VERSION >= 0x050F00 +#ifndef SMSUB_WITHOUT_EXPECT +#ifndef likely +#define likely(x) __builtin_expect((x),1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect((x),0) +#endif +#else +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif +#endif + +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #define smsub_endl Qt::endl #else #define smsub_endl endl