diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 9098a258e7..a0304acad9 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +// #include #include #include #include @@ -41,7 +41,7 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment; int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); -AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) : +AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), _localASPortSharedMem(NULL), @@ -58,8 +58,11 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) : DependencyManager::registerInheritance(); auto addressManager = DependencyManager::set(); auto nodeList = DependencyManager::set(NodeType::Unassigned); - auto avatarHashMap = DependencyManager::set(); + // auto avatarHashMap = DependencyManager::set(); + // make up a uuid for this child so the parent can tell us apart. This id will be changed + // when the domain server hands over an assignment. + QUuid nodeUUID = QUuid::createUuid(); nodeList->setSessionUUID(nodeUUID); // setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us @@ -139,11 +142,37 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) : // Create Singleton objects on main thread NetworkAccessManager::getInstance(); + // DependencyManager::get(); setUpStatsToMonitor(); } +void AssignmentClient::stopAssignmentClient() { + + // QList threads = QObject::findChildren (); + // foreach(QThread *thread, threads) { // or FileUploader* fileuploader, fileUploaders_ ? + // qDebug() << "thread " << thread->currentThreadId(); + // } + + qDebug() << "Exiting."; + + _requestTimer.stop(); + _statsTimerACM.stop(); + + + // DependencyManager::get()->disconnect(); + // DependencyManager::get()->disconnectNotify(); + // DependencyManager::get()->disconnect(); + // DependencyManager::get()->disconnectNotify(); + + // DependencyManager::destroy(); + // DependencyManager::destroy(); + + quit(); +} + + void AssignmentClient::setUpStatsToMonitor() { // Figure out the address to send out stats to quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT; @@ -249,15 +278,12 @@ void AssignmentClient::readPendingDatagrams() { qDebug() << "Received an assignment that could not be unpacked. Re-requesting."; } } else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) { - qDebug() << "Network told me to exit"; - quit(); + qDebug() << "Network told me to exit."; + emit stopAssignmentClient(); } else { - qDebug() << "punt"; // have the NodeList attempt to handle it nodeList->processNodeData(senderSockAddr, receivedPacket); } - } else { - qDebug() << "packetVersionAndHashMatch said no"; } } } diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 7f0f16e6d6..e105309e10 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -21,7 +21,7 @@ class QSharedMemory; class AssignmentClient : public QCoreApplication { Q_OBJECT public: - AssignmentClient(int &argc, char **argv, QUuid nodeUUID); + AssignmentClient(int &argc, char **argv); static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; } private slots: @@ -30,6 +30,7 @@ private slots: void assignmentCompleted(); void handleAuthenticationRequest(); void sendStatsPacketToACM(); + void stopAssignmentClient(); private: void setUpStatsToMonitor(); diff --git a/assignment-client/src/AssignmentClientApp.cpp b/assignment-client/src/AssignmentClientApp.cpp index 4541732e2c..8848b59c49 100644 --- a/assignment-client/src/AssignmentClientApp.cpp +++ b/assignment-client/src/AssignmentClientApp.cpp @@ -21,7 +21,7 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : - QApplication(argc, argv) + QCoreApplication(argc, argv) { # ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); @@ -40,9 +40,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : const QCommandLineOption numChildsOption("n", "number of children to fork", "child-count"); parser.addOption(numChildsOption); - const QCommandLineOption idOption("i", "assignment client id", "uuid"); - parser.addOption(idOption); - if (!parser.parse(QCoreApplication::arguments())) { qCritical() << parser.errorText() << endl; parser.showHelp(); @@ -54,27 +51,16 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) : Q_UNREACHABLE(); } - if (parser.isSet(numChildsOption) && parser.isSet(idOption)) { - qCritical() << "using both -i and -n doesn't make sense."; - parser.showHelp(); - Q_UNREACHABLE(); - } - unsigned int numForks = 0; if (parser.isSet(numChildsOption)) { numForks = parser.value(numChildsOption).toInt(); } - QUuid nodeUUID = QUuid::createUuid(); - if (parser.isSet(idOption)) { - nodeUUID = QUuid(parser.value(idOption)); - } - if (numForks) { AssignmentClientMonitor monitor(argc, argv, numForks); monitor.exec(); } else { - AssignmentClient client(argc, argv, nodeUUID); + AssignmentClient client(argc, argv); client.exec(); } } diff --git a/assignment-client/src/AssignmentClientApp.h b/assignment-client/src/AssignmentClientApp.h index 6c91fa06a3..09952ad19c 100644 --- a/assignment-client/src/AssignmentClientApp.h +++ b/assignment-client/src/AssignmentClientApp.h @@ -11,7 +11,7 @@ #include -class AssignmentClientApp : public QApplication { +class AssignmentClientApp : public QCoreApplication { Q_OBJECT public: AssignmentClientApp(int argc, char* argv[]); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 831d50c134..94975b0a4d 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -20,6 +20,7 @@ #include "AssignmentClientMonitor.h" #include "PacketHeaders.h" +#include "SharedUtil.h" const char* NUM_FORKS_PARAMETER = "-n"; @@ -70,85 +71,49 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const u AssignmentClientMonitor::~AssignmentClientMonitor() { stopChildProcesses(); - - foreach (AssignmentClientChildData* childStatus, _childStatus) { - delete childStatus; - } } - - void AssignmentClientMonitor::stopChildProcesses() { - - QList >::Iterator it = _childProcesses.begin(); - while (it != _childProcesses.end()) { - if (!it->isNull()) { - qDebug() << "Monitor is terminating child process" << it->data(); - - // don't re-spawn this child when it goes down - disconnect(it->data(), 0, this, 0); - - it->data()->terminate(); - it->data()->waitForFinished(); - } - - it = _childProcesses.erase(it); - } + auto nodeList = DependencyManager::get(); + + nodeList->eachNode([&](const SharedNodePointer& node){ + qDebug() << "asking child" << node->getUUID() << "to exit."; + node->activateLocalSocket(); + QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket()); + }); } void AssignmentClientMonitor::spawnChildClient() { QProcess *assignmentClient = new QProcess(this); - _childProcesses.append(QPointer(assignmentClient)); - - QUuid childUUID = QUuid::createUuid(); - - // create a Node for this child. this is done so we can idenitfy packets from unknown children - DependencyManager::get()->addOrUpdateNode - (childUUID, NodeType::Unassigned, HifiSockAddr("localhost", 0), HifiSockAddr("localhost", 0), false); - // make sure that the output from the child process appears in our output assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels); - QStringList idArgs = QStringList() << "-i" << childUUID.toString(); - assignmentClient->start(applicationFilePath(), _childArguments + idArgs); - - // link the child processes' finished slot to our childProcessFinished slot - connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(childProcessFinished(int, QProcess::ExitStatus))); - + assignmentClient->start(applicationFilePath(), _childArguments); qDebug() << "Spawned a child client with PID" << assignmentClient->pid(); } -void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - qDebug("Replacing dead child assignment client with a new one"); - - // remove the old process from our list of child processes - qDebug() << "need to remove" << QPointer(qobject_cast(sender())); - _childProcesses.removeOne(QPointer(qobject_cast(sender()))); - - spawnChildClient(); -} - - void AssignmentClientMonitor::checkSpares() { - qDebug() << "check spares:"; - - QString aSpareId = ""; + auto nodeList = DependencyManager::get(); + QUuid aSpareId = ""; unsigned int spareCount = 0; - QHash::const_iterator i = _childStatus.constBegin(); - while (i != _childStatus.constEnd()) { - qDebug() << " " << i.key() << i.value()->getChildType(); - if (i.value()->getChildType() == "none") { - spareCount ++; - aSpareId = i.key(); - } - ++i; - } + nodeList->removeSilentNodes(); - qDebug() << "spare count is" << spareCount; + qDebug() << "check spares:"; + + nodeList->eachNode([&](const SharedNodePointer& node){ + AssignmentClientChildData *childData = static_cast(node->getLinkedData()); + qDebug() << " " << node->getUUID() << childData->getChildType(); + if (childData->getChildType() == "none") { + spareCount ++; + aSpareId = node->getUUID(); + } + }); + + qDebug() << " spare count is" << spareCount; if (spareCount < 1) { qDebug() << "FORK"; @@ -156,13 +121,16 @@ void AssignmentClientMonitor::checkSpares() { } if (spareCount > 1) { - qDebug() << "KILL"; + // kill aSpareId + qDebug() << "asking child" << aSpareId << "to exit."; + SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId); + childNode->activateLocalSocket(); + QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + nodeList->writeUnverifiedDatagram(diePacket, childNode); } } - - void AssignmentClientMonitor::readPendingDatagrams() { auto nodeList = DependencyManager::get(); @@ -176,16 +144,21 @@ void AssignmentClientMonitor::readPendingDatagrams() { if (nodeList->packetVersionAndHashMatch(receivedPacket)) { if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) { - QUuid packetUUID = uuidFromPacketHeader(receivedPacket); - // qDebug() << "packetUUID = " << packetUUID; - SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket); if (!matchingNode) { - qDebug() << "got packet from unknown child, id =" << packetUUID.toString(); - // tell unknown assignment-client child to exit. - QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); - nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr); + // XXX only do this if from local machine + if (!packetUUID.isNull()) { + matchingNode = DependencyManager::get()->addOrUpdateNode + (packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false); + AssignmentClientChildData *childData = new AssignmentClientChildData("unknown"); + matchingNode->setLinkedData(childData); + } else { + // tell unknown assignment-client child to exit. + qDebug() << "asking unknown child to exit."; + QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode); + nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr); + } } if (matchingNode) { @@ -195,25 +168,18 @@ void AssignmentClientMonitor::readPendingDatagrams() { // push past the packet header QDataStream packetStream(receivedPacket); packetStream.skipRawData(numBytesForPacketHeader(receivedPacket)); - + // decode json QVariantMap unpackedVariantMap; - packetStream >> unpackedVariantMap; - QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap); - // qDebug() << "ACM got stats packet, id =" << packetUUID.toString() - // << "type =" << unpackedStatsJSON["assignment_type"]; - - QString key(QString(packetUUID.toString())); - if (_childStatus.contains(key)) { - delete _childStatus[ key ]; - } - + // get child's assignment type out of the decoded json QString childType = unpackedStatsJSON["assignment_type"].toString(); - auto childStatus = new AssignmentClientChildData(childType); - _childStatus[ key ] = childStatus; - + AssignmentClientChildData *childData = + static_cast(matchingNode->getLinkedData()); + childData->setChildType(childType); + // note when this child talked + matchingNode->setLastHeardMicrostamp(usecTimestampNow()); } } else { // have the NodeList attempt to handle it diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 75d2296533..a91dfa93cc 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -15,21 +15,25 @@ #include #include #include +#include #include extern const char* NUM_FORKS_PARAMETER; -class AssignmentClientChildData { +class AssignmentClientChildData : public NodeData { public: AssignmentClientChildData(QString childType); ~AssignmentClientChildData(); QString getChildType() { return _childType; } + void setChildType(QString childType) { _childType = childType; } + + // implement parseData to return 0 so we can be a subclass of NodeData + int parseData(const QByteArray& packet) { return 0; } private: QString _childType; - // ... timestamp }; @@ -41,17 +45,15 @@ public: void stopChildProcesses(); private slots: - void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); + // void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void readPendingDatagrams(); void checkSpares(); private: void spawnChildClient(); - QList > _childProcesses; + // QList > _childProcesses; QStringList _childArguments; - QHash _childStatus; - QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children }; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 9bcdcbe9a4..f67abdca2b 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -76,7 +76,7 @@ const QString AddressManager::currentPath(bool withOrientation) const { pathString += "/" + orientationString; } else { qDebug() << "Cannot add orientation to path without a getter for position." - << "Call AdressManager::setOrientationGetter to pass a function that will return a glm::quat"; + << "Call AddressManager::setOrientationGetter to pass a function that will return a glm::quat"; } } @@ -84,7 +84,7 @@ const QString AddressManager::currentPath(bool withOrientation) const { return pathString; } else { qDebug() << "Cannot create address path without a getter for position." - << "Call AdressManager::setPositionGetter to pass a function that will return a const glm::vec3&"; + << "Call AddressManager::setPositionGetter to pass a function that will return a const glm::vec3&"; return QString(); } }