diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 95c6bc1efc..9db84055f7 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -34,7 +34,6 @@ namespace Setting { DependencyManager::destroy(); // - globalManager->deleteLater(); globalManager.reset(); // quit the settings manager thread and wait on it to make sure it's gone @@ -72,9 +71,9 @@ namespace Setting { globalManager = DependencyManager::set(); - QObject::connect(globalManager.data(), SIGNAL(destroyed()), thread, SLOT(quit())); QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer())); QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater())); globalManager->moveToThread(thread); thread->start(); qCDebug(shared) << "Settings thread started."; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index a077efc335..cf0e25a757 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -10,3 +10,6 @@ set_target_properties(vhacd-util PROPERTIES FOLDER "Tools") add_subdirectory(ice-client) set_target_properties(ice-client PROPERTIES FOLDER "Tools") + +add_subdirectory(ac-client) +set_target_properties(ac-client PROPERTIES FOLDER "Tools") diff --git a/tools/ac-client/CMakeLists.txt b/tools/ac-client/CMakeLists.txt new file mode 100644 index 0000000000..9e623b02e9 --- /dev/null +++ b/tools/ac-client/CMakeLists.txt @@ -0,0 +1,3 @@ +set(TARGET_NAME ac-client) +setup_hifi_project(Core Widgets) +link_hifi_libraries(shared networking) diff --git a/tools/ac-client/src/ACClientApp.cpp b/tools/ac-client/src/ACClientApp.cpp new file mode 100644 index 0000000000..dad0a6d617 --- /dev/null +++ b/tools/ac-client/src/ACClientApp.cpp @@ -0,0 +1,252 @@ +// +// ACClientApp.cpp +// tools/ac-client/src +// +// Created by Seth Alves on 2016-10-5 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ACClientApp.h" + +ACClientApp::ACClientApp(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + // parse command-line + QCommandLineParser parser; + parser.setApplicationDescription("High Fidelity AC client"); + + const QCommandLineOption helpOption = parser.addHelpOption(); + + const QCommandLineOption verboseOutput("v", "verbose output"); + parser.addOption(verboseOutput); + + const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1"); + parser.addOption(domainAddressOption); + + const QCommandLineOption cacheSTUNOption("s", "cache stun-server response"); + parser.addOption(cacheSTUNOption); + + const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT)); + parser.addOption(listenPortOption); + + + if (!parser.parse(QCoreApplication::arguments())) { + qCritical() << parser.errorText() << endl; + parser.showHelp(); + Q_UNREACHABLE(); + } + + if (parser.isSet(helpOption)) { + parser.showHelp(); + Q_UNREACHABLE(); + } + + _verbose = parser.isSet(verboseOutput); + if (!_verbose) { + QLoggingCategory::setFilterRules("qt.network.ssl.warning=false"); + + const_cast(&networking())->setEnabled(QtDebugMsg, false); + const_cast(&networking())->setEnabled(QtInfoMsg, false); + const_cast(&networking())->setEnabled(QtWarningMsg, false); + + const_cast(&shared())->setEnabled(QtDebugMsg, false); + const_cast(&shared())->setEnabled(QtInfoMsg, false); + const_cast(&shared())->setEnabled(QtWarningMsg, false); + } + + QString domainServerAddress = "127.0.0.1:40103"; + if (parser.isSet(domainAddressOption)) { + domainServerAddress = parser.value(domainAddressOption); + } + + if (_verbose) { + qDebug() << "domain-server address is" << domainServerAddress; + } + + int listenPort = INVALID_PORT; + if (parser.isSet(listenPortOption)) { + listenPort = parser.value(listenPortOption).toInt(); + } + + Setting::preInit(); + DependencyManager::registerInheritance(); + Setting::init(); + + DependencyManager::set([&]{ return QString("Mozilla/5.0 (HighFidelityACClient)"); }); + DependencyManager::set(); + DependencyManager::set(NodeType::Agent, listenPort); + + + auto nodeList = DependencyManager::get(); + + // start the nodeThread so its event loop is running + QThread* nodeThread = new QThread(this); + nodeThread->setObjectName("NodeList Thread"); + nodeThread->start(); + + // make sure the node thread is given highest priority + nodeThread->setPriority(QThread::TimeCriticalPriority); + + // setup a timer for domain-server check ins + QTimer* domainCheckInTimer = new QTimer(nodeList.data()); + connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn); + domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); + + // put the NodeList and datagram processing on the node thread + nodeList->moveToThread(nodeThread); + + const DomainHandler& domainHandler = nodeList->getDomainHandler(); + + connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); + // connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); + // connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); + connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ACClientApp::domainConnectionRefused); + + connect(nodeList.data(), &NodeList::nodeAdded, this, &ACClientApp::nodeAdded); + connect(nodeList.data(), &NodeList::nodeKilled, this, &ACClientApp::nodeKilled); + connect(nodeList.data(), &NodeList::nodeActivated, this, &ACClientApp::nodeActivated); + // connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID); + // connect(nodeList.data(), &NodeList::uuidChanged, this, &ACClientApp::setSessionUUID); + connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ACClientApp::notifyPacketVersionMismatch); + + nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer + << NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer); + + DependencyManager::get()->handleLookupString(domainServerAddress, false); + + QTimer* doTimer = new QTimer(this); + doTimer->setSingleShot(true); + connect(doTimer, &QTimer::timeout, this, &ACClientApp::timedOut); + doTimer->start(4000); +} + +ACClientApp::~ACClientApp() { +} + + +void ACClientApp::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) { + qDebug() << "domainConnectionRefused"; +} + +void ACClientApp::domainChanged(const QString& domainHostname) { + if (_verbose) { + qDebug() << "domainChanged"; + } +} + +void ACClientApp::nodeAdded(SharedNodePointer node) { + if (_verbose) { + qDebug() << "node added: " << node->getType(); + } +} + +void ACClientApp::nodeActivated(SharedNodePointer node) { + if (node->getType() == NodeType::EntityServer) { + if (_verbose) { + qDebug() << "saw EntityServer"; + } + _sawEntityServer = true; + } + else if (node->getType() == NodeType::AudioMixer) { + if (_verbose) { + qDebug() << "saw AudioMixer"; + } + _sawAudioMixer = true; + } + else if (node->getType() == NodeType::AvatarMixer) { + if (_verbose) { + qDebug() << "saw AvatarMixer"; + } + _sawAvatarMixer = true; + } + else if (node->getType() == NodeType::AssetServer) { + if (_verbose) { + qDebug() << "saw AssetServer"; + } + _sawAssetServer = true; + } + else if (node->getType() == NodeType::MessagesMixer) { + if (_verbose) { + qDebug() << "saw MessagesMixer"; + } + _sawMessagesMixer = true; + } + + if (_sawEntityServer && _sawAudioMixer && _sawAvatarMixer && _sawAssetServer && _sawMessagesMixer) { + if (_verbose) { + qDebug() << "success"; + } + finish(0); + } +} + +void ACClientApp::nodeKilled(SharedNodePointer node) { + qDebug() << "nodeKilled"; +} + +void ACClientApp::timedOut() { + if (_verbose) { + qDebug() << "timed out: " << _sawEntityServer << _sawAudioMixer << + _sawAvatarMixer << _sawAssetServer << _sawMessagesMixer; + } + finish(1); +} + +void ACClientApp::notifyPacketVersionMismatch() { + if (_verbose) { + qDebug() << "packet version mismatch"; + } + finish(1); +} + +void ACClientApp::printFailedServers() { + if (!_sawEntityServer) { + qDebug() << "EntityServer"; + } + if (!_sawAudioMixer) { + qDebug() << "AudioMixer"; + } + if (!_sawAvatarMixer) { + qDebug() << "AvatarMixer"; + } + if (!_sawAssetServer) { + qDebug() << "AssetServer"; + } + if (!_sawMessagesMixer) { + qDebug() << "MessagesMixer"; + } +} + +void ACClientApp::finish(int exitCode) { + auto nodeList = DependencyManager::get(); + + // send the domain a disconnect packet, force stoppage of domain-server check-ins + nodeList->getDomainHandler().disconnect(); + nodeList->setIsShuttingDown(true); + + // tell the packet receiver we're shutting down, so it can drop packets + nodeList->getPacketReceiver().setShouldDropPackets(true); + + QThread* nodeThread = DependencyManager::get()->thread(); + // remove the NodeList from the DependencyManager + DependencyManager::destroy(); + // ask the node thread to quit and wait until it is done + nodeThread->quit(); + nodeThread->wait(); + + printFailedServers(); + QCoreApplication::exit(exitCode); +} diff --git a/tools/ac-client/src/ACClientApp.h b/tools/ac-client/src/ACClientApp.h new file mode 100644 index 0000000000..29d571688e --- /dev/null +++ b/tools/ac-client/src/ACClientApp.h @@ -0,0 +1,52 @@ +// +// ACClientApp.h +// tools/ac-client/src +// +// Created by Seth Alves on 2016-10-5 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#ifndef hifi_ACClientApp_h +#define hifi_ACClientApp_h + +#include +#include +#include +#include +#include +#include + + +class ACClientApp : public QCoreApplication { + Q_OBJECT +public: + ACClientApp(int argc, char* argv[]); + ~ACClientApp(); + +private slots: + void domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo); + void domainChanged(const QString& domainHostname); + void nodeAdded(SharedNodePointer node); + void nodeActivated(SharedNodePointer node); + void nodeKilled(SharedNodePointer node); + void notifyPacketVersionMismatch(); + +private: + NodeList* _nodeList; + void timedOut(); + void printFailedServers(); + void finish(int exitCode); + bool _verbose; + + bool _sawEntityServer { false }; + bool _sawAudioMixer { false }; + bool _sawAvatarMixer { false }; + bool _sawAssetServer { false }; + bool _sawMessagesMixer { false }; +}; + +#endif //hifi_ACClientApp_h diff --git a/tools/ac-client/src/main.cpp b/tools/ac-client/src/main.cpp new file mode 100644 index 0000000000..918df6413f --- /dev/null +++ b/tools/ac-client/src/main.cpp @@ -0,0 +1,23 @@ +// +// main.cpp +// tools/ice-client/src +// +// Created by Seth Alves on 2016-10-5 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +#include +#include +#include +#include + +#include "ACClientApp.h" + +using namespace std; + +int main(int argc, char * argv[]) { + ACClientApp app(argc, argv); + return app.exec(); +} diff --git a/tools/ice-client/src/ICEClientApp.cpp b/tools/ice-client/src/ICEClientApp.cpp index 992014ad7d..f9e7a76142 100644 --- a/tools/ice-client/src/ICEClientApp.cpp +++ b/tools/ice-client/src/ICEClientApp.cpp @@ -178,16 +178,9 @@ void ICEClientApp::doSomething() { qDebug() << "sending STUN request"; } _socket->writeDatagram(stunRequestPacket, sizeof(stunRequestPacket), _stunSockAddr); - _stunResponseTimerCanceled = false; - _stunResponseTimer.singleShot(stunResponseTimeoutMilliSeconds, this, [&] { - if (_stunResponseTimerCanceled) { - return; - } - if (_verbose) { - qDebug() << "timeout waiting for stun-server response"; - } - QCoreApplication::exit(stunFailureExitStatus); - }); + _stunResponseTimer.setSingleShot(true); + connect(&_stunResponseTimer, SIGNAL(timeout()), this, SLOT(stunResponseTimeout())); + _stunResponseTimer.start(stunResponseTimeoutMilliSeconds); setState(waitForStunResponse); } else { @@ -215,16 +208,9 @@ void ICEClientApp::doSomething() { } sendPacketToIceServer(PacketType::ICEServerQuery, _iceServerAddr, _sessionUUID, peerID); - _iceResponseTimerCanceled = false; - _iceResponseTimer.singleShot(iceResponseTimeoutMilliSeconds, this, [=] { - if (_iceResponseTimerCanceled) { - return; - } - if (_verbose) { - qDebug() << "timeout waiting for ice-server response"; - } - QCoreApplication::exit(iceFailureExitStatus); - }); + _iceResponseTimer.setSingleShot(true); + connect(&_iceResponseTimer, SIGNAL(timeout()), this, SLOT(iceResponseTimeout())); + _iceResponseTimer.start(iceResponseTimeoutMilliSeconds); } else if (_state == pause0) { setState(pause1); } else if (_state == pause1) { @@ -237,6 +223,20 @@ void ICEClientApp::doSomething() { } } +void ICEClientApp::iceResponseTimeout() { + if (_verbose) { + qDebug() << "timeout waiting for ice-server response"; + } + QCoreApplication::exit(iceFailureExitStatus); +} + +void ICEClientApp::stunResponseTimeout() { + if (_verbose) { + qDebug() << "timeout waiting for stun-server response"; + } + QCoreApplication::exit(stunFailureExitStatus); +} + void ICEClientApp::sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID) { std::unique_ptr icePacket = NLPacket::create(packetType); @@ -298,7 +298,6 @@ void ICEClientApp::processSTUNResponse(std::unique_ptr packet) } _stunResponseTimer.stop(); - _stunResponseTimerCanceled = true; uint16_t newPublicPort; QHostAddress newPublicAddress; @@ -331,7 +330,6 @@ void ICEClientApp::processPacket(std::unique_ptr packet) { if (nlPacket->getType() == PacketType::ICEServerPeerInformation) { // cancel the timeout timer _iceResponseTimer.stop(); - _iceResponseTimerCanceled = true; QDataStream iceResponseStream(message->getMessage()); if (!_domainServerPeerSet) { diff --git a/tools/ice-client/src/ICEClientApp.h b/tools/ice-client/src/ICEClientApp.h index 3635bc07f4..de6b6abb14 100644 --- a/tools/ice-client/src/ICEClientApp.h +++ b/tools/ice-client/src/ICEClientApp.h @@ -33,6 +33,10 @@ public: const int stunResponseTimeoutMilliSeconds { 2000 }; const int iceResponseTimeoutMilliSeconds { 2000 }; +public slots: + void iceResponseTimeout(); + void stunResponseTimeout(); + private: enum State { lookUpStunServer, // 0 @@ -83,9 +87,7 @@ private: int _state { 0 }; QTimer _stunResponseTimer; - bool _stunResponseTimerCanceled { false }; QTimer _iceResponseTimer; - bool _iceResponseTimerCanceled { false }; int _domainPingCount { 0 }; };