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; } } }
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); } } } }