From cb6f7a45f88ad9283aed1495804fd620d8dd3dd6 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 8 Apr 2019 15:30:05 -0700 Subject: [PATCH] Case 819 - Add min-listen-port command line parameter to assignment monitor This will allow users to specify a port range for assignment client UDP ports, allowing easier port forwarding, etc. --- assignment-client/src/AssignmentClientApp.cpp | 13 ++++++- assignment-client/src/AssignmentClientApp.h | 1 + .../src/AssignmentClientMonitor.cpp | 38 ++++++++++++++++--- .../src/AssignmentClientMonitor.h | 10 +++-- 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index acfbb8571c..0b2f4c9295 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -64,6 +64,10 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : "UDP port for this assignment client (or monitor)", "port"); parser.addOption(portOption); + const QCommandLineOption minChildListenPort(ASSIGNMENT_MONITOR_MIN_CHILDREN_LISTEN_PORT_OPTION, + "Minimum UDP listen port", "port"); + parser.addOption(minChildListenPort); + const QCommandLineOption walletDestinationOption(ASSIGNMENT_WALLET_DESTINATION_ID_OPTION, "set wallet destination", "wallet-uuid"); parser.addOption(walletDestinationOption); @@ -195,6 +199,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : assignmentServerPort = parser.value(assignmentServerPortOption).toInt(); } + quint16 childMinListenPort = INVALID_PORT; + if (argumentVariantMap.contains(ASSIGNMENT_MONITOR_MIN_CHILDREN_LISTEN_PORT_OPTION)) { + childMinListenPort = argumentVariantMap.value(ASSIGNMENT_MONITOR_MIN_CHILDREN_LISTEN_PORT_OPTION).toUInt(); + } + // check for an overidden listen port quint16 listenPort = 0; if (argumentVariantMap.contains(ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION)) { @@ -234,8 +243,8 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : if (numForks || minForks || maxForks) { AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks, - requestAssignmentType, assignmentPool, - listenPort, walletUUID, assignmentServerHostname, + requestAssignmentType, assignmentPool, listenPort, + childMinListenPort, walletUUID, assignmentServerHostname, assignmentServerPort, httpStatusPort, logDirectory); monitor->setParent(this); connect(this, &QCoreApplication::aboutToQuit, monitor, &AssignmentClientMonitor::aboutToQuit); diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index 37d3b9cc1d..1b50922980 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -20,6 +20,7 @@ const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION = "p"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; +const QString ASSIGNMENT_MONITOR_MIN_CHILDREN_LISTEN_PORT_OPTION = "min-listen-port"; const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "server-port"; const QString ASSIGNMENT_NUM_FORKS_OPTION = "n"; const QString ASSIGNMENT_MIN_FORKS_OPTION = "min"; diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index fefed6e143..c662ffeb03 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -40,7 +40,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, QString assignmentPool, - quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, + quint16 listenPort, quint16 childMinListenPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory) : _httpManager(QHostAddress::LocalHost, httpStatusServerPort, "", this), _numAssignmentClientForks(numAssignmentClientForks), @@ -48,6 +48,7 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen _maxAssignmentClientForks(maxAssignmentClientForks), _requestAssignmentType(requestAssignmentType), _assignmentPool(assignmentPool), + _childMinListenPort(childMinListenPort), _walletUUID(walletUUID), _assignmentServerHostname(assignmentServerHostname), _assignmentServerPort(assignmentServerPort) @@ -100,8 +101,13 @@ void AssignmentClientMonitor::simultaneousWaitOnChildren(int waitMsecs) { } } -void AssignmentClientMonitor::childProcessFinished(qint64 pid, int exitCode, QProcess::ExitStatus exitStatus) { - auto message = "Child process " + QString::number(pid) + " has %1 with exit code " + QString::number(exitCode) + "."; +void AssignmentClientMonitor::childProcessFinished(qint64 pid, quint16 listenPort, int exitCode, QProcess::ExitStatus exitStatus) { + auto message = "Child process " + QString::number(pid) + " on port " + QString::number(listenPort) + + "has %1 with exit code " + QString::number(exitCode) + "."; + + if (listenPort != INVALID_PORT) { + _childListenPorts.remove(listenPort); + } if (_childProcesses.remove(pid)) { message.append(" Removed from internal map."); @@ -153,6 +159,23 @@ void AssignmentClientMonitor::aboutToQuit() { void AssignmentClientMonitor::spawnChildClient() { QProcess* assignmentClient = new QProcess(this); + quint16 listenPort = INVALID_PORT; + // allocate a port + + if (_childMinListenPort != INVALID_PORT) { + for (listenPort = _childMinListenPort; _childListenPorts.contains(listenPort); listenPort++) { + if (_maxAssignmentClientForks && + (listenPort >= _maxAssignmentClientForks + _childMinListenPort)) { + listenPort = INVALID_PORT; + qDebug() << "Insufficient listen ports"; + break; + } + } + } + if (listenPort != INVALID_PORT) { + _childListenPorts.insert(listenPort); + } + // unparse the parts of the command-line that the child cares about QStringList _childArguments; if (_assignmentPool != "") { @@ -176,6 +199,11 @@ void AssignmentClientMonitor::spawnChildClient() { _childArguments.append(QString::number(_requestAssignmentType)); } + if (listenPort != INVALID_PORT) { + _childArguments.append("-" + ASSIGNMENT_CLIENT_LISTEN_PORT_OPTION); + _childArguments.append(QString::number(listenPort)); + } + // tell children which assignment monitor port to use // for now they simply talk to us on localhost _childArguments.append("--" + ASSIGNMENT_CLIENT_MONITOR_PORT_OPTION); @@ -247,8 +275,8 @@ void AssignmentClientMonitor::spawnChildClient() { auto pid = assignmentClient->processId(); // make sure we hear that this process has finished when it does connect(assignmentClient, static_cast(&QProcess::finished), - this, [this, pid](int exitCode, QProcess::ExitStatus exitStatus) { - childProcessFinished(pid, exitCode, exitStatus); + this, [this, listenPort, pid](int exitCode, QProcess::ExitStatus exitStatus) { + childProcessFinished(pid, listenPort, exitCode, exitStatus); }); qDebug() << "Spawned a child client with PID" << assignmentClient->processId(); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 5e32c50e0d..f5355476b7 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -37,14 +37,15 @@ class AssignmentClientMonitor : public QObject, public HTTPRequestHandler { public: AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks, const unsigned int maxAssignmentClientForks, Assignment::Type requestAssignmentType, - QString assignmentPool, quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname, - quint16 assignmentServerPort, quint16 httpStatusServerPort, QString logDirectory); + QString assignmentPool, quint16 listenPort, quint16 childMinListenPort, QUuid walletUUID, + QString assignmentServerHostname, quint16 assignmentServerPort, quint16 httpStatusServerPort, + QString logDirectory); ~AssignmentClientMonitor(); void stopChildProcesses(); private slots: void checkSpares(); - void childProcessFinished(qint64 pid, int exitCode, QProcess::ExitStatus exitStatus); + void childProcessFinished(qint64 pid, quint16 port, int exitCode, QProcess::ExitStatus exitStatus); void handleChildStatusPacket(QSharedPointer message); bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override; @@ -75,6 +76,9 @@ private: QMap _childProcesses; + quint16 _childMinListenPort; + QSet _childListenPorts; + bool _wantsChildFileLogging { false }; };