Exemple #1
0
Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent)
    : QTcpServer(parent),
      server(_server)
{
    if (_numberPools == 0) {
        server->setThreaded(false);
        Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(0, server);
        Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
        
        server->addDatabaseInterface(thread(), newDatabaseInterface);
        newDatabaseInterface->initDatabase(_sqlDatabase);
        
        connectionPools.append(newPool);
    } else
    for (int i = 0; i < _numberPools; ++i) {
        Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(i, server);
        Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
        
        QThread *newThread = new QThread;
        newThread->setObjectName("pool_" + QString::number(i));
        newPool->moveToThread(newThread);
        newDatabaseInterface->moveToThread(newThread);
        server->addDatabaseInterface(newThread, newDatabaseInterface);
        
        newThread->start();
        QMetaObject::invokeMethod(newDatabaseInterface, "initDatabase", Qt::BlockingQueuedConnection, Q_ARG(QSqlDatabase, _sqlDatabase));
        
        connectionPools.append(newPool);
    }
}
Exemple #2
0
    // Sets up the settings private instance. Should only be run once at startup
    void init() {
        // read the ApplicationInfo.ini file for Name/Version/Domain information
        QSettings::setDefaultFormat(QSettings::IniFormat);
        QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
        // set the associated application properties
        applicationInfo.beginGroup("INFO");
        QCoreApplication::setApplicationName(applicationInfo.value("name").toString());
        QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString());
        QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
        
        // Let's set up the settings Private instance on it's own thread
        QThread* thread = new QThread();
        Q_CHECK_PTR(thread);
        thread->setObjectName("Settings Thread");
        
        privateInstance = new Manager();
        Q_CHECK_PTR(privateInstance);
        
        QObject::connect(privateInstance, SIGNAL(destroyed()), thread, SLOT(quit()));
        QObject::connect(thread, SIGNAL(started()), privateInstance, SLOT(startTimer()));
        QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
        privateInstance->moveToThread(thread);
        thread->start();
        qCDebug(shared) << "Settings thread started.";    

        // Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
        qAddPostRoutine(cleanupPrivateInstance);
    }    
void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer<ReceivedMessage> message) {
    qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack.";

    if (_currentAssignment) {
        qCWarning(assigmnentclient) << "Received a PacketType::CreateAssignment while still running an active assignment. Ignoring.";
        return;
    }

    // construct the deployed assignment from the packet data
    _currentAssignment = AssignmentFactory::unpackAssignment(*message);

    if (_currentAssignment && !_isAssigned) {
        qDebug(assigmnentclient) << "Received an assignment -" << *_currentAssignment;
        _isAssigned = true;

        auto nodeList = DependencyManager::get<NodeList>();

        // switch our DomainHandler hostname and port to whoever sent us the assignment

        nodeList->getDomainHandler().setSockAddr(message->getSenderSockAddr(), _assignmentServerHostname);
        nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID());

        qCDebug(assigmnentclient) << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();

        // start the deployed assignment
        QThread* workerThread = new QThread;
        workerThread->setObjectName("ThreadedAssignment Worker");

        connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);

        // Once the ThreadedAssignment says it is finished - we ask it to deleteLater
        // This is a queued connection so that it is put into the event loop to be processed by the worker
        // thread when it is ready.
        connect(_currentAssignment.data(), &ThreadedAssignment::finished, _currentAssignment.data(),
                &ThreadedAssignment::deleteLater, Qt::QueuedConnection);

        // once it is deleted, we quit the worker thread
        connect(_currentAssignment.data(), &ThreadedAssignment::destroyed, workerThread, &QThread::quit);

        // have the worker thread remove itself once it is done
        connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);

        // once the worker thread says it is done, we consider the assignment completed
        connect(workerThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);

        _currentAssignment->moveToThread(workerThread);

        // Starts an event loop, and emits workerThread->started()
        workerThread->start();
    } else {
        qCWarning(assigmnentclient) << "Received an assignment that could not be unpacked. Re-requesting.";
    }
}
void cThumbnailWidget::slotRender()
{
	if (image && params)
	{
		stopRequest = true;
		while (image->IsUsed())
		{
			// just wait and pray
			Wait(100);
		}

		// random wait to not generate to many events at exactly the same time
		Wait(Random(100) + 50);

		if (cRenderJob::GetRunningJobCount() > systemData.numberOfThreads)
		{
			// try again after some random time
			timer->start(Random(5000) + 1);
			return;
		}

		stopRequest = false;

		cRenderJob *renderJob =
			new cRenderJob(params, fractal, image, &stopRequest, static_cast<QWidget *>(this));
		connect(renderJob, SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)),
			this, SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)));
		connect(renderJob, SIGNAL(updateImage()), this, SLOT(update()));

		renderingTimeTimer.start();
		renderJob->UseSizeFromImage(true);

		cRenderingConfiguration config;
		if (useOneCPUCore) config.DisableMultiThread();
		config.EnableIgnoreErrors();
		config.DisableNetRender();

		renderJob->Init(cRenderJob::still, config);

		QThread *thread = new QThread;
		renderJob->moveToThread(thread);
		QObject::connect(thread, SIGNAL(started()), renderJob, SLOT(slotExecute()));

		thread->setObjectName("ThumbnailWorker");
		thread->start();

		QObject::connect(renderJob, SIGNAL(finished()), renderJob, SLOT(deleteLater()));
		QObject::connect(renderJob, SIGNAL(finished()), thread, SLOT(quit()));
		QObject::connect(renderJob, SIGNAL(fullyRendered(const QString &, const QString &)), this,
			SLOT(slotFullyRendered()));
		QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
	}
Exemple #5
0
AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
    QThread* injectorThread = new QThread();
    injectorThread->setObjectName("Audio Injector Thread");

    AudioInjector* injector = new AudioInjector(buffer, options);
    injector->setLocalAudioInterface(localInterface);

    injector->moveToThread(injectorThread);

    // start injecting when the injector thread starts
    connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);

    // connect the right slots and signals for AudioInjector and thread cleanup
    connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
    connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);

    injectorThread->start();
    return injector;
}
Exemple #6
0
void CmaClient::enterEventLoop(vita_device_t *device)
{
    vita_event_t event;

    qDebug("Starting event loop");

    CmaEvent eventLoop (device);
    QThread thread;
    thread.setObjectName("event_thread");

    eventLoop.moveToThread(&thread);
    connect(&thread, SIGNAL(started()), &eventLoop, SLOT(process()));
    connect(&eventLoop, SIGNAL(refreshDatabase()), this, SIGNAL(refreshDatabase()), Qt::DirectConnection);
    connect(&eventLoop, SIGNAL(finishedEventLoop()), &thread, SLOT(quit()), Qt::DirectConnection);
    thread.start();

    while(isActive()) {
        if(VitaMTP_Read_Event(device, &event) < 0) {
            qWarning("Error reading event from Vita.");
            break;
        }

        // do not create a event for this since there aren't more events to read
        if(event.Code == PTP_EC_VITA_RequestTerminate) {
            qDebug("Terminating event thread");
            break;

            // this one shuold be processed inmediately
        } else if(event.Code == PTP_EC_VITA_RequestCancelTask) {
            eventLoop.vitaEventCancelTask(&event, event.Param1);
            qDebug("Ended event, code: 0x%x, id: %d", event.Code, event.Param1);
            continue;
        }

        // the events are processed synchronously except for cancel/terminate
        qDebug("Sending new event");
        eventLoop.setEvent(event);
    }

    eventLoop.stop();
    thread.wait();
    qDebug("Finishing event loop");
}
Exemple #7
0
/**
 * @brief start initializes the Host Cache.
 * Make sure this is not called before QApplication is instantiated.
 * Any custom initializations should be made within asyncStartUpHelper().
 * Locking: YES (asynchronous)
 */
void HostCache::start()
{
#if ENABLE_G2_HOST_CACHE_DEBUGGING
	systemLog.postLog( LogSeverity::Debug, Component::HostCache, QString( "start()" ) );
#endif //ENABLE_G2_HOST_CACHE_DEBUGGING

	QThread* pThread = new QThread();

	// set thread name
	pThread->setObjectName( "Host Cache and Discovery" );

	moveToThread( pThread );
	pThread->start( QThread::LowPriority );

	// Handle destruction gracefully.
	connect( pThread, &QThread::finished, pThread, &QObject::deleteLater );

	m_pHostCacheDiscoveryThread = pThread;
	QMetaObject::invokeMethod( this, "startUpInternal", Qt::BlockingQueuedConnection );
}
Exemple #8
0
std::unique_ptr<SendQueue> SendQueue::create(Socket* socket, HifiSockAddr destination) {
    Q_ASSERT_X(socket, "SendQueue::create", "Must be called with a valid Socket*");
    
    auto queue = std::unique_ptr<SendQueue>(new SendQueue(socket, destination));

    // Setup queue private thread
    QThread* thread = new QThread;
    thread->setObjectName("Networking: SendQueue " + destination.objectName()); // Name thread for easier debug
    
    connect(thread, &QThread::started, queue.get(), &SendQueue::run);
    
    connect(queue.get(), &QObject::destroyed, thread, &QThread::quit); // Thread auto cleanup
    connect(thread, &QThread::finished, thread, &QThread::deleteLater); // Thread auto cleanup
    
    // Move queue to private thread and start it
    queue->moveToThread(thread);
    
    thread->start();
    
    return queue;
}
Exemple #9
0
void Agent::run() {

    // make sure we request our script once the agent connects to the domain
    auto nodeList = DependencyManager::get<NodeList>();

    connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, this, &Agent::requestScript);

    ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent);

    // Setup MessagesClient
    auto messagesClient = DependencyManager::set<MessagesClient>();
    QThread* messagesThread = new QThread;
    messagesThread->setObjectName("Messages Client Thread");
    messagesClient->moveToThread(messagesThread);
    connect(messagesThread, &QThread::started, messagesClient.data(), &MessagesClient::init);
    messagesThread->start();

    nodeList->addSetOfNodeTypesToNodeInterestSet({
        NodeType::AudioMixer, NodeType::AvatarMixer, NodeType::EntityServer, NodeType::MessagesMixer, NodeType::AssetServer
    });
}
Exemple #10
0
Agent::Agent(ReceivedMessage& message) :
    ThreadedAssignment(message),
    _entityEditSender(),
    _receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
        InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false,
        DEFAULT_WINDOW_STARVE_THRESHOLD, DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES,
        DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false))
{
    DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);

    auto assetClient = DependencyManager::set<AssetClient>();

    QThread* assetThread = new QThread;
    assetThread->setObjectName("Asset Thread");
    assetClient->moveToThread(assetThread);
    connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init);
    assetThread->start();

    DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();

    DependencyManager::set<ResourceCacheSharedItems>();
    DependencyManager::set<SoundCache>();
    DependencyManager::set<AudioInjectorManager>();
    DependencyManager::set<recording::Deck>();
    DependencyManager::set<recording::Recorder>();
    DependencyManager::set<RecordingScriptingInterface>();

    auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();

    packetReceiver.registerListenerForTypes(
        { PacketType::MixedAudio, PacketType::SilentAudioFrame },
        this, "handleAudioPacket");
    packetReceiver.registerListenerForTypes(
        { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
        this, "handleOctreePacket");
    packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket");
}
Exemple #11
0
bool Servatrice::initServer()
{
    serverName = settings->value("server/name").toString();
    serverId = settings->value("server/id", 0).toInt();
    bool regServerOnly = settings->value("server/regonly", 0).toBool();
        
    const QString authenticationMethodStr = settings->value("authentication/method").toString();
    if (authenticationMethodStr == "sql") {
        authenticationMethod = AuthenticationSql;
    } else {
        if (regServerOnly) {
            qDebug() << "Registration only server enabled but no DB Connection : Error.";
            return false;   
        }
        authenticationMethod = AuthenticationNone;
    }
    
    QString dbTypeStr = settings->value("database/type").toString();
    if (dbTypeStr == "mysql")
        databaseType = DatabaseMySql;
    else
        databaseType = DatabaseNone;
    
    servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this);
    setDatabaseInterface(servatriceDatabaseInterface);
    
    if (databaseType != DatabaseNone) {
        settings->beginGroup("database");
        dbPrefix = settings->value("prefix").toString();
        servatriceDatabaseInterface->initDatabase("QMYSQL",
                              settings->value("hostname").toString(),
                              settings->value("database").toString(),
                              settings->value("user").toString(),
                              settings->value("password").toString());
        settings->endGroup();
        
        updateServerList();
        
        qDebug() << "Clearing previous sessions...";
        servatriceDatabaseInterface->clearSessionTables();
    }
    
    const QString roomMethod = settings->value("rooms/method").toString();
    if (roomMethod == "sql") {
        QSqlQuery query(servatriceDatabaseInterface->getDatabase());
        query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc");
        servatriceDatabaseInterface->execSqlQuery(query);
        while (query.next()) {
            QSqlQuery query2(servatriceDatabaseInterface->getDatabase());
            query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room");
            query2.bindValue(":id_room", query.value(0).toInt());
            servatriceDatabaseInterface->execSqlQuery(query2);
            QStringList gameTypes;
            while (query2.next())
                gameTypes.append(query2.value(0).toString());
            
            addRoom(new Server_Room(query.value(0).toInt(),
                                    query.value(1).toString(),
                                    query.value(2).toString(),
                                    query.value(3).toInt(),
                                    query.value(4).toString(),
                                    gameTypes,
                                    this
            ));
        }
    } else {
        int size = settings->beginReadArray("rooms/roomlist");
        for (int i = 0; i < size; ++i) {
            settings->setArrayIndex(i);
            
            QStringList gameTypes;
            int size2 = settings->beginReadArray("game_types");
                for (int j = 0; j < size2; ++j) {
                settings->setArrayIndex(j);
                gameTypes.append(settings->value("name").toString());
            }
            settings->endArray();
                
            Server_Room *newRoom = new Server_Room(
                i,
                settings->value("name").toString(),
                settings->value("description").toString(),
                settings->value("autojoin").toBool(),
                settings->value("joinmessage").toString(),
                gameTypes,
                this
            );
            addRoom(newRoom);
        }
        settings->endArray();
    }
    
    updateLoginMessage();
    
    maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt();
    maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt();
    
    maxUsersPerAddress = settings->value("security/max_users_per_address").toInt();
    messageCountingInterval = settings->value("security/message_counting_interval").toInt();
    maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
    maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
    maxGamesPerUser = settings->value("security/max_games_per_user").toInt();

	try { if (settings->value("servernetwork/active", 0).toInt()) {
		qDebug() << "Connecting to ISL network.";
		const QString certFileName = settings->value("servernetwork/ssl_cert").toString();
		const QString keyFileName = settings->value("servernetwork/ssl_key").toString();
		qDebug() << "Loading certificate...";
		QFile certFile(certFileName);
		if (!certFile.open(QIODevice::ReadOnly))
			throw QString("Error opening certificate file: %1").arg(certFileName);
		QSslCertificate cert(&certFile);
#if QT_VERSION < 0x050000
		if (!cert.isValid())
			throw(QString("Invalid certificate."));
#else
		const QDateTime currentTime = QDateTime::currentDateTime();
		if(currentTime < cert.effectiveDate() ||
			currentTime > cert.expiryDate() ||
			cert.isBlacklisted())
			throw(QString("Invalid certificate."));
#endif
		qDebug() << "Loading private key...";
		QFile keyFile(keyFileName);
		if (!keyFile.open(QIODevice::ReadOnly))
			throw QString("Error opening private key file: %1").arg(keyFileName);
		QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
		if (key.isNull())
			throw QString("Invalid private key.");
		
		QMutableListIterator<ServerProperties> serverIterator(serverList);
		while (serverIterator.hasNext()) {
			const ServerProperties &prop = serverIterator.next();
			if (prop.cert == cert) {
				serverIterator.remove();
				continue;
			}
			
			QThread *thread = new QThread;
			thread->setObjectName("isl_" + QString::number(prop.id));
			connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
			
			IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
			interface->moveToThread(thread);
			connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
			
			thread->start();
			QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
		}
			
		const int networkPort = settings->value("servernetwork/port", 14747).toInt();
		qDebug() << "Starting ISL server on port" << networkPort;
		
		islServer = new Servatrice_IslServer(this, cert, key, this);
		if (islServer->listen(QHostAddress::Any, networkPort))
			qDebug() << "ISL server listening.";
		else
			throw QString("islServer->listen()");
	} } catch (QString error) {
		qDebug() << "ERROR --" << error;
		return false;
	}
	
	pingClock = new QTimer(this);
	connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
	pingClock->start(1000);
	
	int statusUpdateTime = settings->value("server/statusupdate").toInt();
	statusUpdateClock = new QTimer(this);
	connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
	if (statusUpdateTime != 0) {
		qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
		statusUpdateClock->start(statusUpdateTime);
	}
	
	const int numberPools = settings->value("server/number_pools", 1).toInt();
	gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
	gameServer->setMaxPendingConnections(1000);
	const int gamePort = settings->value("server/port", 4747).toInt();
	qDebug() << "Starting server on port" << gamePort;
	if (gameServer->listen(QHostAddress::Any, gamePort))
		qDebug() << "Server listening.";
	else {
		qDebug() << "gameServer->listen(): Error.";
		return false;
	}
	return true;
}
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
                                   quint16 listenPort, QUuid walletUUID, QString assignmentServerHostname,
                                   quint16 assignmentServerPort, quint16 assignmentMonitorPort) :
    _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
{
    LogUtils::init();

    QSettings::setDefaultFormat(QSettings::IniFormat);

    DependencyManager::set<AccountManager>();
 
    auto scriptableAvatar = DependencyManager::set<ScriptableAvatar>();
    auto addressManager = DependencyManager::set<AddressManager>();
    auto scriptEngines = DependencyManager::set<ScriptEngines>();

    // create a NodeList as an unassigned client, must be after addressManager
    auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned, listenPort);

    auto animationCache = DependencyManager::set<AnimationCache>();
    auto entityScriptingInterface = DependencyManager::set<EntityScriptingInterface>(false);

    DependencyManager::registerInheritance<EntityActionFactoryInterface, AssignmentActionFactory>();
    auto actionFactory = DependencyManager::set<AssignmentActionFactory>();
    DependencyManager::set<ResourceScriptingInterface>();

    // setup a thread for the NodeList and its PacketReceiver
    QThread* nodeThread = new QThread(this);
    nodeThread->setObjectName("NodeList Thread");
    nodeThread->start();

    // make sure the node thread is given highest priority
    nodeThread->setPriority(QThread::TimeCriticalPriority);

    // put the NodeList on the node thread
    nodeList->moveToThread(nodeThread);

    // set the logging target to the the CHILD_TARGET_NAME
    LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);

    // make sure we output process IDs for a child AC otherwise it's insane to parse
    LogHandler::getInstance().setShouldOutputProcessID(true);

    // setup our _requestAssignment member variable from the passed arguments
    _requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, assignmentPool);

    // check for a wallet UUID on the command line or in the config
    // this would represent where the user running AC wants funds sent to
    if (!walletUUID.isNull()) {
        qCDebug(assigmnentclient) << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID);
        _requestAssignment.setWalletUUID(walletUUID);
    }

    // check for an overriden assignment server hostname
    if (assignmentServerHostname != "") {
        // change the hostname for our assignment server
        _assignmentServerHostname = assignmentServerHostname;
    }

    _assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerPort, true);
    _assignmentServerSocket.setObjectName("AssigmentServer");
    nodeList->setAssignmentServerSocket(_assignmentServerSocket);

    qCDebug(assigmnentclient) << "Assignment server socket is" << _assignmentServerSocket;

    // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required
    qCDebug(assigmnentclient) << "Waiting for assignment -" << _requestAssignment;

    if (_assignmentServerHostname != "localhost") {
        qCDebug(assigmnentclient) << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort();
    }

    connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
    _requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);

    // connections to AccountManager for authentication
    connect(DependencyManager::get<AccountManager>().data(), &AccountManager::authRequired,
            this, &AssignmentClient::handleAuthenticationRequest);

    // Create Singleton objects on main thread
    NetworkAccessManager::getInstance();

    // did we get an assignment-client monitor port?
    if (assignmentMonitorPort > 0) {
        _assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort);
        _assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor");

        qCDebug(assigmnentclient) << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket;

        // Hook up a timer to send this child's status to the Monitor once per second
        setUpStatusToMonitor();
    }
    auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
    packetReceiver.registerListener(PacketType::CreateAssignment, this, "handleCreateAssignmentPacket");
    packetReceiver.registerListener(PacketType::StopNode, this, "handleStopNodePacket");
}
Exemple #13
0
MainWidget::MainWidget( QWidget *parent )
: QSplitter( Qt::Horizontal, parent )
, mpKryptonite( new Kryptonite() )
, mpAmazonDE( new KryptoniteJobCoverAmazonDE( mpKryptonite ) )
, mpDiscogs( new KryptoniteJobCoverDiscogs( mpKryptonite ) )
, mpLayout( new QGridLayout( this ) )
, mpFileSysTree( new QTreeView( this ) )
, mpFileSysModel( new QFileSystemModel( this ) )
, mpLineEdit( new QLineEdit( this ) )
, mpFollowPartyman( new QCheckBox( tr("Follow Partyman"), this ) )
, mpCopyBuffer( new QPushButton( tr("Copy debug buffer to clipboard"), this ) )
, mpImage( new DropImageWidget( this ) )
, mpInfo( new QListWidget( this ) )
, mpSignalMapper( new QSignalMapper( this ) )
, mDataMap()
, mCacheMap()
, mDebugData()
{
   mpKryptonite->setObjectName( "Downloader");
   mpAmazonDE->setObjectName( "Amazon" );
   mpDiscogs->setObjectName( "Discogs" );
   mpFileSysTree->setObjectName( "FileSysTree" );
   mpFileSysModel->setObjectName( "FileSysModel" );
   mpLineEdit->setObjectName( "LineInput" );
   mpFollowPartyman->setObjectName( "FollowPartyman" );
   mpFollowPartyman->setChecked( true );
   mpCopyBuffer->setObjectName( "CopyBuffer" );
   mpImage->setObjectName( "Image" );
   mpInfo->setObjectName( "Info" );
   QThread *t = new QThread();
   connect( qApp, SIGNAL(aboutToQuit()),
            t, SLOT(quit()) );
   ProxyWidget::setProxy( mpKryptonite->networkAccessManager() );
   mpKryptonite->moveToThread( t );
   mpAmazonDE->moveToThread( t );
   mpDiscogs->moveToThread( t );
   t->setObjectName( "DownloadThread" );
   t->start();
   QWidget *w = 0;
   mpFileSysTree->setModel( mpFileSysModel );
   mpFileSysModel->setRootPath( "/" );
   mpFileSysModel->setFilter( QDir::NoDotAndDotDot | QDir::AllDirs );
   const QString current( Settings::value( Settings::RubberbandmanRootDirectory ) );
   QModelIndex qmi( mpFileSysModel->index( current ) );
   if( qmi.isValid() )
   {
      mpFileSysTree->setRootIndex( qmi );
      mpFileSysTree->setCurrentIndex( mpFileSysModel->index( current ) );
   }
   mpFileSysTree->header()->hide();
   mpFileSysTree->setColumnHidden( 1, true );
   mpFileSysTree->setColumnHidden( 2, true );
   mpFileSysTree->setColumnHidden( 3, true );

   QSplitter *s = new QSplitter( Qt::Vertical, this );
   w = new QWidget( this );
   QVBoxLayout *v = new QVBoxLayout( w );
   v->addWidget( mpFileSysTree );
   v->addWidget( mpLineEdit );
   QHBoxLayout *h = new QHBoxLayout();
   v->addLayout( h );
   h->addWidget( mpFollowPartyman );
   h->addWidget( mpCopyBuffer );
   s->addWidget( w );
   w = new QWidget( this );
   w->setLayout( mpLayout );
   s->addWidget( w );
   addWidget( s );
   w = new QWidget( this );
   v = new QVBoxLayout( w );
   v->addWidget( mpImage );
   v->addWidget( mpInfo );
   addWidget( w );
   v->setStretch( 0, 1 );
   Satellite *satellite = Satellite::get();

   connect( mpImage, SIGNAL(droppedUrl(QUrl)),
            this, SLOT(saveImage(QUrl)) );
   connect( mpCopyBuffer, SIGNAL(clicked()),
            this, SLOT(debugBufferToClipboard()) );
   connect( mpLineEdit, SIGNAL(returnPressed()),
            this, SLOT(requestFromLine()) );
   connect( mpFileSysTree, SIGNAL(clicked(QModelIndex)),
            this, SLOT(entryClicked(QModelIndex)) );
   connect( mpSignalMapper, SIGNAL(mapped(QWidget*)),
            this, SLOT(saveImage(QWidget*)) );
   connect( this, SIGNAL(requestSearch(QString)),
            mpDiscogs, SLOT(requestList(QString)) );
   connect( mpDiscogs, SIGNAL(imageFound(QByteArray,QVariant)),
            this, SLOT(addThumbnail(QByteArray,QVariant)) );
   connect( mpDiscogs, SIGNAL(imageDownloaded(QByteArray,QVariant)),
            this, SLOT(showImage(QByteArray,QVariant)) );
   connect( mpDiscogs, SIGNAL(message(QString,QByteArray)),
            this, SLOT(message(QString,QByteArray)) );
   connect( this, SIGNAL(requestSearch(QString)),
            mpAmazonDE, SLOT(requestList(QString)) );
   connect( mpAmazonDE, SIGNAL(imageFound(QByteArray,QVariant)),
            this, SLOT(addThumbnail(QByteArray,QVariant)) );
   connect( mpAmazonDE, SIGNAL(imageDownloaded(QByteArray,QVariant)),
            this, SLOT(showImage(QByteArray,QVariant)) );
   connect( mpAmazonDE, SIGNAL(message(QString,QByteArray)),
            this, SLOT(message(QString,QByteArray)) );
   connect( satellite, SIGNAL(received(QByteArray)),
            this, SLOT(handleSatelliteMessage(QByteArray)) );

   QList<int> sizes;
   sizes << 30 << 300;
   s->setSizes( sizes );
}
void CNetRender::ProcessData(QTcpSocket *socket, sMessage *inMsg)
{
	// beware: payload points to char, first cast to target type pointer, then dereference
	// *(qint32*)msg->payload

	//------------------------- CLIENT ------------------------
	if(IsClient())
	{
		switch ((netCommand)inMsg->command)
		{
		case netRender_VERSION:
		{
			sMessage outMsg;
			if(*(qint32*)inMsg->payload.data() == version)
			{
				WriteLog("NetRender - version matches (" + QString::number(version) + "), connection established");

				if(systemData.noGui)
				{
					QTextStream out(stdout);
					out << "NetRender - version matches (" + QString::number(version) + "), connection established\n";
				}

				// server version matches, send worker count
				outMsg.command = netRender_WORKER;
				QDataStream stream(&outMsg.payload, QIODevice::WriteOnly);
				stream << workerCount;
				QString machineName = QHostInfo::localHostName();
				stream << (qint32)machineName.toUtf8().size();
				stream.writeRawData(machineName.toUtf8().data(), machineName.toUtf8().size());
				status = netRender_READY;
				emit NewStatusClient();
			}
			else
			{
				qWarning() << "CNetRender - version mismatch! client version: " << version << ", server: " << *(qint32*)inMsg->payload.data();
				outMsg.command = netRender_BAD;
			}
			SendData(clientSocket, outMsg);
			break;
			}
			case netRender_STOP:
			{
				status = netRender_READY;
				gMainInterface->stopRequest = true;
				emit NotifyStatus();
				WriteLog("CNetRender - STOP");
				break;
			}
			case netRender_STATUS:
			{
				emit NotifyStatus();
				break;
			}
			case netRender_JOB:
			{
				if (inMsg->id == actualId)
				{
					WriteLog("NetRender - received new job");
					QDataStream stream(&inMsg->payload, QIODevice::ReadOnly);
					QByteArray buffer;
					qint32 size;
					status = netRender_WORKING;
					emit NotifyStatus();

					// read settings
					stream >> size;
					buffer.resize(size);
					stream.readRawData(buffer.data(), size);
					settingsText = QString::fromUtf8(buffer.data(), buffer.size());

					// read textures
					for (int i = 0; i < textures.textureList.size(); i++)
					{
						stream >> size;
						if (size > 0)
						{
							buffer.resize(size);
							stream.readRawData(buffer.data(), size);
							textures.textureList[i]->FromQByteArray(buffer);
						}
					}

					cSettings parSettings(cSettings::formatCondensedText);
					parSettings.BeQuiet(true);
					parSettings.LoadFromString(settingsText);
					parSettings.Decode(gPar, gParFractal);

					if(!systemData.noGui)
					{
						gMainInterface->SynchronizeInterface(gPar, gParFractal, cInterface::write);
						gMainInterface->StartRender(true);
					}
					else
					{
						//in noGui mode it must be started as separate thread to be able to process event loop
						gMainInterface->headless = new cHeadless;

						QThread *thread = new QThread; //deleted by deleteLater()
						gMainInterface->headless->moveToThread(thread);
						QObject::connect(thread, SIGNAL(started()), gMainInterface->headless, SLOT(slotNetRender()));
						thread->setObjectName("RenderJob");
						thread->start();

						QObject::connect(gMainInterface->headless, SIGNAL(finished()), gMainInterface->headless, SLOT(deleteLater()));
						QObject::connect(gMainInterface->headless, SIGNAL(finished()), thread, SLOT(quit()));
						QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
					}
				}
				else
				{
					WriteLog("NetRender - received JOB message with wrong id");
				}
				break;
			}
			case netRender_RENDER:
			{
				if (inMsg->id == actualId)
				{
					QDataStream stream(&inMsg->payload, QIODevice::ReadOnly);
					qint32 doneSize;
					stream >> doneSize;
					QList<int> done;
					for (int i = 0; i < doneSize; i++)
					{
						qint32 line;
						stream >> line;
						done.append(line);
					}

					emit ToDoListArrived(done);
				}
				else
				{
Exemple #15
0
bool Servatrice::initServer()
{
    serverName = settingsCache->value("server/name", "My Cockatrice server").toString();
    serverId = settingsCache->value("server/id", 0).toInt();
    clientIdRequired = settingsCache->value("server/requireclientid",0).toBool();
    regServerOnly = settingsCache->value("authentication/regonly", 0).toBool();

    const QString authenticationMethodStr = settingsCache->value("authentication/method").toString();
    if (authenticationMethodStr == "sql") {
        qDebug() << "Authenticating method: sql";
        authenticationMethod = AuthenticationSql;
    } else if(authenticationMethodStr == "password") {
        qDebug() << "Authenticating method: password";
        authenticationMethod = AuthenticationPassword;
    } else {
        if (regServerOnly) {
            qDebug() << "Registration only server enabled but no authentication method defined: Error.";
            return false;
        }

        qDebug() << "Authenticating method: none";
        authenticationMethod = AuthenticationNone;
    }

    qDebug() << "Store Replays: " << settingsCache->value("game/store_replays", true).toBool();
    qDebug() << "Client ID Required: " << clientIdRequired;
    bool maxUserLimitEnabled = settingsCache->value("security/enable_max_user_limit", false).toBool();
    qDebug() << "Maximum user limit enabled: " << maxUserLimitEnabled;

    if (maxUserLimitEnabled){
        int maxUserLimit = settingsCache->value("security/max_users_total", 500).toInt();
        qDebug() << "Maximum total user limit: " << maxUserLimit;
        int maxTcpUserLimit = settingsCache->value("security/max_users_tcp", 500).toInt();
        qDebug() << "Maximum tcp user limit: " << maxTcpUserLimit;
        int maxWebsocketUserLimit = settingsCache->value("security/max_users_websocket", 500).toInt();
        qDebug() << "Maximum websocket user limit: " << maxWebsocketUserLimit;
    }

    bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
    bool requireEmailForRegistration = settingsCache->value("registration/requireemail", true).toBool();
    bool requireEmailActivation = settingsCache->value("registration/requireemailactivation", true).toBool();

    qDebug() << "Accept registered users only: " << regServerOnly;
    qDebug() << "Registration enabled: " << registrationEnabled;
    if (registrationEnabled)
    {
        qDebug() << "Require email address to register: " << requireEmailForRegistration;
        qDebug() << "Require email activation via token: " << requireEmailActivation;
    }

    FeatureSet features;
    features.initalizeFeatureList(serverRequiredFeatureList);
    requiredFeatures = settingsCache->value("server/requiredfeatures","").toString();
    QStringList listReqFeatures = requiredFeatures.split(",", QString::SkipEmptyParts);
    if (!listReqFeatures.isEmpty())
        foreach(QString reqFeature, listReqFeatures)
            features.enableRequiredFeature(serverRequiredFeatureList,reqFeature);

    qDebug() << "Required client features: " << serverRequiredFeatureList;

    QString dbTypeStr = settingsCache->value("database/type").toString();
    if (dbTypeStr == "mysql")
        databaseType = DatabaseMySql;
    else
        databaseType = DatabaseNone;

    servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this);
    setDatabaseInterface(servatriceDatabaseInterface);

    if (databaseType != DatabaseNone) {
        settingsCache->beginGroup("database");
        dbPrefix = settingsCache->value("prefix").toString();
        bool dbOpened =
            servatriceDatabaseInterface->initDatabase("QMYSQL",
                 settingsCache->value("hostname").toString(),
                 settingsCache->value("database").toString(),
                 settingsCache->value("user").toString(),
                 settingsCache->value("password").toString());
        settingsCache->endGroup();
        if (!dbOpened) {
            qDebug() << "Failed to open database";
            return false;
        }

        updateServerList();

        qDebug() << "Clearing previous sessions...";
        servatriceDatabaseInterface->clearSessionTables();
    }

    const QString roomMethod = settingsCache->value("rooms/method").toString();
    if (roomMethod == "sql") {
        QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select id, name, descr, permissionlevel, auto_join, join_message, chat_history_size from {prefix}_rooms where id_server = :id_server order by id asc");
        query->bindValue(":id_server", serverId);
        servatriceDatabaseInterface->execSqlQuery(query);
        while (query->next()) {
            QSqlQuery *query2 = servatriceDatabaseInterface->prepareQuery("select name from {prefix}_rooms_gametypes where id_room = :id_room AND id_server = :id_server");
            query2->bindValue(":id_server", serverId);
            query2->bindValue(":id_room", query->value(0).toInt());
            servatriceDatabaseInterface->execSqlQuery(query2);
            QStringList gameTypes;
            while (query2->next())
                gameTypes.append(query2->value(0).toString());

            addRoom(new Server_Room(query->value(0).toInt(),
                                    query->value(6).toInt(),
                                    query->value(1).toString(),
                                    query->value(2).toString(),
                                    query->value(3).toString().toLower(),
                                    query->value(4).toInt(),
                                    query->value(5).toString(),
                                    gameTypes,
                                    this
            ));
        }
    } else {
        int size = settingsCache->beginReadArray("rooms/roomlist");
        for (int i = 0; i < size; ++i) {
            settingsCache->setArrayIndex(i);

            QStringList gameTypes;
            int size2 = settingsCache->beginReadArray("game_types");
                for (int j = 0; j < size2; ++j) {
                settingsCache->setArrayIndex(j);
                gameTypes.append(settingsCache->value("name").toString());
            }
            settingsCache->endArray();

            Server_Room *newRoom = new Server_Room(
                i,
                settingsCache->value("chathistorysize").toInt(),
                settingsCache->value("name").toString(),
                settingsCache->value("description").toString(),
                settingsCache->value("permissionlevel").toString().toLower(),
                settingsCache->value("autojoin").toBool(),
                settingsCache->value("joinmessage").toString(),
                gameTypes,
                this
            );
            addRoom(newRoom);
        }

        if(size==0)
        {
            // no room defined in config, add a dummy one
            Server_Room *newRoom = new Server_Room(
                0,
                100,
                "General room",
                "Play anything here.",
                "none",
                true,
                "",
                QStringList("Standard"),
                this
            );
            addRoom(newRoom);
        }

        settingsCache->endArray();
    }

    updateLoginMessage();

    maxGameInactivityTime = settingsCache->value("game/max_game_inactivity_time", 120).toInt();
    maxPlayerInactivityTime = settingsCache->value("server/max_player_inactivity_time", 15).toInt();
    pingClockInterval = settingsCache->value("server/clientkeepalive", 1).toInt();
    maxUsersPerAddress = settingsCache->value("security/max_users_per_address", 4).toInt();
    messageCountingInterval = settingsCache->value("security/message_counting_interval", 10).toInt();
    maxMessageCountPerInterval = settingsCache->value("security/max_message_count_per_interval", 15).toInt();
    maxMessageSizePerInterval = settingsCache->value("security/max_message_size_per_interval", 1000).toInt();
    maxGamesPerUser = settingsCache->value("security/max_games_per_user", 5).toInt();
    commandCountingInterval = settingsCache->value("game/command_counting_interval", 10).toInt();
    maxCommandCountPerInterval = settingsCache->value("game/max_command_count_per_interval", 20).toInt();

    try { if (settingsCache->value("servernetwork/active", 0).toInt()) {
        qDebug() << "Connecting to ISL network.";
        const QString certFileName = settingsCache->value("servernetwork/ssl_cert").toString();
        const QString keyFileName = settingsCache->value("servernetwork/ssl_key").toString();
        qDebug() << "Loading certificate...";
        QFile certFile(certFileName);
        if (!certFile.open(QIODevice::ReadOnly))
            throw QString("Error opening certificate file: %1").arg(certFileName);
        QSslCertificate cert(&certFile);

        const QDateTime currentTime = QDateTime::currentDateTime();
        if(currentTime < cert.effectiveDate() ||
            currentTime > cert.expiryDate() ||
            cert.isBlacklisted())
            throw(QString("Invalid certificate."));

        qDebug() << "Loading private key...";
        QFile keyFile(keyFileName);
        if (!keyFile.open(QIODevice::ReadOnly))
            throw QString("Error opening private key file: %1").arg(keyFileName);
        QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
        if (key.isNull())
            throw QString("Invalid private key.");

        QMutableListIterator<ServerProperties> serverIterator(serverList);
        while (serverIterator.hasNext()) {
            const ServerProperties &prop = serverIterator.next();
            if (prop.cert == cert) {
                serverIterator.remove();
                continue;
            }

            QThread *thread = new QThread;
            thread->setObjectName("isl_" + QString::number(prop.id));
            connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

            IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
            interface->moveToThread(thread);
            connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));

            thread->start();
            QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
        }

        const int networkPort = settingsCache->value("servernetwork/port", 14747).toInt();
        qDebug() << "Starting ISL server on port" << networkPort;

        islServer = new Servatrice_IslServer(this, cert, key, this);
        if (islServer->listen(QHostAddress::Any, networkPort))
            qDebug() << "ISL server listening.";
        else
            throw QString("islServer->listen()");
    } } catch (QString error) {
        qDebug() << "ERROR --" << error;
        return false;
    }

    pingClock = new QTimer(this);
    connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
    pingClock->start(pingClockInterval * 1000);

    int statusUpdateTime = settingsCache->value("server/statusupdate", 15000).toInt();
    statusUpdateClock = new QTimer(this);
    connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
    if (statusUpdateTime != 0) {
        qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
        statusUpdateClock->start(statusUpdateTime);
    }

    // SOCKET SERVER
    const int numberPools = settingsCache->value("server/number_pools", 1).toInt();
    if(numberPools > 0)
    {
        gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
        gameServer->setMaxPendingConnections(1000);
        const int gamePort = settingsCache->value("server/port", 4747).toInt();
        qDebug() << "Starting server on port" << gamePort;
        if (gameServer->listen(QHostAddress::Any, gamePort))
            qDebug() << "Server listening.";
        else {
            qDebug() << "gameServer->listen(): Error:" << gameServer->errorString();
            return false;
        }
    }

#if QT_VERSION > 0x050300
    // WEBSOCKET SERVER
    const int wesocketNumberPools = settingsCache->value("server/websocket_number_pools", 1).toInt();
    if(wesocketNumberPools > 0)
    {
        websocketGameServer = new Servatrice_WebsocketGameServer(this, wesocketNumberPools, servatriceDatabaseInterface->getDatabase(), this);
        websocketGameServer->setMaxPendingConnections(1000);
        const int websocketGamePort = settingsCache->value("server/websocket_port", 4748).toInt();
        qDebug() << "Starting websocket server on port" << websocketGamePort;
        if (websocketGameServer->listen(QHostAddress::Any, websocketGamePort))
            qDebug() << "Websocket server listening.";
        else {
            qDebug() << "websocketGameServer->listen(): Error:" << websocketGameServer->errorString();
            return false;
        }
    }
#endif
    return true;
}
Exemple #16
0
void AssignmentClient::readPendingDatagrams() {
    auto nodeList = DependencyManager::get<NodeList>();

    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;

    while (nodeList->getNodeSocket().hasPendingDatagrams()) {
        receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
                                               senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());

        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
            if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {

                qDebug() << "Received a PacketTypeCreateAssignment - attempting to unpack.";

                // construct the deployed assignment from the packet data
                _currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);

                if (_currentAssignment) {
                    qDebug() << "Received an assignment -" << *_currentAssignment;

                    // switch our DomainHandler hostname and port to whoever sent us the assignment

                    nodeList->getDomainHandler().setSockAddr(senderSockAddr, _assignmentServerHostname);
                    nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID());

                    qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();

                    // start the deployed assignment
                    QThread* workerThread = new QThread;
                    workerThread->setObjectName("ThreadedAssignment Worker");

                    connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);

                    // Once the ThreadedAssignment says it is finished - we ask it to deleteLater
                    // This is a queued connection so that it is put into the event loop to be processed by the worker
                    // thread when it is ready.
                    connect(_currentAssignment.data(), &ThreadedAssignment::finished, _currentAssignment.data(),
                            &ThreadedAssignment::deleteLater, Qt::QueuedConnection);

                    // once it is deleted, we quit the worker thread
                    connect(_currentAssignment.data(), &ThreadedAssignment::destroyed, workerThread, &QThread::quit);

                    // have the worker thread remove itself once it is done
                    connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);

                    // once the worker thread says it is done, we consider the assignment completed
                    connect(workerThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);

                    _currentAssignment->moveToThread(workerThread);

                    // move the NodeList to the thread used for the _current assignment
                    nodeList->moveToThread(workerThread);

                    // let the assignment handle the incoming datagrams for its duration
                    disconnect(&nodeList->getNodeSocket(), 0, this, 0);
                    connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(),
                            &ThreadedAssignment::readPendingDatagrams);

                    // Starts an event loop, and emits workerThread->started()
                    workerThread->start();
                } else {
                    qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
                }
            } else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
                if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
                    senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
                    qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketTypeStopNode.";

                    QCoreApplication::quit();
                } else {
                    qDebug() << "Got a stop packet from other than localhost.";
                }
            } else {
                // have the NodeList attempt to handle it
                nodeList->processNodeData(senderSockAddr, receivedPacket);
            }
        }
    }
}
int main( int argc, char** argv )
{
    QApplication qApplication(argc, argv);
    qApplication.setOrganizationName("Opposite Renderer");
    qApplication.setApplicationName("Opposite Renderer");
    //attachConEmu();

    QTextStream out(stdout);
    QTextStream in(stdin);
    
    //setvbuf(stdout, NULL, _IONBF, NULL);	// vmarz: disable output stream buffering, otherwise printf output doesn't show up consistently
    //setvbuf(stderr, NULL, _IONBF, NULL);

    try
    {
        ComputeDeviceRepository repository;

        const std::vector<ComputeDevice> & repo = repository.getComputeDevices();

        if(repo.empty())
        {
            out << "You must have a CUDA enabled GPU to run this application." 
                << endl << "Press ENTER to quit." << endl;
            in.read(1);
            return 1;
        }

        out << "Available compute devices:" << endl;

        for(int i = 0; i < repo.size(); i++)
        {
            const ComputeDevice & device = repo.at(i);
            out << "   " <<  i << ": " << device.getName() << " (CC " << device.getComputeCapability() << " PCI Bus "<< device.getPCIBusId() <<")" << endl;
        }

        int deviceNumber = repo.size() == 1 ? 0 : -1;

        while (deviceNumber >= repo.size() || deviceNumber < 0)
        {
            out << "Select 0-" << repo.size()-1 << ":" << endl;
            in >> deviceNumber;
        }

        out << "Using device: " << deviceNumber << endl;

        ComputeDevice device = repo.at(deviceNumber);
        StandaloneApplication application = StandaloneApplication(qApplication, device);

        // Run application
        QThread* applicationThread = new QThread(&qApplication);
        applicationThread->setObjectName("QThread::Application");
        application.moveToThread(applicationThread);
        applicationThread->start();

        MainWindowBase mainWindow(application);
        //mainWindow.showMaximized();
        mainWindow.show();
        mainWindow.resize(1150,700);

        // vmarz: start render manager after MainWindow initialization when all signals/slots hooked up
        application.startRenderManager();
        int returnCode = qApplication.exec();
        application.wait();

        applicationThread->quit();
        applicationThread->wait();

        return returnCode;
    }
    catch(const std::exception & E)
    {
        QMessageBox::warning(NULL, "Exception Thrown During Launch of Standalone", E.what());
        return -1;
    }
}