Exemple #1
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);
            }
        }
    }
}
void DatagramProcessor::processDatagrams() {

    if (_isShuttingDown) {
        return; // bail early... we're shutting down.
    }
    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                            "DatagramProcessor::processDatagrams()");


    HifiSockAddr senderSockAddr;

    static QByteArray incomingPacket;

    Application* application = Application::getInstance();
    auto nodeList = DependencyManager::get<NodeList>();

    while (DependencyManager::get<NodeList>()->getNodeSocket().hasPendingDatagrams()) {
        incomingPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
        nodeList->readDatagram(incomingPacket, senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());

        _inPacketCount++;
        _inByteCount += incomingPacket.size();

        if (nodeList->packetVersionAndHashMatch(incomingPacket)) {

            PacketType incomingType = packetTypeForPacket(incomingPacket);
            // only process this packet if we have a match on the packet version
            switch (incomingType) {
                case PacketTypeAudioEnvironment:
                case PacketTypeAudioStreamStats:
                case PacketTypeMixedAudio:
                case PacketTypeSilentAudioFrame: {
                    if (incomingType == PacketTypeAudioStreamStats) {
                        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "parseAudioStreamStatsPacket",
                                                  Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else if (incomingType == PacketTypeAudioEnvironment) {
                        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "parseAudioEnvironmentData",
                                                  Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    } else {
                        QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "addReceivedAudioToStream",
                                                  Qt::QueuedConnection,
                                                  Q_ARG(QByteArray, incomingPacket));
                    }

                    // update having heard from the audio-mixer and record the bytes received
                    SharedNodePointer audioMixer = nodeList->sendingNodeForPacket(incomingPacket);

                    if (audioMixer) {
                        audioMixer->setLastHeardMicrostamp(usecTimestampNow());
                    }

                    break;
                }
                case PacketTypeEntityData:
                case PacketTypeEntityErase:
                case PacketTypeOctreeStats:
                case PacketTypeEnvironmentData: {
                    PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
                                            "Application::networkReceive()... _octreeProcessor.queueReceivedPacket()");
                    SharedNodePointer matchedNode = DependencyManager::get<NodeList>()->sendingNodeForPacket(incomingPacket);

                    if (matchedNode) {
                        // add this packet to our list of octree packets and process them on the octree data processing
                        application->_octreeProcessor.queueReceivedPacket(matchedNode, incomingPacket);
                    }
                    break;
                }
                case PacketTypeBulkAvatarData:
                case PacketTypeKillAvatar:
                case PacketTypeAvatarIdentity:
                case PacketTypeAvatarBillboard: {
                    // update having heard from the avatar-mixer and record the bytes received
                    SharedNodePointer avatarMixer = nodeList->sendingNodeForPacket(incomingPacket);

                    if (avatarMixer) {
                        avatarMixer->setLastHeardMicrostamp(usecTimestampNow());

                        QMetaObject::invokeMethod(DependencyManager::get<AvatarManager>().data(), "processAvatarMixerDatagram",
                                                  Q_ARG(const QByteArray&, incomingPacket),
                                                  Q_ARG(const QWeakPointer<Node>&, avatarMixer));
                    }
                    break;
                }
                case PacketTypeDomainConnectionDenied: {
                    int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeDomainConnectionDenied);
                    QDataStream packetStream(QByteArray(incomingPacket.constData() + headerSize,
                                                        incomingPacket.size() - headerSize));
                    QString reason;
                    packetStream >> reason;

                    // output to the log so the user knows they got a denied connection request
                    // and check and signal for an access token so that we can make sure they are logged in
                    qCDebug(interfaceapp) << "The domain-server denied a connection request: " << reason;
                    qCDebug(interfaceapp) << "You may need to re-log to generate a keypair so you can provide a username signature.";
                    application->domainConnectionDenied(reason);
                    AccountManager::getInstance().checkAndSignalForAccessToken();
                    break;
                }
                case PacketTypeNoisyMute:
                case PacketTypeMuteEnvironment: {
                    bool mute = !DependencyManager::get<AudioClient>()->isMuted();

                    if (incomingType == PacketTypeMuteEnvironment) {
                        glm::vec3 position;
                        float radius;

                        int headerSize = numBytesForPacketHeaderGivenPacketType(PacketTypeMuteEnvironment);
                        memcpy(&position, incomingPacket.constData() + headerSize, sizeof(glm::vec3));
                        memcpy(&radius, incomingPacket.constData() + headerSize + sizeof(glm::vec3), sizeof(float));
                        float distance = glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(),
                                                 position);

                        mute = mute && (distance < radius);
                    }

                    if (mute) {
                        DependencyManager::get<AudioClient>()->toggleMute();
                        if (incomingType == PacketTypeMuteEnvironment) {
                            AudioScriptingInterface::getInstance().environmentMuted();
                        } else {
                            AudioScriptingInterface::getInstance().mutedByMixer();
                        }
                    }
                    break;
                }
                case PacketTypeEntityEditNack:
                    if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
                        application->_entityEditSender.processNackPacket(incomingPacket);
                    }
                    break;
                default:
                    nodeList->processNodeData(senderSockAddr, incomingPacket);
                    break;
            }
        }
    }
Exemple #3
0
void Agent::readPendingDatagrams() {
    QByteArray receivedPacket;
    HifiSockAddr senderSockAddr;
    auto nodeList = DependencyManager::get<NodeList>();
    
    while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
        if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
            PacketType datagramPacketType = packetTypeForPacket(receivedPacket);
            
            if (datagramPacketType == PacketTypeJurisdiction) {
                int headerBytes = numBytesForPacketHeader(receivedPacket);
                
                SharedNodePointer matchedNode = nodeList->sendingNodeForPacket(receivedPacket);
                
                if (matchedNode) {
                    // PacketType_JURISDICTION, first byte is the node type...
                    switch (receivedPacket[headerBytes]) {
                        case NodeType::EntityServer:
                            _scriptEngine.getEntityScriptingInterface()->getJurisdictionListener()->
                                                                queueReceivedPacket(matchedNode, receivedPacket);
                            break;
                    }
                }
                
            } else if (datagramPacketType == PacketTypeEntityAddResponse) {
                // this will keep creatorTokenIDs to IDs mapped correctly
                EntityItemID::handleAddEntityResponse(receivedPacket);
                
                // also give our local entity tree a chance to remap any internal locally created entities
                _entityViewer.getTree()->handleAddEntityResponse(receivedPacket);

                // Make sure our Node and NodeList knows we've heard from this node.
                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
                sourceNode->setLastHeardMicrostamp(usecTimestampNow());

            } else if (datagramPacketType == PacketTypeOctreeStats
                        || datagramPacketType == PacketTypeEntityData
                        || datagramPacketType == PacketTypeEntityErase
            ) {
                // Make sure our Node and NodeList knows we've heard from this node.
                SharedNodePointer sourceNode = nodeList->sendingNodeForPacket(receivedPacket);
                sourceNode->setLastHeardMicrostamp(usecTimestampNow());

                QByteArray mutablePacket = receivedPacket;
                int messageLength = mutablePacket.size();

                if (datagramPacketType == PacketTypeOctreeStats) {

                    int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(mutablePacket, sourceNode);
                    if (messageLength > statsMessageLength) {
                        mutablePacket = mutablePacket.mid(statsMessageLength);
                        
                        // TODO: this needs to be fixed, the goal is to test the packet version for the piggyback, but
                        //       this is testing the version and hash of the original packet
                        //       need to use numBytesArithmeticCodingFromBuffer()...
                        if (!DependencyManager::get<NodeList>()->packetVersionAndHashMatch(receivedPacket)) {
                            return; // bail since piggyback data doesn't match our versioning
                        }
                    } else {
                        return; // bail since no piggyback data
                    }

                    datagramPacketType = packetTypeForPacket(mutablePacket);
                } // fall through to piggyback message

                if (datagramPacketType == PacketTypeEntityData || datagramPacketType == PacketTypeEntityErase) {
                    _entityViewer.processDatagram(mutablePacket, sourceNode);
                }
                
            } else if (datagramPacketType == PacketTypeMixedAudio || datagramPacketType == PacketTypeSilentAudioFrame) {

                _receivedAudioStream.parseData(receivedPacket);

                _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();

                _receivedAudioStream.clearBuffer();
                
                // let this continue through to the NodeList so it updates last heard timestamp
                // for the sending audio mixer
                DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
            } else if (datagramPacketType == PacketTypeBulkAvatarData
                       || datagramPacketType == PacketTypeAvatarIdentity
                       || datagramPacketType == PacketTypeAvatarBillboard
                       || datagramPacketType == PacketTypeKillAvatar) {
                // let the avatar hash map process it
                _avatarHashMap.processAvatarMixerDatagram(receivedPacket, nodeList->sendingNodeForPacket(receivedPacket));
                
                // let this continue through to the NodeList so it updates last heard timestamp
                // for the sending avatar-mixer
                DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
            } else {
                DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
            }
        }
    }
}