mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 15:33:35 +02:00
Merge branch 'receive_packets' of https://github.com/huffman/hifi into protocol
This commit is contained in:
commit
fbb6a94579
107 changed files with 1920 additions and 2049 deletions
assignment-client/src
Agent.cppAgent.hAssignmentClient.cppAssignmentClient.hAssignmentClientChildData.cppAssignmentClientChildData.hAssignmentClientMonitor.cppAssignmentClientMonitor.hAssignmentFactory.cppAssignmentFactory.h
audio
AudioMixer.cppAudioMixer.hAudioMixerClientData.cppAudioMixerClientData.hAudioMixerDatagramProcessor.cppAudioMixerDatagramProcessor.h
avatars
entities
octree
domain-server/src
interface/src
libraries
audio-client/src
audio/src
avatars/src
entities-renderer/src
entities/src
EntityEditPacketSender.cppEntityEditPacketSender.hEntityItemProperties.cppEntityItemProperties.hEntityTree.cppEntityTree.hEntityTreeHeadlessViewer.cppEntityTreeHeadlessViewer.h
networking/src
Assignment.cppAssignment.hDomainHandler.cppDomainHandler.hLimitedNodeList.cppLimitedNodeList.hNLPacket.cppNLPacket.hNetworkPeer.hNode.hNodeData.hNodeList.cppNodeList.hPacketListener.cppPacketListener.hPacketReceiver.cppPacketReceiver.hReceivedPacketProcessor.cppReceivedPacketProcessor.hSentPacketHistory.hThreadedAssignment.cppThreadedAssignment.h
udt
octree/src
|
@ -32,7 +32,7 @@
|
|||
|
||||
static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
||||
|
||||
Agent::Agent(const QByteArray& packet) :
|
||||
Agent::Agent(NLPacket& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_entityEditSender(),
|
||||
_receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES,
|
||||
|
@ -47,94 +47,64 @@ Agent::Agent(const QByteArray& packet) :
|
|||
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<SoundCache>();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void Agent::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
void Agent::handleOctreePacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
auto packetType = packet->getType();
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType::Value datagramPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (packetType == PacketType::OctreeStats) {
|
||||
|
||||
if (datagramPacketType == PacketType::Jurisdiction) {
|
||||
int headerBytes = numBytesForPacketHeader(receivedPacket);
|
||||
int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(packet, senderNode);
|
||||
if (packet->getSizeUsed() > statsMessageLength) {
|
||||
// pull out the piggybacked packet and create a new QSharedPointer<NLPacket> for it
|
||||
int piggyBackedSizeWithHeader = packet->getSizeUsed() - statsMessageLength;
|
||||
|
||||
std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[piggyBackedSizeWithHeader]);
|
||||
memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggyBackedSizeWithHeader);
|
||||
|
||||
SharedNodePointer matchedNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (matchedNode) {
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
switch (receivedPacket[headerBytes]) {
|
||||
case NodeType::EntityServer:
|
||||
DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
|
||||
queueReceivedPacket(matchedNode, receivedPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (datagramPacketType == PacketType::OctreeStats
|
||||
|| datagramPacketType == PacketType::EntityData
|
||||
|| datagramPacketType == PacketType::EntityErase
|
||||
) {
|
||||
// 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 == PacketType::OctreeStats) {
|
||||
|
||||
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 == PacketType::EntityData || datagramPacketType == PacketType::EntityErase) {
|
||||
_entityViewer.processDatagram(mutablePacket, sourceNode);
|
||||
}
|
||||
|
||||
} else if (datagramPacketType == PacketType::MixedAudio || datagramPacketType == PacketType::SilentAudioFrame) {
|
||||
|
||||
_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 == PacketType::BulkAvatarData
|
||||
|| datagramPacketType == PacketType::AvatarIdentity
|
||||
|| datagramPacketType == PacketType::AvatarBillboard
|
||||
|| datagramPacketType == PacketType::KillAvatar) {
|
||||
// let the avatar hash map process it
|
||||
DependencyManager::get<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);
|
||||
}
|
||||
auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, packet->getSenderSockAddr());
|
||||
packet = QSharedPointer<NLPacket>(newPacket.release());
|
||||
} else {
|
||||
return; // bail since no piggyback data
|
||||
}
|
||||
|
||||
packetType = packet->getType();
|
||||
} // fall through to piggyback message
|
||||
|
||||
if (packetType == PacketType::EntityData || packetType == PacketType::EntityErase) {
|
||||
_entityViewer.processDatagram(*packet, senderNode);
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::handleJurisdictionPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
NodeType_t nodeType;
|
||||
packet->peekPrimitive(&nodeType);
|
||||
|
||||
// PacketType_JURISDICTION, first byte is the node type...
|
||||
if (nodeType == NodeType::EntityServer) {
|
||||
DependencyManager::get<EntityScriptingInterface>()->getJurisdictionListener()->
|
||||
queueReceivedPacket(packet, senderNode);
|
||||
}
|
||||
}
|
||||
|
||||
void Agent::handleAudioPacket(QSharedPointer<NLPacket> packet) {
|
||||
_receivedAudioStream.parseData(*packet);
|
||||
|
||||
_lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness();
|
||||
|
||||
_receivedAudioStream.clearBuffer();
|
||||
}
|
||||
|
||||
const QString AGENT_LOGGING_NAME = "agent";
|
||||
|
||||
void Agent::run() {
|
||||
|
|
|
@ -35,7 +35,7 @@ class Agent : public ThreadedAssignment {
|
|||
Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream)
|
||||
Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness)
|
||||
public:
|
||||
Agent(const QByteArray& packet);
|
||||
Agent(NLPacket& packet);
|
||||
|
||||
void setIsAvatar(bool isAvatar) { QMetaObject::invokeMethod(&_scriptEngine, "setIsAvatar", Q_ARG(bool, isAvatar)); }
|
||||
bool isAvatar() const { return _scriptEngine.isAvatar(); }
|
||||
|
@ -52,9 +52,13 @@ public:
|
|||
|
||||
public slots:
|
||||
void run();
|
||||
void readPendingDatagrams();
|
||||
void playAvatarSound(Sound* avatarSound) { _scriptEngine.setAvatarSound(avatarSound); }
|
||||
|
||||
private slots:
|
||||
void handleAudioPacket(QSharedPointer<NLPacket> packet);
|
||||
void handleOctreePacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleJurisdictionPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
|
||||
private:
|
||||
ScriptEngine _scriptEngine;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
|
|
|
@ -62,6 +62,17 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
DependencyManager::registerInheritance<EntityActionFactoryInterface, AssignmentActionFactory>();
|
||||
auto actionFactory = DependencyManager::set<AssignmentActionFactory>();
|
||||
|
||||
// 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);
|
||||
|
||||
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||
// when the domain server hands over an assignment.
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
|
@ -104,9 +115,6 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest()));
|
||||
_requestTimer.start(ASSIGNMENT_REQUEST_INTERVAL_MSECS);
|
||||
|
||||
// connect our readPendingDatagrams method to the readyRead() signal of the socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
|
||||
// connections to AccountManager for authentication
|
||||
connect(&AccountManager::getInstance(), &AccountManager::authRequired,
|
||||
this, &AssignmentClient::handleAuthenticationRequest);
|
||||
|
@ -121,11 +129,12 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri
|
|||
qDebug() << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket;
|
||||
|
||||
// Hook up a timer to send this child's status to the Monitor once per second
|
||||
setUpStatsToMonitor();
|
||||
setUpStatusToMonitor();
|
||||
}
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::CreateAssignment, this, "handleCreateAssignmentPacket");
|
||||
packetReceiver.registerListener(PacketType::StopNode, this, "handleStopNodePacket");
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::stopAssignmentClient() {
|
||||
qDebug() << "Forced stop of assignment-client.";
|
||||
|
||||
|
@ -151,6 +160,16 @@ void AssignmentClient::stopAssignmentClient() {
|
|||
}
|
||||
}
|
||||
|
||||
AssignmentClient::~AssignmentClient() {
|
||||
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
||||
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
|
||||
// ask the node thread to quit and wait until it is done
|
||||
nodeThread->quit();
|
||||
nodeThread->wait();
|
||||
}
|
||||
|
||||
void AssignmentClient::aboutToQuit() {
|
||||
stopAssignmentClient();
|
||||
|
@ -160,23 +179,28 @@ void AssignmentClient::aboutToQuit() {
|
|||
}
|
||||
|
||||
|
||||
void AssignmentClient::setUpStatsToMonitor() {
|
||||
void AssignmentClient::setUpStatusToMonitor() {
|
||||
// send a stats packet every 1 seconds
|
||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatsPacketToACM);
|
||||
connect(&_statsTimerACM, &QTimer::timeout, this, &AssignmentClient::sendStatusPacketToACM);
|
||||
_statsTimerACM.start(1000);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendStatsPacketToACM() {
|
||||
void AssignmentClient::sendStatusPacketToACM() {
|
||||
// tell the assignment client monitor what this assignment client is doing (if anything)
|
||||
QJsonObject statsObject;
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
quint8 assignmentType = Assignment::Type::AllTypes;
|
||||
|
||||
if (_currentAssignment) {
|
||||
statsObject["assignment_type"] = _currentAssignment->getTypeName();
|
||||
} else {
|
||||
statsObject["assignment_type"] = "none";
|
||||
assignmentType = _currentAssignment->getType();
|
||||
}
|
||||
nodeList->sendStats(statsObject, _assignmentClientMonitorSocket);
|
||||
|
||||
auto statusPacket = NLPacket::create(PacketType::AssignmentClientStatus, sizeof(assignmentType) + NUM_BYTES_RFC4122_UUID);
|
||||
|
||||
statusPacket->write(nodeList->getSessionUUID().toRfc4122());
|
||||
statusPacket->writePrimitive(assignmentType);
|
||||
|
||||
nodeList->sendPacket(std::move(statusPacket), _assignmentClientMonitorSocket);
|
||||
}
|
||||
|
||||
void AssignmentClient::sendAssignmentRequest() {
|
||||
|
@ -206,85 +230,64 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
}
|
||||
}
|
||||
|
||||
void AssignmentClient::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer<NLPacket> packet) {
|
||||
qDebug() << "Received a PacketType::CreateAssignment - attempting to unpack.";
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(*packet);
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
if (_currentAssignment) {
|
||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketType::CreateAssignment) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
qDebug() << "Received a PacketType::CreateAssignment - attempting to unpack.";
|
||||
// switch our DomainHandler hostname and port to whoever sent us the assignment
|
||||
|
||||
// construct the deployed assignment from the packet data
|
||||
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket);
|
||||
nodeList->getDomainHandler().setSockAddr(packet->getSenderSockAddr(), _assignmentServerHostname);
|
||||
nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID());
|
||||
|
||||
if (_currentAssignment) {
|
||||
qDebug() << "Received an assignment -" << *_currentAssignment;
|
||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
|
||||
|
||||
// switch our DomainHandler hostname and port to whoever sent us the assignment
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread;
|
||||
workerThread->setObjectName("ThreadedAssignment Worker");
|
||||
|
||||
nodeList->getDomainHandler().setSockAddr(senderSockAddr, _assignmentServerHostname);
|
||||
nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID());
|
||||
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||
|
||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString();
|
||||
// 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);
|
||||
|
||||
// start the deployed assignment
|
||||
QThread* workerThread = new QThread;
|
||||
workerThread->setObjectName("ThreadedAssignment Worker");
|
||||
// once it is deleted, we quit the worker thread
|
||||
connect(_currentAssignment.data(), &ThreadedAssignment::destroyed, workerThread, &QThread::quit);
|
||||
|
||||
connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
|
||||
// have the worker thread remove itself once it is done
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
|
||||
// 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 the worker thread says it is done, we consider the assignment completed
|
||||
connect(workerThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
|
||||
|
||||
// once it is deleted, we quit the worker thread
|
||||
connect(_currentAssignment.data(), &ThreadedAssignment::destroyed, workerThread, &QThread::quit);
|
||||
_currentAssignment->moveToThread(workerThread);
|
||||
|
||||
// have the worker thread remove itself once it is done
|
||||
connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
|
||||
// Starts an event loop, and emits workerThread->started()
|
||||
workerThread->start();
|
||||
} else {
|
||||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
}
|
||||
|
||||
// once the worker thread says it is done, we consider the assignment completed
|
||||
connect(workerThread, &QThread::destroyed, this, &AssignmentClient::assignmentCompleted);
|
||||
void AssignmentClient::handleStopNodePacket(QSharedPointer<NLPacket> packet) {
|
||||
const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr();
|
||||
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode.";
|
||||
|
||||
_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) == PacketType::StopNode) {
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode.";
|
||||
|
||||
QCoreApplication::quit();
|
||||
} else {
|
||||
qDebug() << "Got a stop packet from other than localhost.";
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
QCoreApplication::quit();
|
||||
} else {
|
||||
qDebug() << "Got a stop packet from other than localhost.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,8 +330,8 @@ void AssignmentClient::assignmentCompleted() {
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// have us handle incoming NodeList datagrams again, and make sure our ThreadedAssignment isn't handling them
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams);
|
||||
// tell the packet receiver to stop dropping packets
|
||||
nodeList->getPacketReceiver().setShouldDropPackets(false);
|
||||
|
||||
// reset our NodeList by switching back to unassigned and clearing the list
|
||||
nodeList->setOwnerType(NodeType::Unassigned);
|
||||
|
|
|
@ -15,30 +15,35 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QPointer>
|
||||
|
||||
#include <PacketListener.h>
|
||||
|
||||
#include "ThreadedAssignment.h"
|
||||
|
||||
class QSharedMemory;
|
||||
|
||||
class AssignmentClient : public QObject {
|
||||
class AssignmentClient : public QObject, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
||||
quint16 assignmentMonitorPort);
|
||||
~AssignmentClient();
|
||||
private slots:
|
||||
void sendAssignmentRequest();
|
||||
void readPendingDatagrams();
|
||||
void assignmentCompleted();
|
||||
void handleAuthenticationRequest();
|
||||
void sendStatsPacketToACM();
|
||||
void sendStatusPacketToACM();
|
||||
void stopAssignmentClient();
|
||||
|
||||
public slots:
|
||||
void aboutToQuit();
|
||||
|
||||
private slots:
|
||||
void handleCreateAssignmentPacket(QSharedPointer<NLPacket> packet);
|
||||
void handleStopNodePacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
private:
|
||||
void setUpStatsToMonitor();
|
||||
void setUpStatusToMonitor();
|
||||
|
||||
Assignment _requestAssignment;
|
||||
QPointer<ThreadedAssignment> _currentAssignment;
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
//
|
||||
// AssignmentClientChildData.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 07/13/15.
|
||||
// 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 "AssignmentClientChildData.h"
|
||||
|
||||
|
||||
AssignmentClientChildData::AssignmentClientChildData(QString childType) :
|
||||
AssignmentClientChildData::AssignmentClientChildData(Assignment::Type childType) :
|
||||
_childType(childType)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -16,17 +16,14 @@
|
|||
|
||||
|
||||
class AssignmentClientChildData : public NodeData {
|
||||
public:
|
||||
AssignmentClientChildData(QString childType);
|
||||
public:
|
||||
AssignmentClientChildData(Assignment::Type childType);
|
||||
|
||||
QString getChildType() { return _childType; }
|
||||
void setChildType(QString childType) { _childType = childType; }
|
||||
Assignment::Type getChildType() { return _childType; }
|
||||
void setChildType(Assignment::Type childType) { _childType = childType; }
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
private:
|
||||
QString _childType;
|
||||
private:
|
||||
Assignment::Type _childType;
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentClientChildData_h
|
||||
|
|
|
@ -53,7 +53,8 @@ AssignmentClientMonitor::AssignmentClientMonitor(const unsigned int numAssignmen
|
|||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<LimitedNodeList>();
|
||||
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClientMonitor::readPendingDatagrams);
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssignmentClientStatus, this, "handleChildStatusPacket");
|
||||
|
||||
// use QProcess to fork off a process for each of the child assignment clients
|
||||
for (unsigned int i = 0; i < _numAssignmentClientForks; i++) {
|
||||
|
@ -172,9 +173,9 @@ void AssignmentClientMonitor::checkSpares() {
|
|||
nodeList->removeSilentNodes();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
AssignmentClientChildData* childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
totalCount ++;
|
||||
if (childData->getChildType() == "none") {
|
||||
if (childData->getChildType() == Assignment::Type::AllTypes) {
|
||||
spareCount ++;
|
||||
aSpareId = node->getUUID();
|
||||
}
|
||||
|
@ -201,63 +202,53 @@ void AssignmentClientMonitor::checkSpares() {
|
|||
}
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer<NLPacket> packet) {
|
||||
QUuid senderID = QUuid::fromRfc4122(QByteArray::fromRawData(packet->getData(), NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
SharedNodePointer matchingNode = nodeList->nodeWithUUID(senderID);
|
||||
const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr();
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
AssignmentClientChildData* childData = nullptr;
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketType::NodeJsonStats) {
|
||||
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (!matchingNode) {
|
||||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
if (!packetUUID.isNull()) {
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false);
|
||||
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "asking unknown child to exit.";
|
||||
|
||||
auto diePacket = NLPacket::create(PacketType::StopNode, 0);
|
||||
nodeList->sendPacket(std::move(diePacket), senderSockAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingNode) {
|
||||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
QVariantMap packetVariantMap =
|
||||
JSONBreakableMarshal::fromStringBuffer(receivedPacket.mid(numBytesForPacketHeader(receivedPacket)));
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(packetVariantMap);
|
||||
|
||||
// get child's assignment type out of the decoded json
|
||||
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||
AssignmentClientChildData *childData =
|
||||
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
childData->setChildType(childType);
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
if (!matchingNode) {
|
||||
// The parent only expects to be talking with prorams running on this same machine.
|
||||
if (senderSockAddr.getAddress() == QHostAddress::LocalHost ||
|
||||
senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) {
|
||||
|
||||
if (!senderID.isNull()) {
|
||||
// We don't have this node yet - we should add it
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(senderID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false, false);
|
||||
|
||||
childData = new AssignmentClientChildData(Assignment::Type::AllTypes);
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "Asking unknown child at" << senderSockAddr << "to exit.";
|
||||
|
||||
auto diePacket = NLPacket::create(PacketType::StopNode, 0);
|
||||
nodeList->sendPacket(std::move(diePacket), senderSockAddr);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
childData = dynamic_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
}
|
||||
|
||||
if (childData) {
|
||||
// update our records about how to reach this child
|
||||
matchingNode->setLocalSocket(senderSockAddr);
|
||||
|
||||
// get child's assignment type out of the packet
|
||||
quint8 assignmentType;
|
||||
packet->readPrimitive(&assignmentType);
|
||||
|
||||
childData->setChildType((Assignment::Type) assignmentType);
|
||||
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
|
||||
class AssignmentClientMonitor : public QObject {
|
||||
class AssignmentClientMonitor : public QObject, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientMonitor(const unsigned int numAssignmentClientForks, const unsigned int minAssignmentClientForks,
|
||||
|
@ -35,9 +35,9 @@ public:
|
|||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void readPendingDatagrams();
|
||||
void checkSpares();
|
||||
void childProcessFinished();
|
||||
void handleChildStatusPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
public slots:
|
||||
void aboutToQuit();
|
||||
|
|
|
@ -17,15 +17,13 @@
|
|||
#include "avatars/AvatarMixer.h"
|
||||
#include "entities/EntityServer.h"
|
||||
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(const QByteArray& packet) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
ThreadedAssignment* AssignmentFactory::unpackAssignment(NLPacket& packet) {
|
||||
|
||||
quint8 packedType;
|
||||
packetStream >> packedType;
|
||||
|
||||
packet.peekPrimitive(&packedType);
|
||||
|
||||
Assignment::Type unpackedType = (Assignment::Type) packedType;
|
||||
|
||||
|
||||
switch (unpackedType) {
|
||||
case Assignment::AudioMixerType:
|
||||
return new AudioMixer(packet);
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
class AssignmentFactory {
|
||||
public:
|
||||
static ThreadedAssignment* unpackAssignment(const QByteArray& packet);
|
||||
static ThreadedAssignment* unpackAssignment(NLPacket& packet);
|
||||
};
|
||||
|
||||
#endif // hifi_AssignmentFactory_h
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioMixerClientData.h"
|
||||
#include "AudioMixerDatagramProcessor.h"
|
||||
#include "AvatarAudioStream.h"
|
||||
#include "InjectedAudioStream.h"
|
||||
|
||||
|
@ -75,7 +74,7 @@ bool AudioMixer::shouldMute(float quietestFrame) {
|
|||
return (quietestFrame > _noiseMutingThreshold);
|
||||
}
|
||||
|
||||
AudioMixer::AudioMixer(const QByteArray& packet) :
|
||||
AudioMixer::AudioMixer(NLPacket& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_trailingSleepRatio(1.0f),
|
||||
_minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f),
|
||||
|
@ -94,6 +93,18 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
|
|||
{
|
||||
// constant defined in AudioMixer.h. However, we don't want to include this here
|
||||
// we will soon find a better common home for these audio-related constants
|
||||
// SOON
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
|
||||
QSet<PacketType::Value> nodeAudioPackets {
|
||||
PacketType::MicrophoneAudioNoEcho, PacketType::MicrophoneAudioWithEcho,
|
||||
PacketType::InjectAudio, PacketType::SilentAudioFrame,
|
||||
PacketType::AudioStreamStats
|
||||
};
|
||||
|
||||
packetReceiver.registerListenerForTypes(nodeAudioPackets, this, "handleNodeAudioPacket");
|
||||
packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket");
|
||||
}
|
||||
|
||||
const float ATTENUATION_BEGINS_AT_DISTANCE = 1.0f;
|
||||
|
@ -487,6 +498,7 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AudioMixerClientData* nodeData = static_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||
AvatarAudioStream* stream = nodeData->getAvatarAudioStream();
|
||||
bool dataChanged = (stream->hasReverb() != hasReverb) ||
|
||||
|
@ -532,37 +544,24 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
void AudioMixer::handleNodeAudioPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
DependencyManager::get<NodeList>()->updateNodeWithDataFromPacket(packet, sendingNode);
|
||||
}
|
||||
|
||||
void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (sendingNode->getCanAdjustLocks()) {
|
||||
auto newPacket = NLPacket::create(PacketType::MuteEnvironment, packet->getSizeUsed());
|
||||
// Copy payload
|
||||
newPacket->write(packet->getPayload(), packet->getSizeUsed());
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
// pull any new audio data from nodes off of the network stack
|
||||
PacketType::Value mixerPacketType = packetTypeForPacket(receivedPacket);
|
||||
if (mixerPacketType == PacketType::MicrophoneAudioNoEcho
|
||||
|| mixerPacketType == PacketType::MicrophoneAudioWithEcho
|
||||
|| mixerPacketType == PacketType::InjectAudio
|
||||
|| mixerPacketType == PacketType::SilentAudioFrame
|
||||
|| mixerPacketType == PacketType::AudioStreamStats) {
|
||||
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
} else if (mixerPacketType == PacketType::MuteEnvironment) {
|
||||
SharedNodePointer sendingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (sendingNode->getCanAdjustLocks()) {
|
||||
auto packet = NLPacket::create(PacketType::MuteEnvironment);
|
||||
// Copy payload
|
||||
packet->write(receivedPacket.mid(numBytesForPacketHeader(receivedPacket)));
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() &&
|
||||
node->getLinkedData() && node != sendingNode) {
|
||||
nodeList->sendPacket(std::move(packet), *node);
|
||||
}
|
||||
});
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
if (node->getType() == NodeType::Agent && node->getActiveSocket() &&
|
||||
node->getLinkedData() && node != sendingNode) {
|
||||
nodeList->sendPacket(std::move(newPacket), *node);
|
||||
}
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,32 +655,6 @@ void AudioMixer::run() {
|
|||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
||||
// setup a QThread with us as parent that will house the AudioMixerDatagramProcessor
|
||||
_datagramProcessingThread = new QThread(this);
|
||||
_datagramProcessingThread->setObjectName("Datagram Processor Thread");
|
||||
|
||||
// create an AudioMixerDatagramProcessor and move it to that thread
|
||||
AudioMixerDatagramProcessor* datagramProcessor = new AudioMixerDatagramProcessor(nodeList->getNodeSocket(), thread());
|
||||
datagramProcessor->moveToThread(_datagramProcessingThread);
|
||||
|
||||
// remove the NodeList as the parent of the node socket
|
||||
nodeList->getNodeSocket().setParent(NULL);
|
||||
nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
|
||||
|
||||
// let the datagram processor handle readyRead from node socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
|
||||
datagramProcessor, &AudioMixerDatagramProcessor::readPendingDatagrams);
|
||||
|
||||
// connect to the datagram processing thread signal that tells us we have to handle a packet
|
||||
connect(datagramProcessor, &AudioMixerDatagramProcessor::packetRequiresProcessing, this, &AudioMixer::readPendingDatagram);
|
||||
|
||||
// delete the datagram processor and the associated thread when the QThread quits
|
||||
connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
|
||||
connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
|
||||
|
||||
// start the datagram processing thread
|
||||
_datagramProcessingThread->start();
|
||||
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
nodeList->linkedDataCreateCallback = [](Node* node) {
|
||||
|
|
|
@ -28,20 +28,21 @@ const int READ_DATAGRAMS_STATS_WINDOW_SECONDS = 30;
|
|||
class AudioMixer : public ThreadedAssignment {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioMixer(const QByteArray& packet);
|
||||
AudioMixer(NLPacket& packet);
|
||||
|
||||
void deleteLater() { qDebug() << "DELETE LATER CALLED?"; QObject::deleteLater(); }
|
||||
public slots:
|
||||
/// threaded run of assignment
|
||||
void run();
|
||||
|
||||
void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle
|
||||
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
void sendStatsPacket();
|
||||
|
||||
static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; }
|
||||
|
||||
private slots:
|
||||
void handleNodeAudioPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void handleMuteEnvironmentPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
/// adds one stream to the mix for a listening node
|
||||
int addStreamToMixForListeningNodeWithStream(AudioMixerClientData* listenerNodeData,
|
||||
|
|
|
@ -49,20 +49,18 @@ AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() const {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int AudioMixerClientData::parseData(const QByteArray& packet) {
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
int AudioMixerClientData::parseData(NLPacket& packet) {
|
||||
PacketType::Value packetType = packet.getType();
|
||||
|
||||
if (packetType == PacketType::AudioStreamStats) {
|
||||
|
||||
const char* dataAt = packet.data();
|
||||
|
||||
// skip over header, appendFlag, and num stats packed
|
||||
dataAt += (numBytesForPacketHeader(packet) + sizeof(quint8) + sizeof(quint16));
|
||||
packet.seek(sizeof(quint8) + sizeof(quint16));
|
||||
|
||||
// read the downstream audio stream stats
|
||||
memcpy(&_downstreamAudioStreamStats, dataAt, sizeof(AudioStreamStats));
|
||||
dataAt += sizeof(AudioStreamStats);
|
||||
packet.readPrimitive(&_downstreamAudioStreamStats);
|
||||
|
||||
return dataAt - packet.data();
|
||||
return packet.pos();
|
||||
|
||||
} else {
|
||||
PositionalAudioStream* matchingStream = NULL;
|
||||
|
@ -76,8 +74,11 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
|
|||
// we don't have a mic stream yet, so add it
|
||||
|
||||
// read the channel flag to see if our stream is stereo or not
|
||||
const char* channelFlagAt = packet.constData() + numBytesForPacketHeader(packet) + sizeof(quint16);
|
||||
quint8 channelFlag = *(reinterpret_cast<const quint8*>(channelFlagAt));
|
||||
packet.seek(sizeof(quint16));
|
||||
|
||||
quint8 channelFlag;
|
||||
packet.readPrimitive(&channelFlag);
|
||||
|
||||
bool isStereo = channelFlag == 1;
|
||||
|
||||
_audioStreams.insert(nullUUID, matchingStream = new AvatarAudioStream(isStereo, AudioMixer::getStreamSettings()));
|
||||
|
@ -88,20 +89,24 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
|
|||
// this is injected audio
|
||||
|
||||
// grab the stream identifier for this injected audio
|
||||
int bytesBeforeStreamIdentifier = numBytesForPacketHeader(packet) + sizeof(quint16);
|
||||
QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(bytesBeforeStreamIdentifier, NUM_BYTES_RFC4122_UUID));
|
||||
int bytesBeforeStereoIdentifier = bytesBeforeStreamIdentifier + NUM_BYTES_RFC4122_UUID;
|
||||
packet.seek(sizeof(quint16));
|
||||
QUuid streamIdentifier = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
bool isStereo;
|
||||
QDataStream(packet.mid(bytesBeforeStereoIdentifier)) >> isStereo;
|
||||
packet.readPrimitive(&isStereo);
|
||||
|
||||
if (!_audioStreams.contains(streamIdentifier)) {
|
||||
// we don't have this injected stream yet, so add it
|
||||
_audioStreams.insert(streamIdentifier, matchingStream = new InjectedAudioStream(streamIdentifier, isStereo, AudioMixer::getStreamSettings()));
|
||||
_audioStreams.insert(streamIdentifier,
|
||||
matchingStream = new InjectedAudioStream(streamIdentifier, isStereo, AudioMixer::getStreamSettings()));
|
||||
} else {
|
||||
matchingStream = _audioStreams.value(streamIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
// seek to the beginning of the packet so that the next reader is in the right spot
|
||||
packet.seek(0);
|
||||
|
||||
return matchingStream->parseData(packet);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
class PerListenerSourcePairData {
|
||||
public:
|
||||
PerListenerSourcePairData() {
|
||||
PerListenerSourcePairData() {
|
||||
_penumbraFilter.initialize(AudioConstants::SAMPLE_RATE, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO / 2);
|
||||
};
|
||||
AudioFilterHSF1s& getPenumbraFilter() { return _penumbraFilter; }
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
const QHash<QUuid, PositionalAudioStream*>& getAudioStreams() const { return _audioStreams; }
|
||||
AvatarAudioStream* getAvatarAudioStream() const;
|
||||
|
||||
int parseData(const QByteArray& packet);
|
||||
int parseData(NLPacket& packet);
|
||||
|
||||
void checkBuffersBeforeFrameSend();
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// AudioMixerDatagramProcessor.cpp
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-08-14.
|
||||
// Copyright 2014 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 <QDebug>
|
||||
|
||||
#include <HifiSockAddr.h>
|
||||
#include <NodeList.h>
|
||||
|
||||
#include "AudioMixerDatagramProcessor.h"
|
||||
|
||||
AudioMixerDatagramProcessor::AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread) :
|
||||
_nodeSocket(nodeSocket),
|
||||
_previousNodeSocketThread(previousNodeSocketThread)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AudioMixerDatagramProcessor::~AudioMixerDatagramProcessor() {
|
||||
// return the node socket to its previous thread
|
||||
_nodeSocket.moveToThread(_previousNodeSocketThread);
|
||||
}
|
||||
|
||||
void AudioMixerDatagramProcessor::readPendingDatagrams() {
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
static QByteArray incomingPacket;
|
||||
|
||||
// read everything that is available
|
||||
while (_nodeSocket.hasPendingDatagrams()) {
|
||||
incomingPacket.resize(_nodeSocket.pendingDatagramSize());
|
||||
|
||||
// just get this packet off the stack
|
||||
_nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
// emit the signal to tell AudioMixer it needs to process a packet
|
||||
emit packetRequiresProcessing(incomingPacket, senderSockAddr);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// AudioMixerDatagramProcessor.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-08-14.
|
||||
// Copyright 2014 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_AudioMixerDatagramProcessor_h
|
||||
#define hifi_AudioMixerDatagramProcessor_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qudpsocket.h>
|
||||
|
||||
class AudioMixerDatagramProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread);
|
||||
~AudioMixerDatagramProcessor();
|
||||
public slots:
|
||||
void readPendingDatagrams();
|
||||
signals:
|
||||
void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
private:
|
||||
QUdpSocket& _nodeSocket;
|
||||
QThread* _previousNodeSocketThread;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioMixerDatagramProcessor_h
|
|
@ -33,7 +33,7 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer";
|
|||
const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 60;
|
||||
const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) * 1000;
|
||||
|
||||
AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
||||
AvatarMixer::AvatarMixer(NLPacket& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_broadcastThread(),
|
||||
_lastFrameTimestamp(QDateTime::currentMSecsSinceEpoch()),
|
||||
|
@ -46,6 +46,12 @@ AvatarMixer::AvatarMixer(const QByteArray& packet) :
|
|||
{
|
||||
// make sure we hear about node kills so we can tell the other nodes
|
||||
connect(DependencyManager::get<NodeList>().data(), &NodeList::nodeKilled, this, &AvatarMixer::nodeKilled);
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AvatarData, this, "handleAvatarDataPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "handleAvatarIdentityPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "handleAvatarBillboardPacket");
|
||||
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||
}
|
||||
|
||||
AvatarMixer::~AvatarMixer() {
|
||||
|
@ -394,65 +400,44 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::readPendingDatagrams() {
|
||||
QByteArray receivedPacket;
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
void AvatarMixer::handleAvatarDataPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->updateNodeWithDataFromPacket(packet, senderNode);
|
||||
}
|
||||
|
||||
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
switch (packetTypeForPacket(receivedPacket)) {
|
||||
case PacketType::AvatarData: {
|
||||
nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket);
|
||||
break;
|
||||
}
|
||||
case PacketType::AvatarIdentity: {
|
||||
// check if we have a matching node in our list
|
||||
SharedNodePointer avatarNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
if (senderNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
if (nodeData != nullptr) {
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
|
||||
if (avatarNode && avatarNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
|
||||
// parse the identity packet and update the change timestamp if appropriate
|
||||
if (avatar.hasIdentityChangedAfterParsing(receivedPacket)) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType::AvatarBillboard: {
|
||||
// check if we have a matching node in our list
|
||||
SharedNodePointer avatarNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
|
||||
if (avatarNode && avatarNode->getLinkedData()) {
|
||||
AvatarMixerClientData* nodeData = static_cast<AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
|
||||
// parse the billboard packet and update the change timestamp if appropriate
|
||||
if (avatar.hasBillboardChangedAfterParsing(receivedPacket)) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType::KillAvatar: {
|
||||
nodeList->processKillNode(receivedPacket);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// hand this off to the NodeList
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
break;
|
||||
// parse the identity packet and update the change timestamp if appropriate
|
||||
if (avatar.hasIdentityChangedAfterParsing(*packet)) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
AvatarMixerClientData* nodeData = dynamic_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
|
||||
// parse the billboard packet and update the change timestamp if appropriate
|
||||
if (avatar.hasBillboardChangedAfterParsing(*packet)) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixer::handleKillAvatarPacket(QSharedPointer<NLPacket> packet) {
|
||||
DependencyManager::get<NodeList>()->processKillNode(*packet);
|
||||
}
|
||||
|
||||
void AvatarMixer::sendStatsPacket() {
|
||||
QJsonObject statsObject;
|
||||
statsObject["average_listeners_last_second"] = (float) _sumListeners / (float) _numStatFrames;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
||||
class AvatarMixer : public ThreadedAssignment {
|
||||
public:
|
||||
AvatarMixer(const QByteArray& packet);
|
||||
AvatarMixer(NLPacket& packet);
|
||||
~AvatarMixer();
|
||||
public slots:
|
||||
/// runs the avatar mixer
|
||||
|
@ -29,9 +29,13 @@ public slots:
|
|||
void nodeAdded(SharedNodePointer nodeAdded);
|
||||
void nodeKilled(SharedNodePointer killedNode);
|
||||
|
||||
void readPendingDatagrams();
|
||||
|
||||
void sendStatsPacket();
|
||||
|
||||
private slots:
|
||||
void handleAvatarDataPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleAvatarIdentityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleAvatarBillboardPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleKillAvatarPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
private:
|
||||
void broadcastAvatarData();
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
int AvatarMixerClientData::parseData(const QByteArray& packet) {
|
||||
int AvatarMixerClientData::parseData(NLPacket& packet) {
|
||||
// compute the offset to the data payload
|
||||
int offset = numBytesForPacketHeader(packet);
|
||||
return _avatar.parseDataAtOffset(packet, offset);
|
||||
return _avatar.parseDataFromBuffer(QByteArray::fromRawData(packet.getPayload(), packet.getSizeUsed()));
|
||||
}
|
||||
|
||||
bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() {
|
||||
|
|
|
@ -31,13 +31,13 @@ const QString OUTBOUND_AVATAR_DATA_STATS_KEY = "outbound_av_data_kbps";
|
|||
class AvatarMixerClientData : public NodeData {
|
||||
Q_OBJECT
|
||||
public:
|
||||
int parseData(const QByteArray& packet);
|
||||
int parseData(NLPacket& packet);
|
||||
AvatarData& getAvatar() { return _avatar; }
|
||||
|
||||
bool checkAndSetHasReceivedFirstPackets();
|
||||
|
||||
PacketSequenceNumber getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const;
|
||||
void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, PacketSequenceNumber sequenceNumber)
|
||||
void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, PacketSequenceNumber sequenceNumber)
|
||||
{ _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; }
|
||||
Q_INVOKABLE void removeLastBroadcastSequenceNumber(const QUuid& nodeUUID) { _lastBroadcastSequenceNumbers.erase(nodeUUID); }
|
||||
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
void incrementNumAvatarsSentLastFrame() { ++_numAvatarsSentLastFrame; }
|
||||
int getNumAvatarsSentLastFrame() const { return _numAvatarsSentLastFrame; }
|
||||
|
||||
void recordNumOtherAvatarStarves(int numAvatarsHeldBack) { _otherAvatarStarves.updateAverage((float) numAvatarsHeldBack); }
|
||||
void recordNumOtherAvatarStarves(int numAvatarsHeldBack) { _otherAvatarStarves.updateAverage((float) numAvatarsHeldBack); }
|
||||
float getAvgNumOtherAvatarStarvesPerSecond() const { return _otherAvatarStarves.getAverageSampleValuePerSecond(); }
|
||||
|
||||
void recordNumOtherAvatarSkips(int numOtherAvatarSkips) { _otherAvatarSkips.updateAverage((float) numOtherAvatarSkips); }
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
|
||||
void recordSentAvatarData(int numBytes) { _avgOtherAvatarDataRate.updateAverage((float) numBytes); }
|
||||
|
||||
float getOutboundAvatarDataKbps() const
|
||||
float getOutboundAvatarDataKbps() const
|
||||
{ return _avgOtherAvatarDataRate.getAverageSampleValuePerSecond() / (float) BYTES_PER_KILOBIT; }
|
||||
|
||||
void loadJSONStats(QJsonObject& jsonObject) const;
|
||||
|
|
|
@ -21,9 +21,13 @@ const char* MODEL_SERVER_NAME = "Entity";
|
|||
const char* MODEL_SERVER_LOGGING_TARGET_NAME = "entity-server";
|
||||
const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
|
||||
|
||||
EntityServer::EntityServer(const QByteArray& packet)
|
||||
: OctreeServer(packet), _entitySimulation(NULL) {
|
||||
// nothing special to do here...
|
||||
EntityServer::EntityServer(NLPacket& packet) :
|
||||
OctreeServer(packet),
|
||||
_entitySimulation(NULL)
|
||||
{
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityEdit, PacketType::EntityErase },
|
||||
this, "handleEntityPacket");
|
||||
}
|
||||
|
||||
EntityServer::~EntityServer() {
|
||||
|
@ -36,6 +40,12 @@ EntityServer::~EntityServer() {
|
|||
tree->removeNewlyCreatedHook(this);
|
||||
}
|
||||
|
||||
void EntityServer::handleEntityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
if (_octreeInboundPacketProcessor) {
|
||||
_octreeInboundPacketProcessor->queueReceivedPacket(packet, senderNode);
|
||||
}
|
||||
}
|
||||
|
||||
OctreeQueryNode* EntityServer::createOctreeQueryNode() {
|
||||
return new EntityNodeData();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityServer(const QByteArray& packet);
|
||||
EntityServer(NLPacket& packet);
|
||||
~EntityServer();
|
||||
|
||||
// Subclasses must implement these methods
|
||||
|
@ -49,6 +49,9 @@ public slots:
|
|||
protected:
|
||||
virtual Octree* createTree();
|
||||
|
||||
private slots:
|
||||
void handleEntityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
|
||||
private:
|
||||
EntitySimulation* _entitySimulation;
|
||||
QTimer* _pruneDeletedEntitiesTimer = nullptr;
|
||||
|
|
|
@ -74,7 +74,7 @@ void OctreeInboundPacketProcessor::midProcess() {
|
|||
}
|
||||
}
|
||||
|
||||
void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
void OctreeInboundPacketProcessor::processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
if (_shuttingDown) {
|
||||
qDebug() << "OctreeInboundPacketProcessor::processPacket() while shutting down... ignoring incoming packet";
|
||||
return;
|
||||
|
@ -83,22 +83,24 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
bool debugProcessPacket = _myServer->wantsVerboseDebug();
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() packetData=%p packetLength=%d", &packet, packet.size());
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() payload=%p payloadLength=%lld",
|
||||
packet->getPayload(),
|
||||
packet->getSizeUsed());
|
||||
}
|
||||
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
|
||||
|
||||
// Ask our tree subclass if it can handle the incoming packet...
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
PacketType::Value packetType = packet->getType();
|
||||
|
||||
if (_myServer->getOctree()->handlesEditPacketType(packetType)) {
|
||||
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE",debugProcessPacket);
|
||||
PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket);
|
||||
_receivedPacketCount++;
|
||||
|
||||
const unsigned char* packetData = reinterpret_cast<const unsigned char*>(packet.data());
|
||||
unsigned short int sequence;
|
||||
packet->readPrimitive(&sequence);
|
||||
|
||||
unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
|
||||
quint64 sentAt = (*((quint64*)(packetData + numBytesPacketHeader + sizeof(sequence))));
|
||||
quint64 sentAt;
|
||||
packet->readPrimitive(&sentAt);
|
||||
|
||||
quint64 arrivedAt = usecTimestampNow();
|
||||
if (sentAt > arrivedAt) {
|
||||
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
|
||||
|
@ -107,6 +109,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
}
|
||||
sentAt = arrivedAt;
|
||||
}
|
||||
|
||||
quint64 transitTime = arrivedAt - sentAt;
|
||||
int editsInPacket = 0;
|
||||
quint64 processTime = 0;
|
||||
|
@ -114,7 +117,7 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
|
||||
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
|
||||
qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
|
||||
qDebug() << " receivedBytes=" << packet.size();
|
||||
qDebug() << " receivedBytes=" << packet->getSizeWithHeader();
|
||||
qDebug() << " sequence=" << sequence;
|
||||
qDebug() << " sentAt=" << sentAt << " usecs";
|
||||
qDebug() << " arrivedAt=" << arrivedAt << " usecs";
|
||||
|
@ -125,42 +128,41 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
}
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << " numBytesPacketHeader=" << numBytesPacketHeader;
|
||||
qDebug() << " numBytesPacketHeader=" << packet->localHeaderSize();
|
||||
qDebug() << " sizeof(sequence)=" << sizeof(sequence);
|
||||
qDebug() << " sizeof(sentAt)=" << sizeof(sentAt);
|
||||
}
|
||||
|
||||
int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt);
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << " atByte=" << atByte;
|
||||
qDebug() << " packet.size()=" << packet.size();
|
||||
if (atByte >= packet.size()) {
|
||||
qDebug() << " atByte (in payload)=" << packet->pos();
|
||||
qDebug() << " payload size=" << packet->getSizeUsed();
|
||||
if (!packet->bytesAvailable()) {
|
||||
qDebug() << " ----- UNEXPECTED ---- got a packet without any edit details!!!! --------";
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char* editData = nullptr;
|
||||
|
||||
while (packet->bytesAvailable() > 0) {
|
||||
|
||||
unsigned char* editData = (unsigned char*)&packetData[atByte];
|
||||
while (atByte < packet.size()) {
|
||||
editData = reinterpret_cast<const unsigned char*>(packet->getPayload() + packet->pos());
|
||||
|
||||
int maxSize = packet.size() - atByte;
|
||||
int maxSize = packet->bytesAvailable();
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << " --- inside while loop ---";
|
||||
qDebug() << " maxSize=" << maxSize;
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() %c "
|
||||
"packetData=%p packetLength=%d editData=%p atByte=%d maxSize=%d",
|
||||
packetType, packetData, packet.size(), editData, atByte, maxSize);
|
||||
"payload=%p payloadLength=%lld editData=%p payloadPosition=%lld maxSize=%d",
|
||||
packetType, packet->getPayload(), packet->getSizeUsed(), editData,
|
||||
packet->pos(), maxSize);
|
||||
}
|
||||
|
||||
quint64 startLock = usecTimestampNow();
|
||||
_myServer->getOctree()->lockForWrite();
|
||||
quint64 startProcess = usecTimestampNow();
|
||||
int editDataBytesRead = _myServer->getOctree()->processEditPacketData(packetType,
|
||||
reinterpret_cast<const unsigned char*>(packet.data()),
|
||||
packet.size(),
|
||||
editData, maxSize, sendingNode);
|
||||
int editDataBytesRead =
|
||||
_myServer->getOctree()->processEditPacketData(*packet, editData, maxSize, sendingNode);
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << "OctreeInboundPacketProcessor::processPacket() after processEditPacketData()..."
|
||||
|
@ -177,27 +179,25 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
|
|||
lockWaitTime += thisLockWaitTime;
|
||||
|
||||
// skip to next edit record in the packet
|
||||
editData += editDataBytesRead;
|
||||
atByte += editDataBytesRead;
|
||||
packet->seek(packet->pos() + editDataBytesRead);
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << " editDataBytesRead=" << editDataBytesRead;
|
||||
qDebug() << " AFTER processEditPacketData atByte=" << atByte;
|
||||
qDebug() << " AFTER processEditPacketData packet.size()=" << packet.size();
|
||||
qDebug() << " AFTER processEditPacketData payload position=" << packet->pos();
|
||||
qDebug() << " AFTER processEditPacketData payload size=" << packet->getSizeUsed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (debugProcessPacket) {
|
||||
qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %c "
|
||||
"packetData=%p packetLength=%d editData=%p atByte=%d",
|
||||
packetType, packetData, packet.size(), editData, atByte);
|
||||
"payload=%p payloadLength=%lld editData=%p payloadPosition=%lld",
|
||||
packetType, packet->getPayload(), packet->getSizeUsed(), editData, packet->pos());
|
||||
}
|
||||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
QUuid& nodeUUID = DEFAULT_NODE_ID_REF;
|
||||
if (sendingNode) {
|
||||
sendingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
nodeUUID = sendingNode->getUUID();
|
||||
if (debugProcessPacket) {
|
||||
qDebug() << "sender has uuid=" << nodeUUID;
|
||||
|
|
|
@ -29,9 +29,9 @@ public:
|
|||
quint64 getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; }
|
||||
quint64 getTotalElementsProcessed() const { return _totalElementsInPacket; }
|
||||
quint64 getTotalPacketsProcessed() const { return _totalPackets; }
|
||||
quint64 getAverageProcessTimePerElement() const
|
||||
quint64 getAverageProcessTimePerElement() const
|
||||
{ return _totalElementsInPacket == 0 ? 0 : _totalProcessTime / _totalElementsInPacket; }
|
||||
quint64 getAverageLockWaitTimePerElement() const
|
||||
quint64 getAverageLockWaitTimePerElement() const
|
||||
{ return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; }
|
||||
|
||||
const SequenceNumberStats& getIncomingEditSequenceNumberStats() const { return _incomingEditSequenceNumberStats; }
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
void trackInboundPacket(unsigned short int incomingSequence, quint64 transitTime,
|
||||
int editsInPacket, quint64 processTime, quint64 lockWaitTime);
|
||||
|
||||
quint64 _totalTransitTime;
|
||||
quint64 _totalTransitTime;
|
||||
quint64 _totalProcessTime;
|
||||
quint64 _totalLockWaitTime;
|
||||
quint64 _totalElementsInPacket;
|
||||
|
@ -53,7 +53,7 @@ typedef QHash<QUuid, SingleSenderStats>::iterator NodeToSenderStatsMapIterator;
|
|||
typedef QHash<QUuid, SingleSenderStats>::const_iterator NodeToSenderStatsMapConstIterator;
|
||||
|
||||
|
||||
/// Handles processing of incoming network packets for the octee servers. As with other ReceivedPacketProcessor classes
|
||||
/// Handles processing of incoming network packets for the octee servers. As with other ReceivedPacketProcessor classes
|
||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
class OctreeInboundPacketProcessor : public ReceivedPacketProcessor {
|
||||
Q_OBJECT
|
||||
|
@ -65,9 +65,9 @@ public:
|
|||
quint64 getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; }
|
||||
quint64 getTotalElementsProcessed() const { return _totalElementsInPacket; }
|
||||
quint64 getTotalPacketsProcessed() const { return _totalPackets; }
|
||||
quint64 getAverageProcessTimePerElement() const
|
||||
quint64 getAverageProcessTimePerElement() const
|
||||
{ return _totalElementsInPacket == 0 ? 0 : _totalProcessTime / _totalElementsInPacket; }
|
||||
quint64 getAverageLockWaitTimePerElement() const
|
||||
quint64 getAverageLockWaitTimePerElement() const
|
||||
{ return _totalElementsInPacket == 0 ? 0 : _totalLockWaitTime / _totalElementsInPacket; }
|
||||
|
||||
void resetStats();
|
||||
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
virtual void processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
virtual unsigned long getMaxWait() const;
|
||||
virtual void preProcess();
|
||||
|
@ -88,13 +88,13 @@ private:
|
|||
int sendNackPackets();
|
||||
|
||||
private:
|
||||
void trackInboundPacket(const QUuid& nodeUUID, unsigned short int sequence, quint64 transitTime,
|
||||
void trackInboundPacket(const QUuid& nodeUUID, unsigned short int sequence, quint64 transitTime,
|
||||
int elementsInPacket, quint64 processTime, quint64 lockWaitTime);
|
||||
|
||||
OctreeServer* _myServer;
|
||||
int _receivedPacketCount;
|
||||
|
||||
quint64 _totalTransitTime;
|
||||
quint64 _totalTransitTime;
|
||||
quint64 _totalProcessTime;
|
||||
quint64 _totalLockWaitTime;
|
||||
quint64 _totalElementsInPacket;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include "OctreeServer.h"
|
||||
#include "OctreeServerConsts.h"
|
||||
#include "OctreeServerDatagramProcessor.h"
|
||||
|
||||
OctreeServer* OctreeServer::_instance = NULL;
|
||||
int OctreeServer::_clientCount = 0;
|
||||
|
@ -213,7 +212,7 @@ void OctreeServer::trackProcessWaitTime(float time) {
|
|||
_averageProcessWaitTime.updateAverage(time);
|
||||
}
|
||||
|
||||
OctreeServer::OctreeServer(const QByteArray& packet) :
|
||||
OctreeServer::OctreeServer(NLPacket& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_argc(0),
|
||||
_argv(NULL),
|
||||
|
@ -813,79 +812,29 @@ void OctreeServer::parsePayload() {
|
|||
}
|
||||
}
|
||||
|
||||
void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
void OctreeServer::handleOctreeQueryPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
// If we got a query packet, then we're talking to an agent, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->updateNodeWithDataFromPacket(packet, senderNode);
|
||||
|
||||
// If we know we're shutting down we just drop these packets on the floor.
|
||||
// This stops us from initializing send threads we just shut down.
|
||||
|
||||
if (!_isShuttingDown) {
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType::Value packetType = packetTypeForPacket(receivedPacket);
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (packetType == getMyQueryMessageType()) {
|
||||
// If we got a query packet, then we're talking to an agent, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
if (matchingNode) {
|
||||
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
|
||||
|
||||
OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
|
||||
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
||||
nodeData->initializeOctreeSendThread(this, matchingNode);
|
||||
}
|
||||
}
|
||||
} else if (packetType == PacketType::OctreeDataNack) {
|
||||
// If we got a nack packet, then we're talking to an agent, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
if (matchingNode) {
|
||||
OctreeQueryNode* nodeData = (OctreeQueryNode*)matchingNode->getLinkedData();
|
||||
if (nodeData) {
|
||||
nodeData->parseNackPacket(receivedPacket);
|
||||
}
|
||||
}
|
||||
} else if (packetType == PacketType::JurisdictionRequest) {
|
||||
_jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket);
|
||||
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
|
||||
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
|
||||
} else {
|
||||
// let processNodeData handle it.
|
||||
DependencyManager::get<NodeList>()->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
}
|
||||
OctreeQueryNode* nodeData = dynamic_cast<OctreeQueryNode*>(senderNode->getLinkedData());
|
||||
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
|
||||
nodeData->initializeOctreeSendThread(this, senderNode);
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeServer::setupDatagramProcessingThread() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
void OctreeServer::handleOctreeDataNackPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
// If we got a nack packet, then we're talking to an agent, and we
|
||||
// need to make sure we have it in our nodeList.
|
||||
OctreeQueryNode* nodeData = dynamic_cast<OctreeQueryNode*>(senderNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
nodeData->parseNackPacket(packet->getData());
|
||||
}
|
||||
}
|
||||
|
||||
// we do not want this event loop to be the handler for UDP datagrams, so disconnect
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
||||
// setup a QThread with us as parent that will house the OctreeServerDatagramProcessor
|
||||
_datagramProcessingThread = new QThread(this);
|
||||
_datagramProcessingThread->setObjectName("Octree Datagram Processor");
|
||||
|
||||
// create an OctreeServerDatagramProcessor and move it to that thread
|
||||
OctreeServerDatagramProcessor* datagramProcessor = new OctreeServerDatagramProcessor(nodeList->getNodeSocket(), thread());
|
||||
datagramProcessor->moveToThread(_datagramProcessingThread);
|
||||
|
||||
// remove the NodeList as the parent of the node socket
|
||||
nodeList->getNodeSocket().setParent(NULL);
|
||||
nodeList->getNodeSocket().moveToThread(_datagramProcessingThread);
|
||||
|
||||
// let the datagram processor handle readyRead from node socket
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead,
|
||||
datagramProcessor, &OctreeServerDatagramProcessor::readPendingDatagrams);
|
||||
|
||||
// connect to the datagram processing thread signal that tells us we have to handle a packet
|
||||
connect(datagramProcessor, &OctreeServerDatagramProcessor::packetRequiresProcessing, this, &OctreeServer::readPendingDatagram);
|
||||
|
||||
// delete the datagram processor and the associated thread when the QThread quits
|
||||
connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater);
|
||||
connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater);
|
||||
|
||||
// start the datagram processing thread
|
||||
_datagramProcessingThread->start();
|
||||
void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
_jurisdictionSender->queueReceivedPacket(packet, senderNode);
|
||||
}
|
||||
|
||||
bool OctreeServer::readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result) {
|
||||
|
@ -1078,6 +1027,12 @@ void OctreeServer::readConfiguration() {
|
|||
}
|
||||
|
||||
void OctreeServer::run() {
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(getMyQueryMessageType(), this, "handleOctreeQueryPacket");
|
||||
packetReceiver.registerListener(PacketType::OctreeDataNack, this, "handleOctreeDataNackPacket");
|
||||
packetReceiver.registerListener(PacketType::JurisdictionRequest, this, "handleJurisdictionRequestPacket");
|
||||
|
||||
_safeServerName = getMyServerName();
|
||||
|
||||
// Before we do anything else, create our tree...
|
||||
|
@ -1093,15 +1048,13 @@ void OctreeServer::run() {
|
|||
// use common init to setup common timers and logging
|
||||
commonInit(getMyLoggingServerTargetName(), getMyNodeType());
|
||||
|
||||
setupDatagramProcessingThread();
|
||||
|
||||
// read the configuration from either the payload or the domain server configuration
|
||||
readConfiguration();
|
||||
|
||||
beforeRun(); // after payload has been processed
|
||||
|
||||
connect(nodeList.data(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
|
||||
connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
|
||||
connect(nodeList.data(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(nodeKilled(SharedNodePointer)));
|
||||
|
||||
|
||||
// we need to ask the DS about agents so we can ping/reply with them
|
||||
|
@ -1169,7 +1122,7 @@ void OctreeServer::nodeKilled(SharedNodePointer node) {
|
|||
_octreeInboundPacketProcessor->nodeKilled(node);
|
||||
|
||||
qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node;
|
||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||
OctreeQueryNode* nodeData = dynamic_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
nodeData->nodeKilled(); // tell our node data and sending threads that we'd like to shut down
|
||||
} else {
|
||||
|
@ -1187,7 +1140,7 @@ void OctreeServer::forceNodeShutdown(SharedNodePointer node) {
|
|||
quint64 start = usecTimestampNow();
|
||||
|
||||
qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node;
|
||||
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||
OctreeQueryNode* nodeData = dynamic_cast<OctreeQueryNode*>(node->getLinkedData());
|
||||
if (nodeData) {
|
||||
nodeData->forceNodeShutdown(); // tell our node data and sending threads that we'd like to shut down
|
||||
} else {
|
||||
|
|
|
@ -32,7 +32,7 @@ const int DEFAULT_PACKETS_PER_INTERVAL = 2000; // some 120,000 packets per secon
|
|||
class OctreeServer : public ThreadedAssignment, public HTTPRequestHandler {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OctreeServer(const QByteArray& packet);
|
||||
OctreeServer(NLPacket& packet);
|
||||
~OctreeServer();
|
||||
|
||||
/// allows setting of run arguments
|
||||
|
@ -125,8 +125,10 @@ public slots:
|
|||
void nodeKilled(SharedNodePointer node);
|
||||
void sendStatsPacket();
|
||||
|
||||
void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle
|
||||
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
private slots:
|
||||
void handleOctreeQueryPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleOctreeDataNackPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
void handleJurisdictionRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
|
||||
protected:
|
||||
virtual Octree* createTree() = 0;
|
||||
|
@ -143,8 +145,6 @@ protected:
|
|||
QString getConfiguration();
|
||||
QString getStatusLink();
|
||||
|
||||
void setupDatagramProcessingThread();
|
||||
|
||||
int _argc;
|
||||
const char** _argv;
|
||||
char** _parsedArgV;
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// OctreeServerDatagramProcessor.h
|
||||
// assignment-client/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2014-09-05
|
||||
// Copyright 2014 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_OctreeServerDatagramProcessor_h
|
||||
#define hifi_OctreeServerDatagramProcessor_h
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qudpsocket.h>
|
||||
|
||||
class OctreeServerDatagramProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OctreeServerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread);
|
||||
~OctreeServerDatagramProcessor();
|
||||
public slots:
|
||||
void readPendingDatagrams();
|
||||
signals:
|
||||
void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
private:
|
||||
QUdpSocket& _nodeSocket;
|
||||
QThread* _previousNodeSocketThread;
|
||||
};
|
||||
|
||||
#endif // hifi_OctreeServerDatagramProcessor_h
|
|
@ -111,6 +111,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
}
|
||||
|
||||
void DomainServer::aboutToQuit() {
|
||||
|
||||
// clear the log handler so that Qt doesn't call the destructor on LogHandler
|
||||
qInstallMessageHandler(0);
|
||||
}
|
||||
|
@ -278,7 +279,16 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
|||
connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, &DomainServer::nodeAdded);
|
||||
connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &DomainServer::nodeKilled);
|
||||
|
||||
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readAvailableDatagrams()));
|
||||
// register as the packet receiver for the types we want
|
||||
PacketReceiver& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::RequestAssignment, this, "processRequestAssignmentPacket");
|
||||
packetReceiver.registerListener(PacketType::DomainConnectRequest, this, "processConnectRequestPackets");
|
||||
packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket");
|
||||
packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
|
||||
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
|
||||
packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket");
|
||||
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, this, "processICEPeerInformationPacket");
|
||||
|
||||
// add whatever static assignments that have been parsed to the queue
|
||||
addStaticAssignmentsToQueue();
|
||||
|
@ -566,17 +576,18 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
|||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||
<< NodeType::AvatarMixer << NodeType::EntityServer;
|
||||
|
||||
void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
void DomainServer::processConnectRequestPacket(QSharedPointer<NLPacket> packet) {
|
||||
NodeType_t nodeType;
|
||||
HifiSockAddr publicSockAddr, localSockAddr;
|
||||
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
QUuid connectUUID;
|
||||
packetStream >> connectUUID;
|
||||
|
||||
parseNodeDataFromByteArray(packetStream, nodeType, publicSockAddr, localSockAddr, senderSockAddr);
|
||||
const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr();
|
||||
|
||||
parseNodeData(packetStream, nodeType, publicSockAddr, localSockAddr, senderSockAddr);
|
||||
|
||||
// check if this connect request matches an assignment in the queue
|
||||
bool isAssignment = _pendingAssignedNodes.contains(connectUUID);
|
||||
|
@ -715,6 +726,24 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
|
||||
NodeType_t throwawayNodeType;
|
||||
HifiSockAddr nodePublicAddress, nodeLocalAddress;
|
||||
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
parseNodeData(packetStream, throwawayNodeType, nodePublicAddress, nodeLocalAddress, packet->getSenderSockAddr());
|
||||
|
||||
sendingNode->setPublicSocket(nodePublicAddress);
|
||||
sendingNode->setLocalSocket(nodeLocalAddress);
|
||||
|
||||
QList<NodeType_t> nodeInterestList;
|
||||
packetStream >> nodeInterestList;
|
||||
|
||||
sendDomainListToNode(sendingNode, packet->getSenderSockAddr(), nodeInterestList.toSet());
|
||||
}
|
||||
|
||||
unsigned int DomainServer::countConnectedUsers() {
|
||||
unsigned int result = 0;
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
@ -902,9 +931,9 @@ QUrl DomainServer::oauthAuthorizationURL(const QUuid& stateUUID) {
|
|||
return authorizationURL;
|
||||
}
|
||||
|
||||
int DomainServer::parseNodeDataFromByteArray(QDataStream& packetStream, NodeType_t& nodeType,
|
||||
HifiSockAddr& publicSockAddr, HifiSockAddr& localSockAddr,
|
||||
const HifiSockAddr& senderSockAddr) {
|
||||
int DomainServer::parseNodeData(QDataStream& packetStream, NodeType_t& nodeType,
|
||||
HifiSockAddr& publicSockAddr, HifiSockAddr& localSockAddr,
|
||||
const HifiSockAddr& senderSockAddr) {
|
||||
packetStream >> nodeType;
|
||||
packetStream >> publicSockAddr >> localSockAddr;
|
||||
|
||||
|
@ -933,15 +962,17 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
|||
// always send the node their own UUID back
|
||||
QDataStream domainListStream(&domainListPackets);
|
||||
|
||||
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + 2;
|
||||
const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NUM_BYTES_RFC4122_UUID + 2;
|
||||
|
||||
// setup the extended header for the domain list packets
|
||||
// this data is at the beginning of each of the domain list packets
|
||||
QByteArray extendedHeader(NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES, 0);
|
||||
extendedHeader.replace(0, NUM_BYTES_RFC4122_UUID, node->getUUID().toRfc4122());
|
||||
QDataStream extendedHeaderStream(&extendedHeader, QIODevice::Append);
|
||||
|
||||
extendedHeader[NUM_BYTES_RFC4122_UUID] = (char) node->getCanAdjustLocks();
|
||||
extendedHeader[NUM_BYTES_RFC4122_UUID + 1] = (char) node->getCanRez();
|
||||
extendedHeaderStream << limitedNodeList->getSessionUUID().toRfc4122();
|
||||
extendedHeaderStream << node->getUUID().toRfc4122();
|
||||
extendedHeaderStream << (quint8) node->getCanAdjustLocks();
|
||||
extendedHeaderStream << (quint8) node->getCanRez();
|
||||
|
||||
domainListPackets.setExtendedHeader(extendedHeader);
|
||||
|
||||
|
@ -1035,97 +1066,68 @@ void DomainServer::broadcastNewNode(const SharedNodePointer& addedNode) {
|
|||
);
|
||||
}
|
||||
|
||||
void DomainServer::readAvailableDatagrams() {
|
||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||
void DomainServer::processRequestAssignmentPacket(QSharedPointer<NLPacket> packet) {
|
||||
// construct the requested assignment from the packet data
|
||||
Assignment requestAssignment(*packet);
|
||||
|
||||
HifiSockAddr senderSockAddr;
|
||||
QByteArray receivedPacket;
|
||||
// Suppress these for Assignment::AgentType to once per 5 seconds
|
||||
static QElapsedTimer noisyMessageTimer;
|
||||
static bool wasNoisyTimerStarted = false;
|
||||
|
||||
while (limitedNodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
receivedPacket.resize(limitedNodeList->getNodeSocket().pendingDatagramSize());
|
||||
limitedNodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
if (packetTypeForPacket(receivedPacket) == PacketType::RequestAssignment
|
||||
&& limitedNodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (!wasNoisyTimerStarted) {
|
||||
noisyMessageTimer.start();
|
||||
wasNoisyTimerStarted = true;
|
||||
}
|
||||
|
||||
// construct the requested assignment from the packet data
|
||||
Assignment requestAssignment(receivedPacket);
|
||||
const qint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000;
|
||||
|
||||
// Suppress these for Assignment::AgentType to once per 5 seconds
|
||||
static QElapsedTimer noisyMessageTimer;
|
||||
static bool wasNoisyTimerStarted = false;
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << packet->getSenderSockAddr();
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
|
||||
if (!wasNoisyTimerStarted) {
|
||||
noisyMessageTimer.start();
|
||||
wasNoisyTimerStarted = true;
|
||||
}
|
||||
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
||||
|
||||
const qint64 NOISY_MESSAGE_INTERVAL_MSECS = 5 * 1000;
|
||||
if (assignmentToDeploy) {
|
||||
qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << packet->getSenderSockAddr();
|
||||
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Received a request for assignment type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
// give this assignment out, either the type matches or the requestor said they will take any
|
||||
static std::unique_ptr<NLPacket> assignmentPacket;
|
||||
|
||||
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
|
||||
if (!assignmentPacket) {
|
||||
assignmentPacket = NLPacket::create(PacketType::CreateAssignment);
|
||||
}
|
||||
|
||||
if (assignmentToDeploy) {
|
||||
qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << senderSockAddr;
|
||||
// setup a copy of this assignment that will have a unique UUID, for packaging purposes
|
||||
Assignment uniqueAssignment(*assignmentToDeploy.data());
|
||||
uniqueAssignment.setUUID(QUuid::createUuid());
|
||||
|
||||
// give this assignment out, either the type matches or the requestor said they will take any
|
||||
static std::unique_ptr<NLPacket> assignmentPacket;
|
||||
// reset the assignmentPacket
|
||||
assignmentPacket->reset();
|
||||
|
||||
if (!assignmentPacket) {
|
||||
assignmentPacket = NLPacket::create(PacketType::CreateAssignment);
|
||||
}
|
||||
QDataStream assignmentStream(assignmentPacket.get());
|
||||
|
||||
// setup a copy of this assignment that will have a unique UUID, for packaging purposes
|
||||
Assignment uniqueAssignment(*assignmentToDeploy.data());
|
||||
uniqueAssignment.setUUID(QUuid::createUuid());
|
||||
assignmentStream << uniqueAssignment;
|
||||
|
||||
// reset the assignmentPacket
|
||||
assignmentPacket->reset();
|
||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||
limitedNodeList->sendUnreliablePacket(*assignmentPacket, packet->getSenderSockAddr());
|
||||
|
||||
QDataStream assignmentStream(assignmentPacket.get());
|
||||
|
||||
assignmentStream << uniqueAssignment;
|
||||
|
||||
limitedNodeList->sendUnreliablePacket(*assignmentPacket, senderSockAddr);
|
||||
|
||||
// add the information for that deployed assignment to the hash of pending assigned nodes
|
||||
PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(),
|
||||
requestAssignment.getWalletUUID());
|
||||
_pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData);
|
||||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << senderSockAddr;
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
}
|
||||
} else if (!_isUsingDTLS) {
|
||||
// not using DTLS, process datagram normally
|
||||
processDatagram(receivedPacket, senderSockAddr);
|
||||
} else {
|
||||
// we're using DTLS, so tell the sender to get back to us using DTLS
|
||||
static std::unique_ptr<NLPacket> dtlsRequiredPacket;
|
||||
|
||||
if (!dtlsRequiredPacket) {
|
||||
dtlsRequiredPacket = NLPacket::create(PacketType::DomainServerRequireDTLS, sizeof(unsigned short));
|
||||
|
||||
// pack the port that we accept DTLS traffic on
|
||||
unsigned short dtlsPort = limitedNodeList->getDTLSSocket().localPort();
|
||||
dtlsRequiredPacket->writePrimitive(dtlsPort);
|
||||
}
|
||||
|
||||
limitedNodeList->sendUnreliablePacket(*dtlsRequiredPacket, senderSockAddr);
|
||||
// add the information for that deployed assignment to the hash of pending assigned nodes
|
||||
PendingAssignedNodeData* pendingNodeData = new PendingAssignedNodeData(assignmentToDeploy->getUUID(),
|
||||
requestAssignment.getWalletUUID());
|
||||
_pendingAssignedNodes.insert(uniqueAssignment.getUUID(), pendingNodeData);
|
||||
} else {
|
||||
if (requestAssignment.getType() != Assignment::AgentType
|
||||
|| noisyMessageTimer.elapsed() > NOISY_MESSAGE_INTERVAL_MSECS) {
|
||||
static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex
|
||||
("Unable to fulfill assignment request of type [^ ]+ from [^ ]+");
|
||||
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
|
||||
<< "from" << packet->getSenderSockAddr();
|
||||
noisyMessageTimer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1353,11 +1355,10 @@ void DomainServer::handlePeerPingTimeout() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::processICEPeerInformation(const QByteArray& packet) {
|
||||
void DomainServer::processICEPeerInformationPacket(QSharedPointer<NLPacket> packet) {
|
||||
// loop through the packet and pull out network peers
|
||||
// any peer we don't have we add to the hash, otherwise we update
|
||||
QDataStream iceResponseStream(packet);
|
||||
iceResponseStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
QDataStream iceResponseStream(packet.data());
|
||||
|
||||
NetworkPeer* receivedPeer = new NetworkPeer;
|
||||
iceResponseStream >> *receivedPeer;
|
||||
|
@ -1382,86 +1383,31 @@ void DomainServer::processICEPeerInformation(const QByteArray& packet) {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr) {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||
void DomainServer::processICEPingPacket(QSharedPointer<NLPacket> packet) {
|
||||
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||
auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*packet, limitedNodeList->getSessionUUID());
|
||||
|
||||
limitedNodeList->sendPacket(std::move(pingReplyPacket), packet->getSenderSockAddr());
|
||||
}
|
||||
|
||||
void DomainServer::processICEPingReplyPacket(QSharedPointer<NLPacket> packet) {
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
QUuid nodeUUID;
|
||||
packetStream >> nodeUUID;
|
||||
|
||||
SharedNetworkPeer sendingPeer = _icePeers.value(nodeUUID);
|
||||
|
||||
if (sendingPeer) {
|
||||
// we had this NetworkPeer in our connecting list - add the right sock addr to our connected list
|
||||
sendingPeer->activateMatchingOrNewSymmetricSocket(senderSockAddr);
|
||||
sendingPeer->activateMatchingOrNewSymmetricSocket(packet->getSenderSockAddr());
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
PacketType::Value requestType = packetTypeForPacket(receivedPacket);
|
||||
switch (requestType) {
|
||||
case PacketType::DomainConnectRequest:
|
||||
handleConnectRequest(receivedPacket, senderSockAddr);
|
||||
break;
|
||||
case PacketType::DomainListRequest: {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
||||
|
||||
if (!nodeUUID.isNull() && nodeList->nodeWithUUID(nodeUUID)) {
|
||||
NodeType_t throwawayNodeType;
|
||||
HifiSockAddr nodePublicAddress, nodeLocalAddress;
|
||||
|
||||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
|
||||
parseNodeDataFromByteArray(packetStream, throwawayNodeType, nodePublicAddress, nodeLocalAddress,
|
||||
senderSockAddr);
|
||||
|
||||
SharedNodePointer checkInNode = nodeList->nodeWithUUID(nodeUUID);
|
||||
checkInNode->setPublicSocket(nodePublicAddress);
|
||||
checkInNode->setLocalSocket(nodeLocalAddress);
|
||||
|
||||
// update last receive to now
|
||||
quint64 timeNow = usecTimestampNow();
|
||||
checkInNode->setLastHeardMicrostamp(timeNow);
|
||||
|
||||
QList<NodeType_t> nodeInterestList;
|
||||
packetStream >> nodeInterestList;
|
||||
|
||||
sendDomainListToNode(checkInNode, senderSockAddr, nodeInterestList.toSet());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketType::DomainServerPathQuery: {
|
||||
// have our private method attempt to respond to this path query
|
||||
respondToPathQuery(receivedPacket, senderSockAddr);
|
||||
break;
|
||||
}
|
||||
case PacketType::NodeJsonStats: {
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (matchingNode) {
|
||||
reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketType::StunResponse:
|
||||
nodeList->processSTUNResponse(receivedPacket);
|
||||
break;
|
||||
case PacketType::ICEPing: {
|
||||
auto pingReplyPacket = nodeList->constructPingReplyPacket(receivedPacket);
|
||||
nodeList->sendPacket(std::move(pingReplyPacket), senderSockAddr);
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketType::ICEPingReply: {
|
||||
processICEPingReply(receivedPacket, senderSockAddr);
|
||||
break;
|
||||
}
|
||||
case PacketType::ICEServerPeerInformation:
|
||||
processICEPeerInformation(receivedPacket);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
void DomainServer::processNodeJSONStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
auto nodeData = dynamic_cast<DomainServerNodeData*>(sendingNode->getLinkedData());
|
||||
if (nodeData) {
|
||||
nodeData->processJSONStatsPacket(*packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2229,19 +2175,17 @@ void DomainServer::addStaticAssignmentsToQueue() {
|
|||
}
|
||||
}
|
||||
|
||||
void DomainServer::respondToPathQuery(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
|
||||
void DomainServer::processPathQueryPacket(QSharedPointer<NLPacket> packet) {
|
||||
// this is a query for the viewpoint resulting from a path
|
||||
// first pull the query path from the packet
|
||||
|
||||
int numHeaderBytes = 0;
|
||||
const char* packetDataStart = receivedPacket.data() + numHeaderBytes;
|
||||
|
||||
// figure out how many bytes the sender said this path is
|
||||
quint16 numPathBytes = *packetDataStart;
|
||||
quint16 numPathBytes;
|
||||
packet->readPrimitive(&numPathBytes);
|
||||
|
||||
if (numPathBytes <= receivedPacket.size() - numHeaderBytes - sizeof(numPathBytes)) {
|
||||
if (numPathBytes <= packet->bytesAvailable()) {
|
||||
// the number of path bytes makes sense for the sent packet - pull out the path
|
||||
QString pathQuery = QString::fromUtf8(packetDataStart + sizeof(numPathBytes), numPathBytes);
|
||||
QString pathQuery = QString::fromUtf8(packet->getPayload() + packet->pos(), numPathBytes);
|
||||
|
||||
// our settings contain paths that start with a leading slash, so make sure this query has that
|
||||
if (!pathQuery.startsWith("/")) {
|
||||
|
@ -2289,7 +2233,7 @@ void DomainServer::respondToPathQuery(const QByteArray& receivedPacket, const Hi
|
|||
|
||||
// send off the packet - see if we can associate this outbound data to a particular node
|
||||
// TODO: does this senderSockAddr always work for a punched DS client?
|
||||
nodeList->sendPacket(std::move(pathResponsePacket), senderSockAddr);
|
||||
nodeList->sendPacket(std::move(pathResponsePacket), packet->getSenderSockAddr());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <Assignment.h>
|
||||
#include <HTTPSConnection.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <PacketListener.h>
|
||||
|
||||
#include "DomainServerSettingsManager.h"
|
||||
#include "DomainServerWebSessionData.h"
|
||||
|
@ -34,7 +35,7 @@
|
|||
typedef QSharedPointer<Assignment> SharedAssignmentPointer;
|
||||
typedef QMultiHash<QUuid, WalletTransaction*> TransactionHash;
|
||||
|
||||
class DomainServer : public QCoreApplication, public HTTPSRequestHandler {
|
||||
class DomainServer : public QCoreApplication, public HTTPSRequestHandler, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DomainServer(int argc, char* argv[]);
|
||||
|
@ -55,11 +56,19 @@ public slots:
|
|||
|
||||
void restart();
|
||||
|
||||
void processRequestAssignmentPacket(QSharedPointer<NLPacket> packet);
|
||||
void processConnectRequestPacket(QSharedPointer<NLPacket> packet);
|
||||
void processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processNodeJSONStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processPathQueryPacket(QSharedPointer<NLPacket> packet);
|
||||
void processICEPingPacket(QSharedPointer<NLPacket> packet);
|
||||
void processICEPingReplyPacket(QSharedPointer<NLPacket> packet);
|
||||
void processICEPeerInformationPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
private slots:
|
||||
void aboutToQuit();
|
||||
|
||||
void loginFailed();
|
||||
void readAvailableDatagrams();
|
||||
void setupPendingAssignmentCredits();
|
||||
void sendPendingTransactionsToServer();
|
||||
|
||||
|
@ -78,14 +87,9 @@ private:
|
|||
|
||||
void setupAutomaticNetworking();
|
||||
void sendHeartbeatToDataServer(const QString& networkAddress);
|
||||
void processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr);
|
||||
void processICEPeerInformation(const QByteArray& packet);
|
||||
|
||||
void pingPunchForConnectingPeer(const SharedNetworkPeer& peer);
|
||||
|
||||
void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
void handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr);
|
||||
unsigned int countConnectedUsers();
|
||||
bool verifyUsersKey (const QString& username, const QByteArray& usernameSignature, QString& reasonReturn);
|
||||
bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature,
|
||||
|
@ -94,11 +98,8 @@ private:
|
|||
void preloadAllowedUserPublicKeys();
|
||||
void requestUserPublicKey(const QString& username);
|
||||
|
||||
int parseNodeDataFromByteArray(QDataStream& packetStream,
|
||||
NodeType_t& nodeType,
|
||||
HifiSockAddr& publicSockAddr,
|
||||
HifiSockAddr& localSockAddr,
|
||||
const HifiSockAddr& senderSockAddr);
|
||||
int parseNodeData(QDataStream& packetStream, NodeType_t& nodeType,
|
||||
HifiSockAddr& publicSockAddr, HifiSockAddr& localSockAddr, const HifiSockAddr& senderSockAddr);
|
||||
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr,
|
||||
const NodeSet& nodeInterestSet);
|
||||
|
||||
|
@ -117,8 +118,6 @@ private:
|
|||
void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
|
||||
void addStaticAssignmentsToQueue();
|
||||
|
||||
void respondToPathQuery(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
QUrl oauthRedirectURL();
|
||||
QUrl oauthAuthorizationURL(const QUuid& stateUUID = QUuid::createUuid());
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ DomainServerNodeData::DomainServerNodeData() :
|
|||
_paymentIntervalTimer.start();
|
||||
}
|
||||
|
||||
void DomainServerNodeData::parseJSONStatsPacket(const QByteArray& statsPacket) {
|
||||
QVariantMap packetVariantMap = JSONBreakableMarshal::fromStringBuffer(statsPacket.mid(numBytesForPacketHeader(statsPacket)));
|
||||
void DomainServerNodeData::processJSONStatsPacket(NLPacket& statsPacket) {
|
||||
QVariantMap packetVariantMap = JSONBreakableMarshal::fromStringBuffer(statsPacket.readAll());
|
||||
_statsJSONObject = mergeJSONStatsFromNewObject(QJsonObject::fromVariantMap(packetVariantMap), _statsJSONObject);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,17 +17,17 @@
|
|||
#include <QtCore/QUuid>
|
||||
|
||||
#include <HifiSockAddr.h>
|
||||
#include <NLPacket.h>
|
||||
#include <NodeData.h>
|
||||
#include <NodeType.h>
|
||||
|
||||
class DomainServerNodeData : public NodeData {
|
||||
public:
|
||||
DomainServerNodeData();
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
const QJsonObject& getStatsJSONObject() const { return _statsJSONObject; }
|
||||
|
||||
void parseJSONStatsPacket(const QByteArray& statsPacket);
|
||||
void processJSONStatsPacket(NLPacket& packet);
|
||||
|
||||
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||
|
|
|
@ -308,7 +308,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
_window(new MainWindow(desktop())),
|
||||
_toolWindow(NULL),
|
||||
_friendsWindow(NULL),
|
||||
_datagramProcessor(),
|
||||
_undoStack(),
|
||||
_undoStackScriptingInterface(&_undoStack),
|
||||
_frameCount(0),
|
||||
|
@ -381,19 +380,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
|
||||
// start the nodeThread so its event loop is running
|
||||
QThread* nodeThread = new QThread(this);
|
||||
nodeThread->setObjectName("Datagram Processor Thread");
|
||||
nodeThread->setObjectName("NodeList Thread");
|
||||
nodeThread->start();
|
||||
|
||||
// make sure the node thread is given highest priority
|
||||
nodeThread->setPriority(QThread::TimeCriticalPriority);
|
||||
|
||||
_datagramProcessor = new DatagramProcessor(nodeList.data());
|
||||
|
||||
// have the NodeList use deleteLater from DM customDeleter
|
||||
nodeList->setCustomDeleter([](Dependency* dependency) {
|
||||
static_cast<NodeList*>(dependency)->deleteLater();
|
||||
});
|
||||
|
||||
// setup a timer for domain-server check ins
|
||||
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
|
||||
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
|
||||
|
@ -409,9 +401,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
ResourceCache* geometryCache = geometryCacheP.data();
|
||||
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
|
||||
|
||||
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
|
||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams);
|
||||
|
||||
// put the audio processing on a separate thread
|
||||
QThread* audioThread = new QThread();
|
||||
audioThread->setObjectName("Audio Thread");
|
||||
|
@ -422,14 +411,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
audioIO->setOrientationGetter(getOrientationForAudio);
|
||||
|
||||
audioIO->moveToThread(audioThread);
|
||||
|
||||
auto& audioScriptingInterface = AudioScriptingInterface::getInstance();
|
||||
|
||||
connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
|
||||
connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);
|
||||
connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
|
||||
connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled);
|
||||
connect(audioIO.data(), &AudioClient::receivedFirstPacket,
|
||||
&AudioScriptingInterface::getInstance(), &AudioScriptingInterface::receivedFirstPacket);
|
||||
connect(audioIO.data(), &AudioClient::disconnected,
|
||||
&AudioScriptingInterface::getInstance(), &AudioScriptingInterface::disconnected);
|
||||
connect(audioIO.data(), &AudioClient::mutedByMixer, &audioScriptingInterface, &AudioScriptingInterface::mutedByMixer);
|
||||
connect(audioIO.data(), &AudioClient::receivedFirstPacket, &audioScriptingInterface, &AudioScriptingInterface::receivedFirstPacket);
|
||||
connect(audioIO.data(), &AudioClient::disconnected, &audioScriptingInterface, &AudioScriptingInterface::disconnected);
|
||||
connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) {
|
||||
auto audioClient = DependencyManager::get<AudioClient>();
|
||||
float distance = glm::distance(DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(),
|
||||
position);
|
||||
bool shouldMute = !audioClient->isMuted() && (distance < radius);
|
||||
|
||||
if (shouldMute) {
|
||||
audioClient->toggleMute();
|
||||
AudioScriptingInterface::getInstance().environmentMuted();
|
||||
}
|
||||
});
|
||||
|
||||
audioThread->start();
|
||||
|
||||
|
@ -462,7 +464,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
connect(nodeList.data(), &NodeList::uuidChanged, _myAvatar, &MyAvatar::setSessionUUID);
|
||||
connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID);
|
||||
connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset);
|
||||
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch);
|
||||
connect(&nodeList->getPacketReceiver(), &PacketReceiver::packetVersionMismatch,
|
||||
this, &Application::notifyPacketVersionMismatch);
|
||||
|
||||
// connect to appropriate slots on AccountManager
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
|
@ -646,6 +649,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
auto applicationUpdater = DependencyManager::get<AutoUpdater>();
|
||||
connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog);
|
||||
applicationUpdater->checkForUpdate();
|
||||
|
||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket");
|
||||
}
|
||||
|
||||
void Application::aboutToQuit() {
|
||||
|
@ -658,8 +664,10 @@ void Application::aboutToQuit() {
|
|||
void Application::cleanupBeforeQuit() {
|
||||
|
||||
_entities.clear(); // this will allow entity scripts to properly shutdown
|
||||
|
||||
_datagramProcessor->shutdown(); // tell the datagram processor we're shutting down, so it can short circuit
|
||||
|
||||
// tell the packet receiver we're shutting down, so it can drop packets
|
||||
DependencyManager::get<NodeList>()->getPacketReceiver().setShouldDropPackets(true);
|
||||
|
||||
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
|
||||
|
||||
|
@ -734,6 +742,8 @@ Application::~Application() {
|
|||
DependencyManager::destroy<SoundCache>();
|
||||
|
||||
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
||||
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
|
||||
// ask the node thread to quit and wait until it is done
|
||||
|
@ -1787,7 +1797,6 @@ void Application::checkFPS() {
|
|||
|
||||
_fps = (float)_frameCount / diffTime;
|
||||
_frameCount = 0;
|
||||
_datagramProcessor->resetCounters();
|
||||
_timerStart.start();
|
||||
}
|
||||
|
||||
|
@ -3809,11 +3818,23 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
_domainConnectionRefusals.clear();
|
||||
}
|
||||
|
||||
void Application::domainConnectionDenied(const QString& reason) {
|
||||
void Application::handleDomainConnectionDeniedPacket(QSharedPointer<NLPacket> packet) {
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
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.";
|
||||
|
||||
if (!_domainConnectionRefusals.contains(reason)) {
|
||||
_domainConnectionRefusals.append(reason);
|
||||
emit domainConnectionRefused(reason);
|
||||
}
|
||||
|
||||
AccountManager::getInstance().checkAndSignalForAccessToken();
|
||||
}
|
||||
|
||||
void Application::connectedToDomain(const QString& hostname) {
|
||||
|
@ -3889,12 +3910,12 @@ void Application::nodeKilled(SharedNodePointer node) {
|
|||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket) {
|
||||
|
||||
void Application::trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket) {
|
||||
|
||||
// Attempt to identify the sender from its address.
|
||||
if (sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
const QUuid& nodeUUID = sendingNode->getUUID();
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
|
@ -3906,70 +3927,71 @@ void Application::trackIncomingOctreePacket(const QByteArray& packet, const Shar
|
|||
}
|
||||
}
|
||||
|
||||
int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingNode) {
|
||||
// But, also identify the sender, and keep track of the contained jurisdiction root for this server
|
||||
|
||||
// parse the incoming stats datas stick it in a temporary object for now, while we
|
||||
// determine which server it belongs to
|
||||
OctreeSceneStats temp;
|
||||
int statsMessageLength = temp.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
int statsMessageLength = 0;
|
||||
|
||||
// quick fix for crash... why would voxelServer be NULL?
|
||||
if (sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
const QUuid& nodeUUID = sendingNode->getUUID();
|
||||
OctreeSceneStats* octreeStats;
|
||||
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) {
|
||||
_octreeServerSceneStats[nodeUUID].unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()),
|
||||
packet.size());
|
||||
} else {
|
||||
_octreeServerSceneStats[nodeUUID] = temp;
|
||||
// now that we know the node ID, let's add these stats to the stats for that node...
|
||||
_octreeSceneStatsLock.lockForWrite();
|
||||
auto it = _octreeServerSceneStats.find(nodeUUID);
|
||||
if (it != _octreeServerSceneStats.end()) {
|
||||
octreeStats = &it->second;
|
||||
statsMessageLength = octreeStats->unpackFromPacket(packet);
|
||||
} else {
|
||||
OctreeSceneStats temp;
|
||||
statsMessageLength = temp.unpackFromPacket(packet);
|
||||
octreeStats = &temp;
|
||||
}
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(octreeStats->getJurisdictionRoot(), rootDetails);
|
||||
|
||||
// see if this is the first we've heard of this node...
|
||||
NodeToJurisdictionMap* jurisdiction = NULL;
|
||||
QString serverType;
|
||||
if (sendingNode->getType() == NodeType::EntityServer) {
|
||||
jurisdiction = &_entityServerJurisdictions;
|
||||
serverType = "Entity";
|
||||
}
|
||||
|
||||
jurisdiction->lockForRead();
|
||||
if (jurisdiction->find(nodeUUID) == jurisdiction->end()) {
|
||||
jurisdiction->unlock();
|
||||
|
||||
qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
|
||||
qPrintable(serverType),
|
||||
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
|
||||
|
||||
// Add the jurisditionDetails object to the list of "fade outs"
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
|
||||
OctreeFade fade(OctreeFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99f;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_octreeFadesLock.lockForWrite();
|
||||
_octreeFades.push_back(fade);
|
||||
_octreeFadesLock.unlock();
|
||||
}
|
||||
_octreeSceneStatsLock.unlock();
|
||||
|
||||
VoxelPositionSize rootDetails;
|
||||
voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails);
|
||||
|
||||
// see if this is the first we've heard of this node...
|
||||
NodeToJurisdictionMap* jurisdiction = NULL;
|
||||
QString serverType;
|
||||
if (sendingNode->getType() == NodeType::EntityServer) {
|
||||
jurisdiction = &_entityServerJurisdictions;
|
||||
serverType = "Entity";
|
||||
}
|
||||
|
||||
jurisdiction->lockForRead();
|
||||
if (jurisdiction->find(nodeUUID) == jurisdiction->end()) {
|
||||
jurisdiction->unlock();
|
||||
|
||||
qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]",
|
||||
qPrintable(serverType),
|
||||
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
|
||||
|
||||
// Add the jurisditionDetails object to the list of "fade outs"
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
|
||||
OctreeFade fade(OctreeFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99f;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_octreeFadesLock.lockForWrite();
|
||||
_octreeFades.push_back(fade);
|
||||
_octreeFadesLock.unlock();
|
||||
}
|
||||
} else {
|
||||
jurisdiction->unlock();
|
||||
}
|
||||
// store jurisdiction details for later use
|
||||
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
|
||||
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
|
||||
// details from the OctreeSceneStats to construct the JurisdictionMap
|
||||
JurisdictionMap jurisdictionMap;
|
||||
jurisdictionMap.copyContents(temp.getJurisdictionRoot(), temp.getJurisdictionEndNodes());
|
||||
jurisdiction->lockForWrite();
|
||||
(*jurisdiction)[nodeUUID] = jurisdictionMap;
|
||||
} else {
|
||||
jurisdiction->unlock();
|
||||
}
|
||||
// store jurisdiction details for later use
|
||||
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
|
||||
// but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the
|
||||
// details from the OctreeSceneStats to construct the JurisdictionMap
|
||||
JurisdictionMap jurisdictionMap;
|
||||
jurisdictionMap.copyContents(octreeStats->getJurisdictionRoot(), octreeStats->getJurisdictionEndNodes());
|
||||
jurisdiction->lockForWrite();
|
||||
(*jurisdiction)[nodeUUID] = jurisdictionMap;
|
||||
jurisdiction->unlock();
|
||||
|
||||
return statsMessageLength;
|
||||
}
|
||||
|
||||
|
@ -4809,6 +4831,7 @@ mat4 Application::getEyeProjection(int eye) const {
|
|||
if (isHMDMode()) {
|
||||
return OculusManager::getEyeProjection(eye);
|
||||
}
|
||||
|
||||
return _viewFrustum.getProjection();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <OctreeQuery.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <PacketListener.h>
|
||||
#include <PhysicalEntitySimulation.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
@ -43,7 +44,6 @@
|
|||
#include "AudioClient.h"
|
||||
#include "Bookmarks.h"
|
||||
#include "Camera.h"
|
||||
#include "DatagramProcessor.h"
|
||||
#include "Environment.h"
|
||||
#include "FileLogger.h"
|
||||
#include "GLCanvas.h"
|
||||
|
@ -135,7 +135,10 @@ class Application;
|
|||
|
||||
typedef bool (Application::* AcceptURLMethod)(const QString &);
|
||||
|
||||
class Application : public QApplication, public AbstractViewStateInterface, AbstractScriptingServicesInterface {
|
||||
class Application : public QApplication,
|
||||
public AbstractViewStateInterface,
|
||||
AbstractScriptingServicesInterface,
|
||||
public PacketListener {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OctreePacketProcessor;
|
||||
|
@ -214,6 +217,7 @@ public:
|
|||
OctreeQuery& getOctreeQuery() { return _octreeQuery; }
|
||||
EntityTree* getEntityClipboard() { return &_entityClipboard; }
|
||||
EntityTreeRenderer* getEntityClipboardRenderer() { return &_entityClipboardRenderer; }
|
||||
EntityEditPacketSender* getEntityEditPacketSender() { return &_entityEditSender; }
|
||||
|
||||
bool isMousePressed() const { return _mousePressed; }
|
||||
bool isMouseHidden() const { return !_cursorVisible; }
|
||||
|
@ -444,7 +448,7 @@ public slots:
|
|||
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
void domainConnectionDenied(const QString& reason);
|
||||
void handleDomainConnectionDeniedPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
void cameraMenuChanged();
|
||||
|
||||
|
@ -528,8 +532,6 @@ private:
|
|||
ToolWindow* _toolWindow;
|
||||
WebWindowClass* _friendsWindow;
|
||||
|
||||
DatagramProcessor* _datagramProcessor;
|
||||
|
||||
QUndoStack _undoStack;
|
||||
UndoStackScriptingInterface _undoStackScriptingInterface;
|
||||
|
||||
|
@ -615,8 +617,8 @@ private:
|
|||
StDev _idleLoopStdev;
|
||||
float _idleLoopMeasuredJitter;
|
||||
|
||||
int parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
void trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket);
|
||||
int processOctreeStats(NLPacket& packet, SharedNodePointer sendingNode);
|
||||
void trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket);
|
||||
|
||||
NodeToJurisdictionMap _entityServerJurisdictions;
|
||||
NodeToOctreeSceneStats _octreeServerSceneStats;
|
||||
|
|
|
@ -1,169 +0,0 @@
|
|||
//
|
||||
// DatagramProcessor.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/23/2014.
|
||||
// Copyright 2014 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 <QtCore/QWeakPointer>
|
||||
|
||||
#include <AccountManager.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "AudioClient.h"
|
||||
#include "Menu.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
#include "DatagramProcessor.h"
|
||||
|
||||
DatagramProcessor::DatagramProcessor(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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::Value incomingType = packetTypeForPacket(incomingPacket);
|
||||
// only process this packet if we have a match on the packet version
|
||||
switch (incomingType) {
|
||||
case PacketType::AudioEnvironment:
|
||||
case PacketType::AudioStreamStats:
|
||||
case PacketType::MixedAudio:
|
||||
case PacketType::SilentAudioFrame: {
|
||||
if (incomingType == PacketType::AudioStreamStats) {
|
||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "parseAudioStreamStatsPacket",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(QByteArray, incomingPacket));
|
||||
} else if (incomingType == PacketType::AudioEnvironment) {
|
||||
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 PacketType::EntityData:
|
||||
case PacketType::EntityErase:
|
||||
case PacketType::OctreeStats:
|
||||
case PacketType::EnvironmentData: {
|
||||
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 PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
case PacketType::AvatarIdentity:
|
||||
case PacketType::AvatarBillboard: {
|
||||
// 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 PacketType::DomainConnectionDenied: {
|
||||
int headerSize = 0;
|
||||
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 PacketType::NoisyMute:
|
||||
case PacketType::MuteEnvironment: {
|
||||
bool mute = !DependencyManager::get<AudioClient>()->isMuted();
|
||||
|
||||
if (incomingType == PacketType::MuteEnvironment) {
|
||||
glm::vec3 position;
|
||||
float radius;
|
||||
|
||||
int headerSize = 0;
|
||||
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 == PacketType::MuteEnvironment) {
|
||||
AudioScriptingInterface::getInstance().environmentMuted();
|
||||
} else {
|
||||
AudioScriptingInterface::getInstance().mutedByMixer();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType::EntityEditNack:
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) {
|
||||
application->_entityEditSender.processNackPacket(incomingPacket);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
nodeList->processNodeData(senderSockAddr, incomingPacket);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// DatagramProcessor.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/23/2014.
|
||||
// Copyright 2014 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_DatagramProcessor_h
|
||||
#define hifi_DatagramProcessor_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class DatagramProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DatagramProcessor(QObject* parent = 0);
|
||||
|
||||
int getInPacketCount() const { return _inPacketCount; }
|
||||
int getOutPacketCount() const { return _outPacketCount; }
|
||||
int getInByteCount() const { return _inByteCount; }
|
||||
int getOutByteCount() const { return _outByteCount; }
|
||||
|
||||
void resetCounters() { _inPacketCount = 0; _outPacketCount = 0; _inByteCount = 0; _outByteCount = 0; }
|
||||
|
||||
void shutdown() { _isShuttingDown = true; }
|
||||
public slots:
|
||||
void processDatagrams();
|
||||
|
||||
private:
|
||||
int _inPacketCount = 0;
|
||||
int _outPacketCount = 0;
|
||||
int _inByteCount = 0;
|
||||
int _outByteCount = 0;
|
||||
bool _isShuttingDown = false;
|
||||
};
|
||||
|
||||
#endif // hifi_DatagramProcessor_h
|
|
@ -500,7 +500,9 @@ Menu::Menu() {
|
|||
#endif
|
||||
|
||||
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
|
||||
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false,
|
||||
qApp->getEntityEditPacketSender(),
|
||||
SLOT(toggleNackPackets()));
|
||||
addCheckableActionToQMenuAndActionHash(networkMenu,
|
||||
MenuOption::DisableActivityLogger,
|
||||
0,
|
||||
|
|
|
@ -169,7 +169,7 @@ namespace MenuOption {
|
|||
const QString DeleteBookmark = "Delete Bookmark...";
|
||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||
const QString DisableLightEntities = "Disable Light Entities";
|
||||
const QString DisableNackPackets = "Disable NACK Packets";
|
||||
const QString DisableNackPackets = "Disable Entity NACK Packets";
|
||||
const QString DiskCacheEditor = "Disk Cache Editor";
|
||||
const QString DisplayHands = "Show Hand Info";
|
||||
const QString DisplayHandTargets = "Show Hand Targets";
|
||||
|
|
|
@ -1002,7 +1002,7 @@ void Avatar::setBillboard(const QByteArray& billboard) {
|
|||
_billboardTexture.reset();
|
||||
}
|
||||
|
||||
int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||
int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
if (!_initialized) {
|
||||
// now that we have data for this Avatar we are go for init
|
||||
init();
|
||||
|
@ -1011,7 +1011,7 @@ int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
// change in position implies movement
|
||||
glm::vec3 oldPosition = _position;
|
||||
|
||||
int bytesRead = AvatarData::parseDataAtOffset(packet, offset);
|
||||
int bytesRead = AvatarData::parseDataFromBuffer(buffer);
|
||||
|
||||
const float MOVE_DISTANCE_THRESHOLD = 0.001f;
|
||||
_moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD;
|
||||
|
@ -1137,7 +1137,7 @@ void Avatar::setShowDisplayName(bool showDisplayName) {
|
|||
}
|
||||
}
|
||||
|
||||
// virtual
|
||||
// virtual
|
||||
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
|
||||
shapeInfo.setCapsuleY(capsule.getRadius(), capsule.getHalfHeight());
|
||||
|
|
|
@ -85,10 +85,10 @@ public:
|
|||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition,
|
||||
bool postLighting = false);
|
||||
|
||||
bool addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
|
||||
bool addToScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
|
||||
void removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
|
||||
void removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
|
||||
//setters
|
||||
|
@ -146,7 +146,7 @@ public:
|
|||
|
||||
void setShowDisplayName(bool showDisplayName);
|
||||
|
||||
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer);
|
||||
|
||||
static void renderJointConnectingCone( gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2,
|
||||
float radius1, float radius2, const glm::vec4& color);
|
||||
|
@ -163,7 +163,7 @@ public:
|
|||
Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const;
|
||||
|
||||
Q_INVOKABLE void setJointModelPositionAndOrientation(int index, const glm::vec3 position, const glm::quat& rotation);
|
||||
Q_INVOKABLE void setJointModelPositionAndOrientation(const QString& name, const glm::vec3 position,
|
||||
Q_INVOKABLE void setJointModelPositionAndOrientation(const QString& name, const glm::vec3 position,
|
||||
const glm::quat& rotation);
|
||||
|
||||
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
||||
|
@ -179,8 +179,8 @@ public:
|
|||
|
||||
void slamPosition(const glm::vec3& position);
|
||||
|
||||
// Call this when updating Avatar position with a delta. This will allow us to
|
||||
// _accurately_ measure position changes and compute the resulting velocity
|
||||
// Call this when updating Avatar position with a delta. This will allow us to
|
||||
// _accurately_ measure position changes and compute the resulting velocity
|
||||
// (otherwise floating point error will cause problems at large positions).
|
||||
void applyPositionDelta(const glm::vec3& delta);
|
||||
|
||||
|
@ -203,9 +203,9 @@ protected:
|
|||
|
||||
// These position histories and derivatives are in the world-frame.
|
||||
// The derivatives are the MEASURED results of all external and internal forces
|
||||
// and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained
|
||||
// and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained
|
||||
// by setting these values.
|
||||
// Floating point error prevents us from accurately measuring velocity using a naive approach
|
||||
// Floating point error prevents us from accurately measuring velocity using a naive approach
|
||||
// (e.g. vel = (pos - lastPos)/dt) so instead we use _positionDeltaAccumulator.
|
||||
glm::vec3 _positionDeltaAccumulator;
|
||||
glm::vec3 _lastVelocity;
|
||||
|
|
|
@ -29,7 +29,6 @@ class AvatarManager : public AvatarHashMap {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
|
||||
/// Registers the script types associated with the avatar manager.
|
||||
static void registerMetaTypes(QScriptEngine* engine);
|
||||
|
||||
|
|
|
@ -870,12 +870,11 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
|
|||
return attachment;
|
||||
}
|
||||
|
||||
int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||
int MyAvatar::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"
|
||||
<< " packetLength = " << packet.size()
|
||||
<< " offset = " << offset;
|
||||
<< " packetLength = " << buffer.size();
|
||||
// this packet is just bad, so we pretend that we unpacked it ALL
|
||||
return packet.size() - offset;
|
||||
return buffer.size();
|
||||
}
|
||||
|
||||
void MyAvatar::sendKillAvatar() {
|
||||
|
|
|
@ -102,7 +102,7 @@ public:
|
|||
|
||||
eyeContactTarget getEyeContactTarget();
|
||||
|
||||
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer);
|
||||
|
||||
static void sendKillAvatar();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//Merge branch 'master' of ssh://github.com/highfidelity/hifi into isentropic/
|
||||
//
|
||||
// OctreePacketProcessor.cpp
|
||||
// interface/src/octree
|
||||
//
|
||||
|
@ -16,91 +16,104 @@
|
|||
#include "OctreePacketProcessor.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
|
||||
void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
OctreePacketProcessor::OctreePacketProcessor() {
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
|
||||
QSet<PacketType::Value> types {
|
||||
PacketType::OctreeStats, PacketType::EntityData,
|
||||
PacketType::EntityErase, PacketType::OctreeStats, PacketType::EnvironmentData
|
||||
};
|
||||
|
||||
packetReceiver.registerListenerForTypes(types, this, "handleOctreePacket");
|
||||
}
|
||||
|
||||
OctreePacketProcessor::~OctreePacketProcessor() {
|
||||
DependencyManager::get<NodeList>()->getPacketReceiver().unregisterListener(this);
|
||||
}
|
||||
|
||||
void OctreePacketProcessor::handleOctreePacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode) {
|
||||
queueReceivedPacket(packet, senderNode);
|
||||
}
|
||||
|
||||
void OctreePacketProcessor::processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"OctreePacketProcessor::processPacket()");
|
||||
|
||||
QByteArray mutablePacket = packet;
|
||||
|
||||
const int WAY_BEHIND = 300;
|
||||
|
||||
if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) {
|
||||
qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount());
|
||||
}
|
||||
int messageLength = mutablePacket.size();
|
||||
|
||||
|
||||
Application* app = Application::getInstance();
|
||||
bool wasStatsPacket = false;
|
||||
|
||||
|
||||
PacketType::Value voxelPacketType = packetTypeForPacket(mutablePacket);
|
||||
PacketType::Value octreePacketType = packet->getType();
|
||||
|
||||
// note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA
|
||||
// immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first
|
||||
// then process any remaining bytes as if it was another packet
|
||||
if (voxelPacketType == PacketType::OctreeStats) {
|
||||
int statsMessageLength = app->parseOctreeStats(mutablePacket, sendingNode);
|
||||
wasStatsPacket = true;
|
||||
if (messageLength > statsMessageLength) {
|
||||
mutablePacket = mutablePacket.mid(statsMessageLength);
|
||||
if (octreePacketType == PacketType::OctreeStats) {
|
||||
int statsMessageLength = app->processOctreeStats(*packet, sendingNode);
|
||||
|
||||
// TODO: this does not look correct, the goal is to test the packet version for the piggyback, but
|
||||
// this is testing the version and hash of the original packet
|
||||
if (!DependencyManager::get<NodeList>()->packetVersionAndHashMatch(packet)) {
|
||||
return; // bail since piggyback data doesn't match our versioning
|
||||
}
|
||||
wasStatsPacket = true;
|
||||
int piggybackBytes = packet->getSizeUsed() - statsMessageLength;
|
||||
|
||||
if (piggybackBytes) {
|
||||
// construct a new packet from the piggybacked one
|
||||
std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[piggybackBytes]);
|
||||
memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggybackBytes);
|
||||
|
||||
auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, packet->getSenderSockAddr());
|
||||
packet = QSharedPointer<NLPacket>(newPacket.release());
|
||||
} else {
|
||||
// Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket()
|
||||
return; // bail since no piggyback data
|
||||
}
|
||||
} // fall through to piggyback message
|
||||
|
||||
voxelPacketType = packetTypeForPacket(mutablePacket);
|
||||
PacketVersion packetVersion = mutablePacket[1];
|
||||
PacketVersion expectedVersion = versionForPacketType(voxelPacketType);
|
||||
PacketType::Value packetType = packet->getType();
|
||||
|
||||
// check version of piggyback packet against expected version
|
||||
if (packetVersion != expectedVersion) {
|
||||
if (packetType != versionForPacketType(packet->getType())) {
|
||||
static QMultiMap<QUuid, PacketType::Value> versionDebugSuppressMap;
|
||||
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
if (!versionDebugSuppressMap.contains(senderUUID, voxelPacketType)) {
|
||||
qDebug() << "Packet version mismatch on" << voxelPacketType << "- Sender"
|
||||
<< senderUUID << "sent" << (int)packetVersion << "but"
|
||||
<< (int)expectedVersion << "expected.";
|
||||
const QUuid& senderUUID = packet->getSourceID();
|
||||
if (!versionDebugSuppressMap.contains(senderUUID, packetType)) {
|
||||
|
||||
qDebug() << "Packet version mismatch on" << packetType << "- Sender"
|
||||
<< senderUUID << "sent" << (int) packetType << "but"
|
||||
<< (int) versionForPacketType(packetType) << "expected.";
|
||||
|
||||
emit packetVersionMismatch();
|
||||
|
||||
versionDebugSuppressMap.insert(senderUUID, voxelPacketType);
|
||||
versionDebugSuppressMap.insert(senderUUID, packetType);
|
||||
}
|
||||
return; // bail since piggyback version doesn't match
|
||||
}
|
||||
|
||||
app->trackIncomingOctreePacket(mutablePacket, sendingNode, wasStatsPacket);
|
||||
app->trackIncomingOctreePacket(*packet, sendingNode, wasStatsPacket);
|
||||
|
||||
if (sendingNode) {
|
||||
switch(packetType) {
|
||||
case PacketType::EntityErase: {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
app->_entities.processEraseMessage(*packet, sendingNode);
|
||||
}
|
||||
} break;
|
||||
|
||||
switch(voxelPacketType) {
|
||||
case PacketType::EntityErase: {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
app->_entities.processEraseMessage(mutablePacket, sendingNode);
|
||||
}
|
||||
} break;
|
||||
case PacketType::EntityData: {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
app->_entities.processDatagram(*packet, sendingNode);
|
||||
}
|
||||
} break;
|
||||
|
||||
case PacketType::EntityData: {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||
app->_entities.processDatagram(mutablePacket, sendingNode);
|
||||
}
|
||||
} break;
|
||||
case PacketType::EnvironmentData: {
|
||||
app->_environment.processPacket(*packet);
|
||||
} break;
|
||||
|
||||
case PacketType::EnvironmentData: {
|
||||
app->_environment.parseData(*sendingNode->getActiveSocket(), mutablePacket);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
// nothing to do
|
||||
} break;
|
||||
}
|
||||
default: {
|
||||
// nothing to do
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,16 +13,23 @@
|
|||
#define hifi_OctreePacketProcessor_h
|
||||
|
||||
#include <ReceivedPacketProcessor.h>
|
||||
#include <PacketListener.h>
|
||||
|
||||
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
||||
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
|
||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||
class OctreePacketProcessor : public ReceivedPacketProcessor {
|
||||
class OctreePacketProcessor : public ReceivedPacketProcessor, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
OctreePacketProcessor();
|
||||
~OctreePacketProcessor();
|
||||
|
||||
signals:
|
||||
void packetVersionMismatch();
|
||||
|
||||
protected:
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
virtual void processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private slots:
|
||||
void handleOctreePacket(QSharedPointer<NLPacket> packet, SharedNodePointer senderNode);
|
||||
};
|
||||
#endif // hifi_OctreePacketProcessor_h
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include <QtMultimedia/QAudioInput>
|
||||
#include <QtMultimedia/QAudioOutput>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
|
@ -43,7 +43,7 @@ extern "C" {
|
|||
#include <gverb/gverbdsp.h>
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
@ -140,6 +140,14 @@ AudioClient::AudioClient() :
|
|||
// create GVerb filter
|
||||
_gverb = createGverbFilter();
|
||||
configureGverbFilter(_gverb);
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "handleAudioStreamStatsPacket");
|
||||
packetReceiver.registerListener(PacketType::AudioEnvironment, this, "handleAudioEnvironmentDataPacket");
|
||||
packetReceiver.registerListener(PacketType::SilentAudioFrame, this, "handleAudioDataPacket");
|
||||
packetReceiver.registerListener(PacketType::MixedAudio, this, "handleAudioDataPacket");
|
||||
packetReceiver.registerListener(PacketType::NoisyMute, this, "handleNoisyMutePacket");
|
||||
packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket");
|
||||
}
|
||||
|
||||
AudioClient::~AudioClient() {
|
||||
|
@ -527,6 +535,60 @@ void AudioClient::stop() {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<NLPacket> packet) {
|
||||
|
||||
char bitset;
|
||||
packet->readPrimitive(&bitset);
|
||||
|
||||
bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT);
|
||||
|
||||
if (hasReverb) {
|
||||
float reverbTime, wetLevel;
|
||||
packet->readPrimitive(&reverbTime);
|
||||
packet->readPrimitive(&wetLevel);
|
||||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
_receivedAudioStream.clearReverb();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleAudioDataPacket(QSharedPointer<NLPacket> packet) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||
|
||||
if (_audioOutput) {
|
||||
|
||||
if (!_hasReceivedFirstPacket) {
|
||||
_hasReceivedFirstPacket = true;
|
||||
|
||||
// have the audio scripting interface emit a signal to say we just connected to mixer
|
||||
emit receivedFirstPacket();
|
||||
}
|
||||
|
||||
// Audio output must exist and be correctly set up if we're going to process received audio
|
||||
_receivedAudioStream.parseData(*packet);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleNoisyMutePacket(QSharedPointer<NLPacket> packet) {
|
||||
if (!_muted) {
|
||||
toggleMute();
|
||||
|
||||
// have the audio scripting interface emit a signal to say we were muted by the mixer
|
||||
emit mutedByMixer();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::handleMuteEnvironmentPacket(QSharedPointer<NLPacket> packet) {
|
||||
glm::vec3 position;
|
||||
float radius;
|
||||
|
||||
packet->readPrimitive(&position);
|
||||
packet->readPrimitive(&radius);
|
||||
|
||||
emit muteEnvironmentRequested(position, radius);
|
||||
}
|
||||
|
||||
QString AudioClient::getDefaultDeviceName(QAudio::Mode mode) {
|
||||
QAudioDeviceInfo deviceInfo = defaultAudioDeviceForMode(mode);
|
||||
return deviceInfo.deviceName();
|
||||
|
@ -928,44 +990,6 @@ void AudioClient::sendMuteEnvironmentPacket() {
|
|||
}
|
||||
}
|
||||
|
||||
void AudioClient::addReceivedAudioToStream(const QByteArray& audioByteArray) {
|
||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||
|
||||
if (_audioOutput) {
|
||||
|
||||
if (!_hasReceivedFirstPacket) {
|
||||
_hasReceivedFirstPacket = true;
|
||||
|
||||
// have the audio scripting interface emit a signal to say we just connected to mixer
|
||||
emit receivedFirstPacket();
|
||||
}
|
||||
|
||||
// Audio output must exist and be correctly set up if we're going to process received audio
|
||||
_receivedAudioStream.parseData(audioByteArray);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::parseAudioEnvironmentData(const QByteArray &packet) {
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
const char* dataAt = packet.constData() + numBytesPacketHeader;
|
||||
|
||||
char bitset;
|
||||
memcpy(&bitset, dataAt, sizeof(char));
|
||||
dataAt += sizeof(char);
|
||||
|
||||
bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT);;
|
||||
if (hasReverb) {
|
||||
float reverbTime, wetLevel;
|
||||
memcpy(&reverbTime, dataAt, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
memcpy(&wetLevel, dataAt, sizeof(float));
|
||||
dataAt += sizeof(float);
|
||||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||
} else {
|
||||
_receivedAudioStream.clearReverb();
|
||||
}
|
||||
}
|
||||
|
||||
void AudioClient::toggleMute() {
|
||||
_muted = !_muted;
|
||||
emit muteToggled();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AudioClient_h
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
@ -32,10 +33,13 @@
|
|||
#include <AudioSourceTone.h>
|
||||
#include <AudioSourceNoise.h>
|
||||
#include <AudioStreamStats.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <HifiSockAddr.h>
|
||||
#include <NLPacket.h>
|
||||
#include <MixedProcessedAudioStream.h>
|
||||
#include <RingBufferHistory.h>
|
||||
#include <PacketListener.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <Sound.h>
|
||||
#include <StDev.h>
|
||||
|
@ -77,7 +81,7 @@ typedef glm::quat (*AudioOrientationGetter)();
|
|||
|
||||
class NLPacket;
|
||||
|
||||
class AudioClient : public AbstractAudioInterface, public Dependency {
|
||||
class AudioClient : public AbstractAudioInterface, public Dependency, public PacketListener {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
public:
|
||||
|
@ -135,10 +139,13 @@ public:
|
|||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
void addReceivedAudioToStream(const QByteArray& audioByteArray);
|
||||
void parseAudioEnvironmentData(const QByteArray& packet);
|
||||
|
||||
void handleAudioEnvironmentDataPacket(QSharedPointer<NLPacket> packet);
|
||||
void handleAudioDataPacket(QSharedPointer<NLPacket> packet);
|
||||
void handleNoisyMutePacket(QSharedPointer<NLPacket> packet);
|
||||
void handleMuteEnvironmentPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
void sendDownstreamAudioStatsPacket() { _stats.sendDownstreamAudioStatsPacket(); }
|
||||
void parseAudioStreamStatsPacket(const QByteArray& packet) { _stats.parseAudioStreamStatsPacket(packet); }
|
||||
void handleAudioInput();
|
||||
void reset();
|
||||
void audioMixerKilled();
|
||||
|
@ -181,6 +188,7 @@ public slots:
|
|||
|
||||
signals:
|
||||
bool muteToggled();
|
||||
void mutedByMixer();
|
||||
void inputReceived(const QByteArray& inputSamples);
|
||||
void outputBytesToNetwork(int numBytes);
|
||||
void inputBytesFromNetwork(int numBytes);
|
||||
|
@ -192,6 +200,8 @@ signals:
|
|||
|
||||
void audioFinished();
|
||||
|
||||
void muteEnvironmentRequested(glm::vec3 position, float radius);
|
||||
|
||||
protected:
|
||||
AudioClient();
|
||||
~AudioClient();
|
||||
|
|
|
@ -63,27 +63,24 @@ void AudioIOStats::sentPacket() {
|
|||
_lastSentAudioPacket = now;
|
||||
}
|
||||
}
|
||||
void AudioIOStats::parseAudioStreamStatsPacket(const QByteArray& packet) {
|
||||
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
const char* dataAt = packet.constData() + numBytesPacketHeader;
|
||||
void AudioIOStats::processStreamStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
|
||||
// parse the appendFlag, clear injected audio stream stats if 0
|
||||
quint8 appendFlag = *(reinterpret_cast<const quint16*>(dataAt));
|
||||
dataAt += sizeof(quint8);
|
||||
quint8 appendFlag;
|
||||
packet->readPrimitive(&appendFlag);
|
||||
|
||||
if (!appendFlag) {
|
||||
_mixerInjectedStreamStatsMap.clear();
|
||||
}
|
||||
|
||||
// parse the number of stream stats structs to follow
|
||||
quint16 numStreamStats = *(reinterpret_cast<const quint16*>(dataAt));
|
||||
dataAt += sizeof(quint16);
|
||||
quint16 numStreamStats;
|
||||
packet->readPrimitive(&numStreamStats);
|
||||
|
||||
// parse the stream stats
|
||||
AudioStreamStats streamStats;
|
||||
for (quint16 i = 0; i < numStreamStats; i++) {
|
||||
memcpy(&streamStats, dataAt, sizeof(AudioStreamStats));
|
||||
dataAt += sizeof(AudioStreamStats);
|
||||
packet->readPrimitive(&streamStats);
|
||||
|
||||
if (streamStats._streamType == PositionalAudioStream::Microphone) {
|
||||
_mixerAvatarStreamStats = streamStats;
|
||||
|
|
|
@ -17,10 +17,13 @@
|
|||
#include <QObject>
|
||||
|
||||
#include <AudioStreamStats.h>
|
||||
#include <Node.h>
|
||||
#include <NLPacket.h>
|
||||
#include <PacketListener.h>
|
||||
|
||||
class MixedProcessedAudioStream;
|
||||
|
||||
class AudioIOStats : public QObject {
|
||||
class AudioIOStats : public QObject, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioIOStats(MixedProcessedAudioStream* receivedAudioStream);
|
||||
|
@ -41,7 +44,7 @@ public:
|
|||
const MovingMinMaxAvg<quint64>& getPacketSentTimeGaps() const { return _packetSentTimeGaps; }
|
||||
|
||||
void sendDownstreamAudioStatsPacket();
|
||||
void parseAudioStreamStatsPacket(const QByteArray& packet);
|
||||
void processStreamStatsPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
private:
|
||||
MixedProcessedAudioStream* _receivedAudioStream;
|
||||
|
||||
|
@ -57,4 +60,4 @@ private:
|
|||
MovingMinMaxAvg<quint64> _packetSentTimeGaps;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioIOStats_h
|
||||
#endif // hifi_AudioIOStats_h
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <NLPacket.h>
|
||||
#include <Node.h>
|
||||
|
||||
#include "InboundAudioStream.h"
|
||||
#include "udt/PacketHeaders.h"
|
||||
|
||||
|
@ -96,28 +99,23 @@ void InboundAudioStream::perSecondCallbackForUpdatingStats() {
|
|||
_timeGapStatsForStatsPacket.currentIntervalComplete();
|
||||
}
|
||||
|
||||
int InboundAudioStream::parseData(const QByteArray& packet) {
|
||||
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
|
||||
// parse header
|
||||
int numBytesHeader = numBytesForPacketHeader(packet);
|
||||
const char* dataAt = packet.constData() + numBytesHeader;
|
||||
int readBytes = numBytesHeader;
|
||||
int InboundAudioStream::parseData(NLPacket& packet) {
|
||||
|
||||
// parse sequence number and track it
|
||||
quint16 sequence = *(reinterpret_cast<const quint16*>(dataAt));
|
||||
dataAt += sizeof(quint16);
|
||||
readBytes += sizeof(quint16);
|
||||
SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, senderUUID);
|
||||
quint16 sequence;
|
||||
packet.readPrimitive(&sequence);
|
||||
SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence,
|
||||
packet.getSourceID());
|
||||
|
||||
packetReceivedUpdateTimingStats();
|
||||
|
||||
int networkSamples;
|
||||
|
||||
// parse the info after the seq number and before the audio data (the stream properties)
|
||||
readBytes += parseStreamProperties(packetType, packet.mid(readBytes), networkSamples);
|
||||
int propertyBytes = parseStreamProperties(packet.getType(),
|
||||
QByteArray::fromRawData(packet.getPayload(), packet.pos()),
|
||||
networkSamples);
|
||||
packet.seek(packet.pos() + propertyBytes);
|
||||
|
||||
// handle this packet based on its arrival status.
|
||||
switch (arrivalInfo._status) {
|
||||
|
@ -132,10 +130,12 @@ int InboundAudioStream::parseData(const QByteArray& packet) {
|
|||
}
|
||||
case SequenceNumberStats::OnTime: {
|
||||
// Packet is on time; parse its data to the ringbuffer
|
||||
if (packetType == PacketType::SilentAudioFrame) {
|
||||
if (packet.getType() == PacketType::SilentAudioFrame) {
|
||||
writeDroppableSilentSamples(networkSamples);
|
||||
} else {
|
||||
readBytes += parseAudioData(packetType, packet.mid(readBytes), networkSamples);
|
||||
int audioBytes = parseAudioData(packet.getType(), QByteArray::fromRawData(packet.getPayload(), packet.pos()),
|
||||
networkSamples);
|
||||
packet.seek(packet.pos() + audioBytes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ int InboundAudioStream::parseData(const QByteArray& packet) {
|
|||
|
||||
framesAvailableChanged();
|
||||
|
||||
return readBytes;
|
||||
return packet.pos();
|
||||
}
|
||||
|
||||
int InboundAudioStream::parseStreamProperties(PacketType::Value type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) {
|
||||
|
@ -314,7 +314,7 @@ void InboundAudioStream::setToStarved() {
|
|||
starvesInWindow++;
|
||||
} while (starvesIterator != end);
|
||||
|
||||
// this starve put us over the starve threshold. update _desiredJitterBufferFrames to
|
||||
// this starve put us over the starve threshold. update _desiredJitterBufferFrames to
|
||||
// value determined by window A.
|
||||
if (starvesInWindow >= _starveThreshold) {
|
||||
int calculatedJitterBufferFrames;
|
||||
|
@ -398,7 +398,7 @@ void InboundAudioStream::packetReceivedUpdateTimingStats() {
|
|||
_timeGapStatsForDesiredReduction.update(gap);
|
||||
|
||||
if (_timeGapStatsForDesiredCalcOnTooManyStarves.getNewStatsAvailableFlag()) {
|
||||
_calculatedJitterBufferFramesUsingMaxGap = ceilf((float)_timeGapStatsForDesiredCalcOnTooManyStarves.getWindowMax()
|
||||
_calculatedJitterBufferFramesUsingMaxGap = ceilf((float)_timeGapStatsForDesiredCalcOnTooManyStarves.getWindowMax()
|
||||
/ (float) AudioConstants::NETWORK_FRAME_USECS);
|
||||
_timeGapStatsForDesiredCalcOnTooManyStarves.clearNewStatsAvailableFlag();
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
{}
|
||||
|
||||
// max number of frames over desired in the ringbuffer.
|
||||
int _maxFramesOverDesired;
|
||||
int _maxFramesOverDesired;
|
||||
|
||||
// if false, _desiredJitterBufferFrames will always be _staticDesiredJitterBufferFrames. Otherwise,
|
||||
// either fred or philip's method will be used to calculate _desiredJitterBufferFrames based on packet timegaps.
|
||||
|
@ -107,7 +107,7 @@ public:
|
|||
virtual void resetStats();
|
||||
void clearBuffer();
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
virtual int parseData(NLPacket& packet);
|
||||
|
||||
int popFrames(int maxFrames, bool allOrNothing, bool starveIfNoFramesPopped = true);
|
||||
int popSamples(int maxSamples, bool allOrNothing, bool starveIfNoSamplesPopped = true);
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
virtual AudioStreamStats getAudioStreamStats() const;
|
||||
|
||||
/// returns the desired number of jitter buffer frames under the dyanmic jitter buffers scheme
|
||||
int getCalculatedJitterBufferFrames() const { return _useStDevForJitterCalc ?
|
||||
int getCalculatedJitterBufferFrames() const { return _useStDevForJitterCalc ?
|
||||
_calculatedJitterBufferFramesUsingStDev : _calculatedJitterBufferFramesUsingMaxGap; };
|
||||
|
||||
/// returns the desired number of jitter buffer frames using Philip's method
|
||||
|
@ -217,7 +217,7 @@ protected:
|
|||
bool _dynamicJitterBuffers; // if false, _desiredJitterBufferFrames is locked at 1 (old behavior)
|
||||
int _staticDesiredJitterBufferFrames;
|
||||
|
||||
// if jitter buffer is dynamic, this determines what method of calculating _desiredJitterBufferFrames
|
||||
// if jitter buffer is dynamic, this determines what method of calculating _desiredJitterBufferFrames
|
||||
// if true, Philip's timegap std dev calculation is used. Otherwise, Freddy's max timegap calculation is used
|
||||
bool _useStDevForJitterCalc;
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ bool AvatarData::shouldLogError(const quint64& now) {
|
|||
}
|
||||
|
||||
// read data in packet starting at byte offset and return number of bytes parsed
|
||||
int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
|
||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||
if (!_headData) {
|
||||
|
@ -277,7 +277,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
_handData = new HandData(this);
|
||||
}
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data()) + offset;
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(buffer.data());
|
||||
const unsigned char* sourceBuffer = startPosition;
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
|
@ -299,7 +299,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
|
|||
// = 45 bytes
|
||||
int minPossibleSize = 45;
|
||||
|
||||
int maxAvailableSize = packet.size() - offset;
|
||||
int maxAvailableSize = buffer.size();
|
||||
if (minPossibleSize > maxAvailableSize) {
|
||||
if (shouldLogError(now)) {
|
||||
qCDebug(avatars) << "Malformed AvatarData packet at the start; "
|
||||
|
@ -867,9 +867,8 @@ void AvatarData::clearJointsData() {
|
|||
}
|
||||
}
|
||||
|
||||
bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
bool AvatarData::hasIdentityChangedAfterParsing(NLPacket& packet) {
|
||||
QDataStream packetStream(&packet);
|
||||
|
||||
QUuid avatarUUID;
|
||||
QUrl faceModelURL, skeletonModelURL;
|
||||
|
@ -911,8 +910,8 @@ QByteArray AvatarData::identityByteArray() {
|
|||
return identityData;
|
||||
}
|
||||
|
||||
bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& packet) {
|
||||
QByteArray newBillboard = packet.mid(numBytesForPacketHeader(packet));
|
||||
bool AvatarData::hasBillboardChangedAfterParsing(NLPacket& packet) {
|
||||
QByteArray newBillboard = packet.readAll();
|
||||
if (newBillboard == _billboard) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef unsigned long long quint64;
|
|||
#include <QReadWriteLock>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <NLPacket.h>
|
||||
#include <Node.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
|
@ -66,12 +67,12 @@ typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
|||
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
|
||||
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
|
||||
|
||||
const quint32 AVATAR_MOTION_DEFAULTS =
|
||||
const quint32 AVATAR_MOTION_DEFAULTS =
|
||||
AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED |
|
||||
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
||||
|
||||
// these bits will be expanded as features are exposed
|
||||
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
||||
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
||||
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
|
||||
|
||||
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
|
||||
|
@ -181,7 +182,7 @@ public:
|
|||
/// \param packet byte array of data
|
||||
/// \param offset number of bytes into packet where data starts
|
||||
/// \return number of bytes parsed
|
||||
virtual int parseDataAtOffset(const QByteArray& packet, int offset);
|
||||
virtual int parseDataFromBuffer(const QByteArray& buffer);
|
||||
|
||||
// Body Rotation (degrees)
|
||||
float getBodyYaw() const { return _bodyYaw; }
|
||||
|
@ -241,7 +242,7 @@ public:
|
|||
Q_INVOKABLE virtual void clearJointsData();
|
||||
|
||||
/// Returns the index of the joint with the specified name, or -1 if not found/unknown.
|
||||
Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; }
|
||||
Q_INVOKABLE virtual int getJointIndex(const QString& name) const { return _jointIndices.value(name) - 1; }
|
||||
|
||||
Q_INVOKABLE virtual QStringList getJointNames() const { return _jointNames; }
|
||||
|
||||
|
@ -260,10 +261,10 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool hasIdentityChangedAfterParsing(const QByteArray& packet);
|
||||
bool hasIdentityChangedAfterParsing(NLPacket& packet);
|
||||
QByteArray identityByteArray();
|
||||
|
||||
bool hasBillboardChangedAfterParsing(const QByteArray& packet);
|
||||
bool hasBillboardChangedAfterParsing(NLPacket& packet);
|
||||
|
||||
const QUrl& getFaceModelURL() const { return _faceModelURL; }
|
||||
QString getFaceModelURLString() const { return _faceModelURL.toString(); }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// AvatarHashMap.cpp
|
||||
// libraries/avatars/src
|
||||
//
|
||||
// Created by AndrewMeadows on 1/28/2014.
|
||||
// Created by Andrew Meadows on 1/28/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -18,25 +18,12 @@
|
|||
|
||||
AvatarHashMap::AvatarHashMap() {
|
||||
connect(DependencyManager::get<NodeList>().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
|
||||
}
|
||||
|
||||
void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
switch (packetTypeForPacket(datagram)) {
|
||||
case PacketType::BulkAvatarData:
|
||||
processAvatarDataPacket(datagram, mixerWeakPointer);
|
||||
break;
|
||||
case PacketType::AvatarIdentity:
|
||||
processAvatarIdentityPacket(datagram, mixerWeakPointer);
|
||||
break;
|
||||
case PacketType::AvatarBillboard:
|
||||
processAvatarBillboardPacket(datagram, mixerWeakPointer);
|
||||
break;
|
||||
case PacketType::KillAvatar:
|
||||
processKillAvatar(datagram);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::BulkAvatarData, this, "processAvatarDataPacket");
|
||||
packetReceiver.registerListener(PacketType::KillAvatar, this, "processKillAvatar");
|
||||
packetReceiver.registerListener(PacketType::AvatarIdentity, this, "processAvatarIdentityPacket");
|
||||
packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket");
|
||||
}
|
||||
|
||||
bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) {
|
||||
|
@ -65,86 +52,84 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
|
|||
return avatar;
|
||||
}
|
||||
|
||||
void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) {
|
||||
int bytesRead = numBytesForPacketHeader(datagram);
|
||||
|
||||
void AvatarHashMap::processAvatarDataPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
|
||||
// enumerate over all of the avatars in this packet
|
||||
// only add them if mixerWeakPointer points to something (meaning that mixer is still around)
|
||||
while (bytesRead < datagram.size() && mixerWeakPointer.data()) {
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
|
||||
bytesRead += NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
while (packet->bytesAvailable()) {
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
if (sessionUUID != _lastOwnerSessionUUID) {
|
||||
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
|
||||
if (!avatar) {
|
||||
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
||||
avatar = addAvatar(sessionUUID, sendingNode);
|
||||
}
|
||||
|
||||
|
||||
// have the matching (or new) avatar parse the data from the packet
|
||||
bytesRead += avatar->parseDataAtOffset(datagram, bytesRead);
|
||||
int bytesRead = avatar->parseDataFromBuffer(QByteArray::fromRawData(packet->getPayload(), packet->pos()));
|
||||
packet->seek(packet->pos() + bytesRead);
|
||||
} else {
|
||||
// create a dummy AvatarData class to throw this data on the ground
|
||||
AvatarData dummyData;
|
||||
bytesRead += dummyData.parseDataAtOffset(datagram, bytesRead);
|
||||
int bytesRead = dummyData.parseDataFromBuffer(QByteArray::fromRawData(packet->getPayload(), packet->pos()));
|
||||
packet->seek(packet->pos() + bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarHashMap::processAvatarIdentityPacket(const QByteArray &packet, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
// setup a data stream to parse the packet
|
||||
QDataStream identityStream(packet);
|
||||
identityStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
QDataStream identityStream(packet.data());
|
||||
|
||||
QUuid sessionUUID;
|
||||
|
||||
while (!identityStream.atEnd()) {
|
||||
|
||||
|
||||
QUrl faceMeshURL, skeletonURL;
|
||||
QVector<AttachmentData> attachmentData;
|
||||
QString displayName;
|
||||
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName;
|
||||
|
||||
|
||||
// mesh URL for a UUID, find avatar in our list
|
||||
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
|
||||
if (!avatar) {
|
||||
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
||||
avatar = addAvatar(sessionUUID, sendingNode);
|
||||
}
|
||||
if (avatar->getFaceModelURL() != faceMeshURL) {
|
||||
avatar->setFaceModelURL(faceMeshURL);
|
||||
}
|
||||
|
||||
|
||||
if (avatar->getSkeletonModelURL() != skeletonURL) {
|
||||
avatar->setSkeletonModelURL(skeletonURL);
|
||||
}
|
||||
|
||||
|
||||
if (avatar->getAttachmentData() != attachmentData) {
|
||||
avatar->setAttachmentData(attachmentData);
|
||||
}
|
||||
|
||||
|
||||
if (avatar->getDisplayName() != displayName) {
|
||||
avatar->setDisplayName(displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarHashMap::processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
int headerSize = numBytesForPacketHeader(packet);
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
|
||||
if (!avatar) {
|
||||
avatar = addAvatar(sessionUUID, mixerWeakPointer);
|
||||
avatar = addAvatar(sessionUUID, sendingNode);
|
||||
}
|
||||
|
||||
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
|
||||
QByteArray billboard = packet->read(packet->bytesAvailable());
|
||||
if (avatar->getBillboard() != billboard) {
|
||||
avatar->setBillboard(billboard);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarHashMap::processKillAvatar(const QByteArray& datagram) {
|
||||
void AvatarHashMap::processKillAvatar(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
// read the node id
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(numBytesForPacketHeader(datagram), NUM_BYTES_RFC4122_UUID));
|
||||
QUuid sessionUUID = QUuid::fromRfc4122(packet->read(NUM_BYTES_RFC4122_UUID));
|
||||
removeAvatar(sessionUUID);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// AvatarHashMap.h
|
||||
// libraries/avatars/src
|
||||
//
|
||||
// Created by Stephen AndrewMeadows on 1/28/2014.
|
||||
// Created by Andrew Meadows on 1/28/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
@ -19,41 +19,41 @@
|
|||
#include <memory>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <NLPacket.h>
|
||||
#include <Node.h>
|
||||
#include <PacketListener.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class AvatarHashMap : public QObject, public Dependency {
|
||||
class AvatarHashMap : public QObject, public Dependency, public PacketListener {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
|
||||
public:
|
||||
const AvatarHash& getAvatarHash() { return _avatarHash; }
|
||||
int size() { return _avatarHash.size(); }
|
||||
|
||||
|
||||
public slots:
|
||||
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
bool isAvatarInRange(const glm::vec3 & position, const float range);
|
||||
|
||||
|
||||
private slots:
|
||||
void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID);
|
||||
|
||||
void processAvatarDataPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processAvatarIdentityPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processAvatarBillboardPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processKillAvatar(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
protected:
|
||||
AvatarHashMap();
|
||||
|
||||
|
||||
virtual AvatarSharedPointer newSharedAvatar();
|
||||
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
virtual void removeAvatar(const QUuid& sessionUUID);
|
||||
|
||||
|
||||
AvatarHash _avatarHash;
|
||||
|
||||
private:
|
||||
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processAvatarIdentityPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
|
||||
void processKillAvatar(const QByteArray& datagram);
|
||||
|
||||
QUuid _lastOwnerSessionUUID;
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
#include "EntitiesRendererLogging.h"
|
||||
#include "AddressManager.h"
|
||||
|
||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
AbstractScriptingServicesInterface* scriptingServices) :
|
||||
OctreeRenderer(),
|
||||
_wantScripts(wantScripts),
|
||||
|
@ -75,13 +75,13 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
}
|
||||
|
||||
EntityTreeRenderer::~EntityTreeRenderer() {
|
||||
// NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a
|
||||
// NOTE: we don't need to delete _entitiesScriptEngine because it is registered with the application and has a
|
||||
// signal tied to call it's deleteLater on doneRunning
|
||||
if (_sandboxScriptEngine) {
|
||||
// TODO: consider reworking how _sandboxScriptEngine is managed. It's treated differently than _entitiesScriptEngine
|
||||
// because we don't call registerScriptEngineWithApplicationServices() for it. This implementation is confusing and
|
||||
// potentially error prone because it's not a full fledged ScriptEngine that has been fully connected to the
|
||||
// application. We did this so that scripts that were ill-formed could be evaluated but not execute against the
|
||||
// because we don't call registerScriptEngineWithApplicationServices() for it. This implementation is confusing and
|
||||
// potentially error prone because it's not a full fledged ScriptEngine that has been fully connected to the
|
||||
// application. We did this so that scripts that were ill-formed could be evaluated but not execute against the
|
||||
// application services. But this means it's shutdown behavior is different from other ScriptEngines
|
||||
delete _sandboxScriptEngine;
|
||||
_sandboxScriptEngine = NULL;
|
||||
|
@ -121,7 +121,7 @@ void EntityTreeRenderer::init() {
|
|||
}
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
|
||||
connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity, Qt::QueuedConnection);
|
||||
|
@ -140,7 +140,7 @@ void EntityTreeRenderer::scriptContentsAvailable(const QUrl& url, const QString&
|
|||
_waitingOnPreload.remove(url);
|
||||
foreach(EntityItemID entityID, entityIDs) {
|
||||
checkAndCallPreload(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItem
|
|||
}
|
||||
|
||||
|
||||
QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& urlOut,
|
||||
QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& urlOut,
|
||||
bool& reload) {
|
||||
isPending = false;
|
||||
QUrl url(scriptMaybeURLorText);
|
||||
|
@ -355,7 +355,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
|
|||
|
||||
// Note: at this point we don't need to worry about the tree being locked, because we only deal with
|
||||
// EntityItemIDs from here. The loadEntityScript() method is robust against attempting to load scripts
|
||||
// for entity IDs that no longer exist.
|
||||
// for entity IDs that no longer exist.
|
||||
|
||||
// for all of our previous containing entities, if they are no longer containing then send them a leave event
|
||||
foreach(const EntityItemID& entityID, _currentEntitiesInside) {
|
||||
|
@ -402,7 +402,7 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
_currentEntitiesInside.clear();
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
}
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en
|
|||
const FBXGeometry* result = NULL;
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||
assert(modelEntityItem); // we need this!!!
|
||||
Model* model = modelEntityItem->getModel(this);
|
||||
|
@ -529,7 +529,7 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer en
|
|||
const Model* EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityItem) {
|
||||
const Model* result = NULL;
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||
result = modelEntityItem->getModel(this);
|
||||
}
|
||||
|
@ -540,7 +540,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
|
|||
const FBXGeometry* result = NULL;
|
||||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
|
||||
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
|
||||
if (modelEntityItem->hasCompoundShapeURL()) {
|
||||
Model* model = modelEntityItem->getModel(this);
|
||||
|
@ -680,20 +680,20 @@ float EntityTreeRenderer::getSizeScale() const {
|
|||
return _viewState->getSizeScale();
|
||||
}
|
||||
|
||||
int EntityTreeRenderer::getBoundaryLevelAdjust() const {
|
||||
int EntityTreeRenderer::getBoundaryLevelAdjust() const {
|
||||
return _viewState->getBoundaryLevelAdjust();
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
static_cast<EntityTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||
void EntityTreeRenderer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) {
|
||||
static_cast<EntityTree*>(_tree)->processEraseMessage(packet, sourceNode);
|
||||
}
|
||||
|
||||
Model* EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) {
|
||||
Model* model = NULL;
|
||||
// Make sure we only create and delete models on the thread that owns the EntityTreeRenderer
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(Model*, model),
|
||||
Q_ARG(const QString&, url));
|
||||
|
||||
|
@ -717,7 +717,7 @@ Model* EntityTreeRenderer::updateModel(Model* original, const QString& newUrl, c
|
|||
|
||||
// Before we do any creating or deleting, make sure we're on our renderer thread
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(this, "updateModel", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(Model*, model),
|
||||
Q_ARG(Model*, original),
|
||||
Q_ARG(const QString&, newUrl));
|
||||
|
@ -758,7 +758,7 @@ void EntityTreeRenderer::deleteReleasedModels() {
|
|||
}
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking) {
|
||||
RayToEntityIntersectionResult result;
|
||||
if (_tree) {
|
||||
|
@ -766,8 +766,8 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
|||
|
||||
OctreeElement* element;
|
||||
EntityItemPointer intersectedEntity = NULL;
|
||||
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
if (result.intersects && intersectedEntity) {
|
||||
result.entityID = intersectedEntity->getEntityItemID();
|
||||
|
@ -780,15 +780,15 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
||||
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface,
|
||||
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface,
|
||||
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId){
|
||||
entityScriptingInterface->mousePressOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
|
||||
});
|
||||
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface,
|
||||
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface,
|
||||
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) {
|
||||
entityScriptingInterface->mouseMoveOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
|
||||
});
|
||||
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface,
|
||||
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface,
|
||||
[=](const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId) {
|
||||
entityScriptingInterface->mouseReleaseOnEntity(intersection.entityID, MouseEvent(*event, deviceId));
|
||||
});
|
||||
|
@ -968,7 +968,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event, unsigned int deviceI
|
|||
|
||||
} else {
|
||||
// handle the hover logic...
|
||||
// if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to
|
||||
// if we were previously hovering over an entity, and we're no longer hovering over any entity then we need to
|
||||
// send the hover leave for our previous entity
|
||||
if (!_currentHoverOverEntityID.isInvalidID()) {
|
||||
emit hoverLeaveEntity(_currentHoverOverEntityID, MouseEvent(*event, deviceID));
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
class EntityTreeRenderer : public OctreeRenderer, public EntityItemFBXService, public ScriptUser {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
AbstractScriptingServicesInterface* scriptingServices);
|
||||
virtual ~EntityTreeRenderer();
|
||||
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
EntityTree* getTree() { return static_cast<EntityTree*>(_tree); }
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
virtual void render(RenderArgs* renderArgs) override;
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
Q_INVOKABLE Model* allocateModel(const QString& url, const QString& collisionUrl);
|
||||
|
||||
/// if a renderable entity item needs to update the URL of a model, we will handle that for the entity
|
||||
Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl, const QString& collisionUrl);
|
||||
Q_INVOKABLE Model* updateModel(Model* original, const QString& newUrl, const QString& collisionUrl);
|
||||
|
||||
/// if a renderable entity item is done with a model, it should return it to us
|
||||
void releaseModel(Model* model);
|
||||
|
@ -136,7 +136,7 @@ private:
|
|||
|
||||
QList<Model*> _releasedModels;
|
||||
void renderProxies(EntityItemPointer entity, RenderArgs* args);
|
||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking);
|
||||
|
||||
EntityItemID _currentHoverOverEntityID;
|
||||
|
|
|
@ -17,9 +17,18 @@
|
|||
#include "EntitiesLogging.h"
|
||||
#include "EntityItem.h"
|
||||
|
||||
EntityEditPacketSender::EntityEditPacketSender() {
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::EntityEditNack, this, "processEntityEditNackPacket");
|
||||
}
|
||||
|
||||
void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer<NLPacket> packet) {
|
||||
if (_shouldNack) {
|
||||
processNackPacket(QByteArray::fromRawData(packet->getData(), packet->getSizeWithHeader()));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityEditPacketSender::adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew) {
|
||||
|
||||
if (type == PacketType::EntityAdd || type == PacketType::EntityEdit) {
|
||||
EntityItem::adjustEditPacketForClockSkew(buffer, clockSkew);
|
||||
}
|
||||
|
|
|
@ -14,12 +14,16 @@
|
|||
|
||||
#include <OctreeEditPacketSender.h>
|
||||
|
||||
#include <PacketListener.h>
|
||||
|
||||
#include "EntityItem.h"
|
||||
|
||||
/// Utility for processing, packing, queueing and sending of outbound edit voxel messages.
|
||||
class EntityEditPacketSender : public OctreeEditPacketSender {
|
||||
class EntityEditPacketSender : public OctreeEditPacketSender, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EntityEditPacketSender();
|
||||
|
||||
/// Queues an array of several voxel edit messages. Will potentially send a pending multi-command packet. Determines
|
||||
/// which voxel-server node or nodes the packet should be sent to. Can be called even before voxel servers are known, in
|
||||
/// which case up to MaxPendingMessages will be buffered and processed when voxel servers are known.
|
||||
|
@ -28,8 +32,16 @@ public:
|
|||
|
||||
void queueEraseEntityMessage(const EntityItemID& entityItemID);
|
||||
|
||||
void processEntityEditNackPacket(QSharedPointer<NLPacket> packet);
|
||||
|
||||
// My server type is the model server
|
||||
virtual char getMyNodeType() const { return NodeType::EntityServer; }
|
||||
virtual void adjustEditPacketForClockSkew(PacketType::Value type, QByteArray& buffer, int clockSkew);
|
||||
|
||||
public slots:
|
||||
void toggleNackPackets() { _shouldNack = !_shouldNack; }
|
||||
|
||||
private:
|
||||
bool _shouldNack = false;
|
||||
};
|
||||
#endif // hifi_EntityEditPacketSender_h
|
||||
|
|
|
@ -128,8 +128,8 @@ void EntityItemProperties::setSittingPoints(const QVector<SittingPoint>& sitting
|
|||
}
|
||||
}
|
||||
|
||||
bool EntityItemProperties::animationSettingsChanged() const {
|
||||
return _animationSettingsChanged;
|
||||
bool EntityItemProperties::animationSettingsChanged() const {
|
||||
return _animationSettingsChanged;
|
||||
}
|
||||
|
||||
void EntityItemProperties::setAnimationSettings(const QString& value) {
|
||||
|
@ -900,11 +900,14 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
//
|
||||
// TODO: Implement support for script and visible properties.
|
||||
//
|
||||
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||
bool EntityItemProperties::decodeEntityEditPacket(NLPacket& packet, int& processedBytes,
|
||||
EntityItemID& entityID, EntityItemProperties& properties) {
|
||||
bool valid = false;
|
||||
|
||||
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(packet.getPayload());
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
int bytesToRead = packet.getSizeUsed();
|
||||
processedBytes = 0;
|
||||
|
||||
// the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
|
||||
|
|
|
@ -179,8 +179,8 @@ public:
|
|||
|
||||
static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer);
|
||||
|
||||
static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
|
||||
EntityItemID& entityID, EntityItemProperties& properties);
|
||||
static bool decodeEntityEditPacket(NLPacket& packet, int& processedBytes,
|
||||
EntityItemID& entityID, EntityItemProperties& properties);
|
||||
|
||||
bool glowLevelChanged() const { return _glowLevelChanged; }
|
||||
bool localRenderAlphaChanged() const { return _localRenderAlphaChanged; }
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "LogHandler.h"
|
||||
|
||||
|
||||
EntityTree::EntityTree(bool shouldReaverage) :
|
||||
EntityTree::EntityTree(bool shouldReaverage) :
|
||||
Octree(shouldReaverage),
|
||||
_fbxService(NULL),
|
||||
_simulation(NULL)
|
||||
|
@ -568,8 +568,8 @@ EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entit
|
|||
return foundEntity;
|
||||
}
|
||||
|
||||
int EntityTree::processEditPacketData(PacketType::Value packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) {
|
||||
int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& senderNode) {
|
||||
|
||||
if (!getIsServer()) {
|
||||
qCDebug(entities) << "UNEXPECTED!!! processEditPacketData() should only be called on a server tree.";
|
||||
|
@ -578,9 +578,9 @@ int EntityTree::processEditPacketData(PacketType::Value packetType, const unsign
|
|||
|
||||
int processedBytes = 0;
|
||||
// we handle these types of "edit" packets
|
||||
switch (packetType) {
|
||||
switch (packet.getType()) {
|
||||
case PacketType::EntityErase: {
|
||||
QByteArray dataByteArray((const char*)editData, maxLength);
|
||||
QByteArray dataByteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(editData), maxLength);
|
||||
processedBytes = processEraseMessageDetails(dataByteArray, senderNode);
|
||||
break;
|
||||
}
|
||||
|
@ -598,8 +598,8 @@ int EntityTree::processEditPacketData(PacketType::Value packetType, const unsign
|
|||
EntityItemID entityItemID;
|
||||
EntityItemProperties properties;
|
||||
startDecode = usecTimestampNow();
|
||||
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(editData, maxLength,
|
||||
processedBytes, entityItemID, properties);
|
||||
bool validEditPacket = EntityItemProperties::decodeEntityEditPacket(packet, processedBytes,
|
||||
entityItemID, properties);
|
||||
endDecode = usecTimestampNow();
|
||||
|
||||
// If we got a valid edit packet, then it could be a new entity or it could be an update to
|
||||
|
@ -609,7 +609,7 @@ int EntityTree::processEditPacketData(PacketType::Value packetType, const unsign
|
|||
startLookup = usecTimestampNow();
|
||||
EntityItemPointer existingEntity = findEntityByEntityItemID(entityItemID);
|
||||
endLookup = usecTimestampNow();
|
||||
if (existingEntity && packetType == PacketType::EntityEdit) {
|
||||
if (existingEntity && packet.getType() == PacketType::EntityEdit) {
|
||||
// if the EntityItem exists, then update it
|
||||
startLogging = usecTimestampNow();
|
||||
if (wantEditLogging()) {
|
||||
|
@ -623,7 +623,7 @@ int EntityTree::processEditPacketData(PacketType::Value packetType, const unsign
|
|||
existingEntity->markAsChangedOnServer();
|
||||
endUpdate = usecTimestampNow();
|
||||
_totalUpdates++;
|
||||
} else if (packetType == PacketType::EntityAdd) {
|
||||
} else if (packet.getType() == PacketType::EntityAdd) {
|
||||
if (senderNode->getCanRez()) {
|
||||
// this is a new entity... assign a new entityID
|
||||
properties.setCreated(properties.getLastEdited());
|
||||
|
@ -651,7 +651,7 @@ int EntityTree::processEditPacketData(PacketType::Value packetType, const unsign
|
|||
} else {
|
||||
static QString repeatedMessage =
|
||||
LogHandler::getInstance().addRepeatedMessageRegex("^Add or Edit failed.*");
|
||||
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity.get();
|
||||
qCDebug(entities) << "Add or Edit failed." << packet.getType() << existingEntity.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -854,45 +854,26 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) {
|
|||
|
||||
|
||||
// TODO: consider consolidating processEraseMessageDetails() and processEraseMessage()
|
||||
int EntityTree::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) {
|
||||
lockForWrite();
|
||||
const unsigned char* packetData = (const unsigned char*)dataByteArray.constData();
|
||||
const unsigned char* dataAt = packetData;
|
||||
size_t packetLength = dataByteArray.size();
|
||||
|
||||
size_t numBytesPacketHeader = numBytesForPacketHeader(dataByteArray);
|
||||
size_t processedBytes = numBytesPacketHeader;
|
||||
dataAt += numBytesPacketHeader;
|
||||
packet.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME));
|
||||
|
||||
dataAt += sizeof(OCTREE_PACKET_FLAGS);
|
||||
processedBytes += sizeof(OCTREE_PACKET_FLAGS);
|
||||
|
||||
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
processedBytes += sizeof(OCTREE_PACKET_SEQUENCE);
|
||||
|
||||
dataAt += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
processedBytes += sizeof(OCTREE_PACKET_SENT_TIME);
|
||||
|
||||
uint16_t numberOfIds = 0; // placeholder for now
|
||||
memcpy(&numberOfIds, dataAt, sizeof(numberOfIds));
|
||||
dataAt += sizeof(numberOfIds);
|
||||
processedBytes += sizeof(numberOfIds);
|
||||
|
||||
if (numberOfIds > 0) {
|
||||
uint16_t numberOfIDs = 0; // placeholder for now
|
||||
packet.readPrimitive(&numberOfIDs);
|
||||
|
||||
if (numberOfIDs > 0) {
|
||||
QSet<EntityItemID> entityItemIDsToDelete;
|
||||
|
||||
for (size_t i = 0; i < numberOfIds; i++) {
|
||||
for (size_t i = 0; i < numberOfIDs; i++) {
|
||||
|
||||
if (processedBytes + NUM_BYTES_RFC4122_UUID > packetLength) {
|
||||
if (NUM_BYTES_RFC4122_UUID > packet.bytesAvailable()) {
|
||||
qCDebug(entities) << "EntityTree::processEraseMessage().... bailing because not enough bytes in buffer";
|
||||
break; // bail to prevent buffer overflow
|
||||
}
|
||||
|
||||
QByteArray encodedID = dataByteArray.mid(processedBytes, NUM_BYTES_RFC4122_UUID);
|
||||
QUuid entityID = QUuid::fromRfc4122(encodedID);
|
||||
dataAt += encodedID.size();
|
||||
processedBytes += encodedID.size();
|
||||
|
||||
QUuid entityID = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
EntityItemID entityItemID(entityID);
|
||||
entityItemIDsToDelete << entityItemID;
|
||||
|
||||
|
@ -904,7 +885,7 @@ int EntityTree::processEraseMessage(const QByteArray& dataByteArray, const Share
|
|||
deleteEntities(entityItemIDsToDelete, true, true);
|
||||
}
|
||||
unlock();
|
||||
return processedBytes;
|
||||
return packet.pos();
|
||||
}
|
||||
|
||||
// This version skips over the header
|
||||
|
|
|
@ -66,8 +66,8 @@ public:
|
|||
virtual bool canProcessVersion(PacketVersion thisVersion) const
|
||||
{ return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; }
|
||||
virtual bool handlesEditPacketType(PacketType::Value packetType) const;
|
||||
virtual int processEditPacketData(PacketType::Value packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||
virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& senderNode);
|
||||
|
||||
virtual bool rootElementHasData() const { return true; }
|
||||
|
||||
|
@ -133,8 +133,8 @@ public:
|
|||
bool& hasMore);
|
||||
void forgetEntitiesDeletedBefore(quint64 sinceTime);
|
||||
|
||||
int processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
int processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
int processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode);
|
||||
int processEraseMessageDetails(const QByteArray& buffer, const SharedNodePointer& sourceNode);
|
||||
|
||||
EntityItemFBXService* getFBXService() const { return _fbxService; }
|
||||
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
|
||||
|
@ -186,9 +186,9 @@ public:
|
|||
virtual quint64 getAverageLoggingTime() const { return _totalEditMessages == 0 ? 0 : _totalLoggingTime / _totalEditMessages; }
|
||||
|
||||
void trackIncomingEntityLastEdited(quint64 lastEditedTime, int bytesRead);
|
||||
quint64 getAverageEditDeltas() const
|
||||
quint64 getAverageEditDeltas() const
|
||||
{ return _totalTrackedEdits == 0 ? 0 : _totalEditDeltas / _totalTrackedEdits; }
|
||||
quint64 getAverageEditBytes() const
|
||||
quint64 getAverageEditBytes() const
|
||||
{ return _totalTrackedEdits == 0 ? 0 : _totalEditBytes / _totalTrackedEdits; }
|
||||
quint64 getMaxEditDelta() const { return _maxEditDelta; }
|
||||
quint64 getTotalTrackedEdits() const { return _totalTrackedEdits; }
|
||||
|
|
|
@ -40,6 +40,6 @@ void EntityTreeHeadlessViewer::update() {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityTreeHeadlessViewer::processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) {
|
||||
static_cast<EntityTree*>(_tree)->processEraseMessage(dataByteArray, sourceNode);
|
||||
void EntityTreeHeadlessViewer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) {
|
||||
static_cast<EntityTree*>(_tree)->processEraseMessage(packet, sourceNode);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
EntityTree* getTree() { return (EntityTree*)_tree; }
|
||||
|
||||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
|
||||
|
|
|
@ -60,28 +60,25 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const
|
|||
}
|
||||
}
|
||||
|
||||
Assignment::Assignment(const QByteArray& packet) :
|
||||
Assignment::Assignment(NLPacket& packet) :
|
||||
_pool(),
|
||||
_location(GlobalLocation),
|
||||
_payload(),
|
||||
_walletUUID()
|
||||
{
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
|
||||
if (packetType == PacketType::RequestAssignment) {
|
||||
if (packet.getType() == PacketType::RequestAssignment) {
|
||||
_command = Assignment::RequestCommand;
|
||||
} else if (packetType == PacketType::CreateAssignment) {
|
||||
} else if (packet.getType() == PacketType::CreateAssignment) {
|
||||
_command = Assignment::CreateCommand;
|
||||
}
|
||||
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
QDataStream packetStream(&packet);
|
||||
|
||||
packetStream >> *this;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(default:4351)
|
||||
#pragma warning(default:4351)
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -59,10 +59,9 @@ public:
|
|||
|
||||
void swap(Assignment& otherAssignment);
|
||||
|
||||
/// Constructs an Assignment from the data in the buffer
|
||||
/// \param dataBuffer the source buffer to un-pack the assignment from
|
||||
/// \param numBytes the number of bytes left to read in the source buffer
|
||||
Assignment(const QByteArray& packet);
|
||||
/// Constructs an Assignment from a network packet
|
||||
/// \param packet the packet to un-pack the assignment from
|
||||
Assignment(NLPacket& packet);
|
||||
|
||||
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
||||
const QUuid& getUUID() const { return _uuid; }
|
||||
|
@ -86,9 +85,6 @@ public:
|
|||
|
||||
const char* getTypeName() const;
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
friend QDebug operator<<(QDebug debug, const Assignment& assignment);
|
||||
friend QDataStream& operator<<(QDataStream &out, const Assignment& assignment);
|
||||
friend QDataStream& operator>>(QDataStream &in, Assignment& assignment);
|
||||
|
|
|
@ -38,6 +38,12 @@ DomainHandler::DomainHandler(QObject* parent) :
|
|||
{
|
||||
// if we get a socket that make sure our NetworkPeer ping timer stops
|
||||
connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer);
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
|
||||
packetReceiver.registerListener(PacketType::ICEServerPeerInformation, this, "processICEResponsePacket");
|
||||
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, this, "processDTLSRequirementPacket");
|
||||
packetReceiver.registerListener(PacketType::ICEPingReply, this, "processICEPingReplyPacket");
|
||||
}
|
||||
|
||||
void DomainHandler::clearConnectionInfo() {
|
||||
|
@ -281,12 +287,28 @@ void DomainHandler::settingsRequestFinished() {
|
|||
settingsReply->deleteLater();
|
||||
}
|
||||
|
||||
void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) {
|
||||
// figure out the port that the DS wants us to use for us to talk to them with DTLS
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(dtlsRequirementPacket);
|
||||
void DomainHandler::processICEPingReplyPacket(QSharedPointer<NLPacket> packet) {
|
||||
const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr();
|
||||
qCDebug(networking) << "Received reply from domain-server on" << senderSockAddr;
|
||||
|
||||
unsigned short dtlsPort = 0;
|
||||
memcpy(&dtlsPort, dtlsRequirementPacket.data() + numBytesPacketHeader, sizeof(dtlsPort));
|
||||
if (getIP().isNull()) {
|
||||
// for now we're unsafely assuming this came back from the domain
|
||||
if (senderSockAddr == _icePeer.getLocalSocket()) {
|
||||
qCDebug(networking) << "Connecting to domain using local socket";
|
||||
activateICELocalSocket();
|
||||
} else if (senderSockAddr == _icePeer.getPublicSocket()) {
|
||||
qCDebug(networking) << "Conecting to domain using public socket";
|
||||
activateICEPublicSocket();
|
||||
} else {
|
||||
qCDebug(networking) << "Reply does not match either local or public socket for domain. Will not connect.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DomainHandler::processDTLSRequirementPacket(QSharedPointer<NLPacket> dtlsRequirementPacket) {
|
||||
// figure out the port that the DS wants us to use for us to talk to them with DTLS
|
||||
unsigned short dtlsPort;
|
||||
dtlsRequirementPacket->readPrimitive(&dtlsPort);
|
||||
|
||||
qCDebug(networking) << "domain-server DTLS port changed to" << dtlsPort << "- Enabling DTLS.";
|
||||
|
||||
|
@ -295,9 +317,13 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement
|
|||
// initializeDTLSSession();
|
||||
}
|
||||
|
||||
void DomainHandler::processICEResponsePacket(const QByteArray& icePacket) {
|
||||
QDataStream iceResponseStream(icePacket);
|
||||
iceResponseStream.skipRawData(numBytesForPacketHeader(icePacket));
|
||||
void DomainHandler::processICEResponsePacket(QSharedPointer<NLPacket> icePacket) {
|
||||
if (!_icePeer.hasSockets()) {
|
||||
// bail on processing this packet if our ice peer doesn't have sockets
|
||||
return;
|
||||
}
|
||||
|
||||
QDataStream iceResponseStream(icePacket.data());
|
||||
|
||||
iceResponseStream >> _icePeer;
|
||||
|
||||
|
|
|
@ -21,17 +21,19 @@
|
|||
|
||||
#include "HifiSockAddr.h"
|
||||
#include "NetworkPeer.h"
|
||||
#include "NLPacket.h"
|
||||
#include "PacketListener.h"
|
||||
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102;
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = 40103;
|
||||
const quint16 DOMAIN_SERVER_HTTP_PORT = 40100;
|
||||
const quint16 DOMAIN_SERVER_HTTPS_PORT = 40101;
|
||||
|
||||
class DomainHandler : public QObject {
|
||||
class DomainHandler : public QObject, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
DomainHandler(QObject* parent = 0);
|
||||
|
||||
|
||||
void clearConnectionInfo();
|
||||
void clearSettings();
|
||||
|
||||
|
@ -69,9 +71,7 @@ public:
|
|||
void requestDomainSettings();
|
||||
const QJsonObject& getSettingsObject() const { return _settingsObject; }
|
||||
|
||||
void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket);
|
||||
void processICEResponsePacket(const QByteArray& icePacket);
|
||||
|
||||
|
||||
void setPendingPath(const QString& pendingPath) { _pendingPath = pendingPath; }
|
||||
const QString& getPendingPath() { return _pendingPath; }
|
||||
void clearPendingPath() { _pendingPath.clear(); }
|
||||
|
@ -83,6 +83,10 @@ public slots:
|
|||
void setHostnameAndPort(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT);
|
||||
void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id);
|
||||
|
||||
void processICEPingReplyPacket(QSharedPointer<NLPacket> packet);
|
||||
void processDTLSRequirementPacket(QSharedPointer<NLPacket> dtlsRequirementPacket);
|
||||
void processICEResponsePacket(QSharedPointer<NLPacket> icePacket);
|
||||
|
||||
private slots:
|
||||
void completedHostnameLookup(const QHostInfo& hostInfo);
|
||||
void completedIceServerHostnameLookup();
|
||||
|
|
|
@ -50,6 +50,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
_localSockAddr(),
|
||||
_publicSockAddr(),
|
||||
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
|
||||
_packetReceiver(this),
|
||||
_numCollectedPackets(0),
|
||||
_numCollectedBytes(0),
|
||||
_packetStatTimer(),
|
||||
|
@ -94,7 +95,14 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
// check the local socket right now
|
||||
updateLocalSockAddr();
|
||||
|
||||
// TODO: Create a new thread, and move PacketReceiver to it
|
||||
|
||||
connect(&_nodeSocket, &QUdpSocket::readyRead, &_packetReceiver, &PacketReceiver::processDatagrams);
|
||||
|
||||
_packetStatTimer.start();
|
||||
|
||||
// make sure we handle STUN response packets
|
||||
_packetReceiver.registerListener(PacketType::StunResponse, this, "processSTUNResponse");
|
||||
}
|
||||
|
||||
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||
|
@ -165,54 +173,33 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
|||
}
|
||||
}
|
||||
|
||||
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||
PacketType::Value checkType = packetTypeForPacket(packet);
|
||||
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
||||
|
||||
if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
|
||||
&& checkType != PacketType::StunResponse) {
|
||||
PacketType::Value mismatchType = packetTypeForPacket(packet);
|
||||
|
||||
static QMultiMap<QUuid, PacketType::Value> versionDebugSuppressMap;
|
||||
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||
qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
|
||||
<< uuidFromPacketHeader(packet) << "sent" << qPrintable(QString::number(packet[numPacketTypeBytes])) << "but"
|
||||
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
|
||||
|
||||
emit packetVersionMismatch();
|
||||
|
||||
versionDebugSuppressMap.insert(senderUUID, checkType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NON_VERIFIED_PACKETS.contains(checkType)) {
|
||||
bool LimitedNodeList::packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode) {
|
||||
|
||||
if (!NON_VERIFIED_PACKETS.contains(packet.getType()) && !NON_SOURCED_PACKETS.contains(packet.getType())) {
|
||||
// figure out which node this is from
|
||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||
if (sendingNode) {
|
||||
matchingNode = nodeWithUUID(packet.getSourceID());
|
||||
|
||||
if (matchingNode) {
|
||||
// check if the md5 hash in the header matches the hash we would expect
|
||||
if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) {
|
||||
if (packet.getVerificationHash() == packet.payloadHashWithConnectionUUID(matchingNode->getConnectionSecret())) {
|
||||
return true;
|
||||
} else {
|
||||
static QMultiMap<QUuid, PacketType::Value> hashDebugSuppressMap;
|
||||
|
||||
const QUuid& senderID = packet.getSourceID();
|
||||
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||
qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
|
||||
<< uuidFromPacketHeader(packet);
|
||||
if (!hashDebugSuppressMap.contains(senderID, packet.getType())) {
|
||||
qCDebug(networking) << "Packet hash mismatch on" << packet.getType() << "- Sender" << senderID;
|
||||
|
||||
hashDebugSuppressMap.insert(senderUUID, checkType);
|
||||
hashDebugSuppressMap.insert(senderID, packet.getType());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static QString repeatedMessage
|
||||
= LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");
|
||||
|
||||
qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID"
|
||||
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
|
||||
qCDebug(networking) << "Packet of type" << packet.getType() << "received from unknown node with UUID"
|
||||
<< qPrintable(uuidStringWithoutCurlyBraces(packet.getSourceID()));
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
|
@ -317,47 +304,19 @@ PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid
|
|||
return _packetSequenceNumbers[nodeUUID][packetType]++;
|
||||
}
|
||||
|
||||
void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
// the node decided not to do anything with this packet
|
||||
// if it comes from a known source we should keep that node alive
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
if (matchingNode) {
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
}
|
||||
int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
QMutexLocker locker(&sendingNode->getMutex());
|
||||
|
||||
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
|
||||
QMutexLocker locker(&matchingNode->getMutex());
|
||||
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
// if this was a sequence numbered packet we should store the last seq number for
|
||||
// a packet of this type for this node
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
|
||||
}
|
||||
|
||||
NodeData* linkedData = matchingNode->getLinkedData();
|
||||
NodeData* linkedData = sendingNode->getLinkedData();
|
||||
if (!linkedData && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(matchingNode.data());
|
||||
linkedDataCreateCallback(sendingNode.data());
|
||||
}
|
||||
|
||||
if (linkedData) {
|
||||
QMutexLocker linkedDataLocker(&linkedData->getMutex());
|
||||
return linkedData->parseData(packet);
|
||||
return linkedData->parseData(*packet);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
|
||||
if (matchingNode) {
|
||||
return updateNodeWithDataFromPacket(matchingNode, packet);
|
||||
}
|
||||
|
||||
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -368,13 +327,6 @@ SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
|||
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
||||
}
|
||||
|
||||
SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||
|
||||
// return the matching node, or NULL if there is no match
|
||||
return nodeWithUUID(nodeUUID);
|
||||
}
|
||||
|
||||
void LimitedNodeList::eraseAllNodes() {
|
||||
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
|
||||
|
||||
|
@ -416,9 +368,9 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
|||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::processKillNode(const QByteArray& dataByteArray) {
|
||||
void LimitedNodeList::processKillNode(NLPacket& packet) {
|
||||
// read the node id
|
||||
QUuid nodeUUID = QUuid::fromRfc4122(dataByteArray.mid(numBytesForPacketHeader(dataByteArray), NUM_BYTES_RFC4122_UUID));
|
||||
QUuid nodeUUID = QUuid::fromRfc4122(packet.read(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
// kill the node with this UUID, if it exists
|
||||
killNodeWithUUID(nodeUUID);
|
||||
|
@ -477,9 +429,8 @@ std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(PingType_t pingTy
|
|||
return pingPacket;
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket) {
|
||||
QDataStream pingPacketStream(pingPacket);
|
||||
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
|
||||
std::unique_ptr<NLPacket> LimitedNodeList::constructPingReplyPacket(NLPacket& pingPacket) {
|
||||
QDataStream pingPacketStream(&pingPacket);
|
||||
|
||||
PingType_t typeFromOriginalPing;
|
||||
pingPacketStream >> typeFromOriginalPing;
|
||||
|
@ -508,11 +459,11 @@ std::unique_ptr<NLPacket> LimitedNodeList::constructICEPingPacket(PingType_t pin
|
|||
return icePingPacket;
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> LimitedNodeList::constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID) {
|
||||
std::unique_ptr<NLPacket> LimitedNodeList::constructICEPingReplyPacket(NLPacket& pingPacket, const QUuid& iceID) {
|
||||
// pull out the ping type so we can reply back with that
|
||||
PingType_t pingType;
|
||||
|
||||
memcpy(&pingType, pingPacket.data() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t));
|
||||
memcpy(&pingType, pingPacket.getPayload() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t));
|
||||
|
||||
int packetSize = NUM_BYTES_RFC4122_UUID + sizeof(PingType_t);
|
||||
auto icePingReplyPacket = NLPacket::create(PacketType::ICEPingReply, packetSize);
|
||||
|
@ -635,7 +586,7 @@ void LimitedNodeList::rebindNodeSocket() {
|
|||
_nodeSocket.bind(QHostAddress::AnyIPv4, oldPort);
|
||||
}
|
||||
|
||||
bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
||||
bool LimitedNodeList::processSTUNResponse(QSharedPointer<NLPacket> packet) {
|
||||
// check the cookie to make sure this is actually a STUN response
|
||||
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
||||
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
||||
|
@ -645,13 +596,13 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
|||
|
||||
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
||||
|
||||
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||
if (memcmp(packet->getData() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
||||
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
||||
|
||||
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||
while (attributeStartIndex < packet.size()) {
|
||||
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||
while (attributeStartIndex < packet->getSizeWithHeader()) {
|
||||
if (memcmp(packet->getData() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
||||
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
||||
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
||||
|
@ -659,14 +610,14 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
|||
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
||||
|
||||
uint8_t addressFamily = 0;
|
||||
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
||||
memcpy(&addressFamily, packet->getData() + byteIndex, sizeof(addressFamily));
|
||||
|
||||
byteIndex += sizeof(addressFamily);
|
||||
|
||||
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
||||
// grab the X-Port
|
||||
uint16_t xorMappedPort = 0;
|
||||
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
||||
memcpy(&xorMappedPort, packet->getData() + byteIndex, sizeof(xorMappedPort));
|
||||
|
||||
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
||||
|
||||
|
@ -674,7 +625,7 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
|||
|
||||
// grab the X-Address
|
||||
uint32_t xorMappedAddress = 0;
|
||||
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
||||
memcpy(&xorMappedAddress, packet->getData() + byteIndex, sizeof(xorMappedAddress));
|
||||
|
||||
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
|
@ -704,7 +655,7 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
|
|||
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
||||
|
||||
uint16_t attributeLength = 0;
|
||||
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
||||
memcpy(&attributeLength, packet->getData() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
||||
sizeof(attributeLength));
|
||||
attributeLength = ntohs(attributeLength);
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <QtCore/QReadWriteLock>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QSharedMemory>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtNetwork/QUdpSocket>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
|
||||
|
@ -39,6 +38,8 @@
|
|||
#include "Node.h"
|
||||
#include "NLPacket.h"
|
||||
#include "udt/PacketHeaders.h"
|
||||
#include "PacketReceiver.h"
|
||||
#include "PacketListener.h"
|
||||
#include "NLPacketList.h"
|
||||
#include "UUIDHasher.h"
|
||||
|
||||
|
@ -61,9 +62,6 @@ const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
|
|||
|
||||
class HifiSockAddr;
|
||||
|
||||
typedef QSharedPointer<Node> SharedNodePointer;
|
||||
Q_DECLARE_METATYPE(SharedNodePointer)
|
||||
|
||||
using namespace tbb;
|
||||
typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
|
||||
typedef concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;
|
||||
|
@ -76,7 +74,7 @@ namespace PingType {
|
|||
const PingType_t Symmetric = 3;
|
||||
}
|
||||
|
||||
class LimitedNodeList : public QObject, public Dependency {
|
||||
class LimitedNodeList : public QObject, public Dependency, public PacketListener {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
public:
|
||||
|
@ -117,9 +115,9 @@ public:
|
|||
QUdpSocket& getNodeSocket() { return _nodeSocket; }
|
||||
QUdpSocket& getDTLSSocket();
|
||||
|
||||
bool packetVersionAndHashMatch(const QByteArray& packet);
|
||||
bool packetSourceAndHashMatch(const NLPacket& packet, SharedNodePointer& matchingNode);
|
||||
|
||||
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
|
||||
PacketReceiver& getPacketReceiver() { return _packetReceiver; }
|
||||
|
||||
qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode);
|
||||
qint64 sendUnreliablePacket(const NLPacket& packet, const HifiSockAddr& sockAddr);
|
||||
|
@ -135,7 +133,6 @@ public:
|
|||
int size() const { return _nodeHash.size(); }
|
||||
|
||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||
|
||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||
|
@ -147,11 +144,9 @@ public:
|
|||
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
||||
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
||||
|
||||
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
void processKillNode(const QByteArray& datagram);
|
||||
void processKillNode(NLPacket& packet);
|
||||
|
||||
int updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray& packet);
|
||||
int findNodeAndUpdateWithDataFromPacket(const QByteArray& packet);
|
||||
int updateNodeWithDataFromPacket(QSharedPointer<NLPacket> packet, SharedNodePointer matchingNode);
|
||||
|
||||
unsigned int broadcastToNodes(std::unique_ptr<NLPacket> packet, const NodeSet& destinationNodeTypes);
|
||||
SharedNodePointer soloNodeOfType(char nodeType);
|
||||
|
@ -160,12 +155,12 @@ public:
|
|||
void resetPacketStats();
|
||||
|
||||
std::unique_ptr<NLPacket> constructPingPacket(PingType_t pingType = PingType::Agnostic);
|
||||
std::unique_ptr<NLPacket> constructPingReplyPacket(const QByteArray& pingPacket);
|
||||
std::unique_ptr<NLPacket> constructPingReplyPacket(NLPacket& pingPacket);
|
||||
|
||||
std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
|
||||
std::unique_ptr<NLPacket> constructICEPingReplyPacket(const QByteArray& pingPacket, const QUuid& iceID);
|
||||
std::unique_ptr<NLPacket> constructICEPingReplyPacket(NLPacket& pingPacket, const QUuid& iceID);
|
||||
|
||||
virtual bool processSTUNResponse(const QByteArray& packet);
|
||||
virtual bool processSTUNResponse(QSharedPointer<NLPacket> packet);
|
||||
|
||||
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr);
|
||||
void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID);
|
||||
|
@ -234,6 +229,7 @@ public slots:
|
|||
virtual void sendSTUNRequest();
|
||||
|
||||
void killNodeWithUUID(const QUuid& nodeUUID);
|
||||
|
||||
signals:
|
||||
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
||||
void nodeAdded(SharedNodePointer);
|
||||
|
@ -245,11 +241,6 @@ signals:
|
|||
void canAdjustLocksChanged(bool canAdjustLocks);
|
||||
void canRezChanged(bool canRez);
|
||||
|
||||
void dataSent(const quint8 channel_type, const int bytes);
|
||||
void dataReceived(const quint8 channel_type, const int bytes);
|
||||
|
||||
void packetVersionMismatch();
|
||||
|
||||
protected:
|
||||
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
||||
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
|
@ -282,6 +273,8 @@ protected:
|
|||
HifiSockAddr _publicSockAddr;
|
||||
HifiSockAddr _stunSockAddr;
|
||||
|
||||
PacketReceiver _packetReceiver;
|
||||
|
||||
// XXX can BandwidthRecorder be used for this?
|
||||
int _numCollectedPackets;
|
||||
int _numCollectedBytes;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
qint64 NLPacket::localHeaderSize(PacketType::Value type) {
|
||||
qint64 size = ((NON_SOURCED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID) +
|
||||
((NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_RFC4122_UUID);
|
||||
((NON_SOURCED_PACKETS.contains(type) || NON_VERIFIED_PACKETS.contains(type)) ? 0 : NUM_BYTES_MD5_HASH);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,19 @@ std::unique_ptr<NLPacket> NLPacket::create(PacketType::Value type, qint64 size)
|
|||
return std::unique_ptr<NLPacket>(new NLPacket(type, size));
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> NLPacket::fromReceivedPacket(std::unique_ptr<char> data, qint64 size,
|
||||
const HifiSockAddr& senderSockAddr) {
|
||||
// Fail with null data
|
||||
Q_ASSERT(data);
|
||||
|
||||
// Fail with invalid size
|
||||
Q_ASSERT(size >= 0);
|
||||
|
||||
// allocate memory
|
||||
return std::unique_ptr<NLPacket>(new NLPacket(std::move(data), size, senderSockAddr));
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> NLPacket::createCopy(const NLPacket& other) {
|
||||
return std::unique_ptr<NLPacket>(new NLPacket(other));
|
||||
}
|
||||
|
@ -43,15 +56,52 @@ NLPacket::NLPacket(PacketType::Value type, qint64 size) : Packet(type, localHead
|
|||
NLPacket::NLPacket(const NLPacket& other) : Packet(other) {
|
||||
}
|
||||
|
||||
void NLPacket::setSourceUuid(QUuid sourceUuid) {
|
||||
Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type));
|
||||
auto offset = Packet::totalHeadersSize();
|
||||
memcpy(_packet.get() + offset, sourceUuid.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||
NLPacket::NLPacket(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr) :
|
||||
Packet(std::move(data), size, senderSockAddr)
|
||||
{
|
||||
readSourceID();
|
||||
readVerificationHash();
|
||||
}
|
||||
|
||||
void NLPacket::setConnectionUuid(QUuid connectionUuid) {
|
||||
Q_ASSERT(!NON_VERIFIED_PACKETS.contains(_type));
|
||||
auto offset = Packet::totalHeadersSize() +
|
||||
((NON_SOURCED_PACKETS.contains(_type)) ? 0 : NUM_BYTES_RFC4122_UUID);
|
||||
memcpy(_packet.get() + offset, connectionUuid.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||
void NLPacket::readSourceID() {
|
||||
if (!NON_SOURCED_PACKETS.contains(_type)) {
|
||||
auto offset = Packet::totalHeadersSize();
|
||||
_sourceID = QUuid::fromRfc4122(QByteArray::fromRawData(_packet.get() + offset, NUM_BYTES_RFC4122_UUID));
|
||||
}
|
||||
}
|
||||
|
||||
void NLPacket::readVerificationHash() {
|
||||
if (!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type)) {
|
||||
auto offset = Packet::totalHeadersSize() + NUM_BYTES_RFC4122_UUID;
|
||||
_verificationHash = QByteArray(_packet.get() + offset, NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
}
|
||||
|
||||
void NLPacket::setSourceID(const QUuid& sourceID) {
|
||||
Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type));
|
||||
|
||||
auto offset = Packet::totalHeadersSize();
|
||||
memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||
|
||||
_sourceID = sourceID;
|
||||
}
|
||||
|
||||
void NLPacket::setVerificationHash(const QByteArray& verificationHash) {
|
||||
Q_ASSERT(!NON_SOURCED_PACKETS.contains(_type) && !NON_VERIFIED_PACKETS.contains(_type));
|
||||
|
||||
auto offset = Packet::totalHeadersSize() + NUM_BYTES_RFC4122_UUID;
|
||||
memcpy(_packet.get() + offset, verificationHash.data(), verificationHash.size());
|
||||
|
||||
_verificationHash = verificationHash;
|
||||
}
|
||||
|
||||
QByteArray NLPacket::payloadHashWithConnectionUUID(const QUuid& connectionUUID) const {
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
|
||||
// add the packet payload and the connection UUID
|
||||
hash.addData(_payloadStart, _sizeUsed);
|
||||
hash.addData(connectionUUID.toRfc4122());
|
||||
|
||||
// return the hash
|
||||
return hash.result();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ class NLPacket : public Packet {
|
|||
Q_OBJECT
|
||||
public:
|
||||
static std::unique_ptr<NLPacket> create(PacketType::Value type, qint64 size = -1);
|
||||
static std::unique_ptr<NLPacket> fromReceivedPacket(std::unique_ptr<char> data, qint64 size,
|
||||
const HifiSockAddr& senderSockAddr);
|
||||
// Provided for convenience, try to limit use
|
||||
static std::unique_ptr<NLPacket> createCopy(const NLPacket& other);
|
||||
|
||||
|
@ -27,12 +29,24 @@ public:
|
|||
virtual qint64 totalHeadersSize() const; // Cumulated size of all the headers
|
||||
virtual qint64 localHeaderSize() const; // Current level's header size
|
||||
|
||||
const QUuid& getSourceID() const { return _sourceID; }
|
||||
const QByteArray& getVerificationHash() const { return _verificationHash; }
|
||||
|
||||
QByteArray payloadHashWithConnectionUUID(const QUuid& connectionUUID) const;
|
||||
|
||||
protected:
|
||||
NLPacket(PacketType::Value type, qint64 size);
|
||||
NLPacket(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
||||
NLPacket(const NLPacket& other);
|
||||
|
||||
void setSourceUuid(QUuid sourceUuid);
|
||||
void setConnectionUuid(QUuid connectionUuid);
|
||||
void readSourceID();
|
||||
void setSourceID(const QUuid& sourceID);
|
||||
|
||||
void readVerificationHash();
|
||||
void setVerificationHash(const QByteArray& verificationHash);
|
||||
|
||||
QUuid _sourceID;
|
||||
QByteArray _verificationHash;
|
||||
};
|
||||
|
||||
#endif // hifi_NLPacket_h
|
||||
|
|
|
@ -59,8 +59,8 @@ public:
|
|||
quint64 getWakeTimestamp() const { return _wakeTimestamp; }
|
||||
void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; }
|
||||
|
||||
quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; }
|
||||
void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; }
|
||||
quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp.load(); }
|
||||
void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp.store(lastHeardMicrostamp); }
|
||||
|
||||
QByteArray toByteArray() const;
|
||||
|
||||
|
@ -92,7 +92,7 @@ protected:
|
|||
HifiSockAddr* _activeSocket;
|
||||
|
||||
quint64 _wakeTimestamp;
|
||||
quint64 _lastHeardMicrostamp;
|
||||
std::atomic_ullong _lastHeardMicrostamp;
|
||||
|
||||
QTimer* _pingTimer = NULL;
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QMutex>
|
||||
|
||||
#include "HifiSockAddr.h"
|
||||
#include "NetworkPeer.h"
|
||||
|
@ -92,6 +92,9 @@ private:
|
|||
PacketTypeSequenceMap _lastSequenceNumbers;
|
||||
};
|
||||
|
||||
typedef QSharedPointer<Node> SharedNodePointer;
|
||||
Q_DECLARE_METATYPE(SharedNodePointer)
|
||||
|
||||
QDebug operator<<(QDebug debug, const Node &message);
|
||||
|
||||
#endif // hifi_Node_h
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "NLPacket.h"
|
||||
|
||||
class Node;
|
||||
|
||||
|
@ -22,7 +25,7 @@ class NodeData : public QObject {
|
|||
public:
|
||||
NodeData();
|
||||
virtual ~NodeData() = 0;
|
||||
virtual int parseData(const QByteArray& packet) = 0;
|
||||
virtual int parseData(NLPacket& packet) { return 0; }
|
||||
|
||||
QMutex& getMutex() { return _mutex; }
|
||||
|
||||
|
|
|
@ -45,6 +45,11 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
qRegisterMetaType<SharedNodePointer>();
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
setCustomDeleter([](Dependency* dependency){
|
||||
static_cast<NodeList*>(dependency)->deleteLater();
|
||||
});
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
// handle domain change signals from AddressManager
|
||||
|
@ -90,6 +95,12 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
|
||||
// we definitely want STUN to update our public socket, so call the LNL to kick that off
|
||||
startSTUNPublicSocketUpdate();
|
||||
|
||||
auto& packetReceiver = getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::DomainList, this, "processDomainServerList");
|
||||
packetReceiver.registerListener(PacketType::Ping, this, "processPingPacket");
|
||||
packetReceiver.registerListener(PacketType::PingReply, this, "processPingReplyPacket");
|
||||
packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket");
|
||||
}
|
||||
|
||||
qint64 NodeList::sendStats(const QJsonObject& statsObject, const HifiSockAddr& destination) {
|
||||
|
@ -116,9 +127,8 @@ qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) {
|
|||
return sendStats(statsObject, _domainHandler.getSockAddr());
|
||||
}
|
||||
|
||||
void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
void NodeList::timePingReply(QSharedPointer<NLPacket> packet, const SharedNodePointer& sendingNode) {
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
quint8 pingType;
|
||||
quint64 ourOriginalTime, othersReplyTime;
|
||||
|
@ -152,106 +162,36 @@ void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer&
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
|
||||
PacketType::Value packetType = packetTypeForPacket(packet);
|
||||
switch (packetType) {
|
||||
case PacketType::DomainList:
|
||||
case PacketType::DomainServerAddedNode: {
|
||||
if (!_domainHandler.getSockAddr().isNull()) {
|
||||
// only process a packet from domain-server if we're talking to a domain
|
||||
// TODO: how do we make sure this is actually the domain we want the list from (DTLS probably)
|
||||
if (packetType == PacketType::DomainList) {
|
||||
processDomainServerList(packet);
|
||||
} else if (packetType == PacketType::DomainServerAddedNode) {
|
||||
processDomainServerAddedNode(packet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType::DomainServerRequireDTLS: {
|
||||
_domainHandler.parseDTLSRequirementPacket(packet);
|
||||
break;
|
||||
}
|
||||
case PacketType::ICEServerPeerInformation: {
|
||||
if (!_domainHandler.getICEPeer().hasSockets()) {
|
||||
_domainHandler.processICEResponsePacket(packet);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PacketType::Ping: {
|
||||
// send back a reply
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
if (matchingNode) {
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
auto replyPacket = constructPingReplyPacket(packet);
|
||||
sendPacket(std::move(replyPacket), *matchingNode, senderSockAddr);
|
||||
void NodeList::processPingPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
// send back a reply
|
||||
auto replyPacket = constructPingReplyPacket(*packet);
|
||||
const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr();
|
||||
sendPacket(std::move(replyPacket), sendingNode, senderSockAddr);
|
||||
|
||||
// If we don't have a symmetric socket for this node and this socket doesn't match
|
||||
// what we have for public and local then set it as the symmetric.
|
||||
// This allows a server on a reachable port to communicate with nodes on symmetric NATs
|
||||
if (matchingNode->getSymmetricSocket().isNull()) {
|
||||
if (senderSockAddr != matchingNode->getLocalSocket() && senderSockAddr != matchingNode->getPublicSocket()) {
|
||||
matchingNode->setSymmetricSocket(senderSockAddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
// If we don't have a symmetric socket for this node and this socket doesn't match
|
||||
// what we have for public and local then set it as the symmetric.
|
||||
// This allows a server on a reachable port to communicate with nodes on symmetric NATs
|
||||
if (sendingNode->getSymmetricSocket().isNull()) {
|
||||
if (senderSockAddr != sendingNode->getLocalSocket() && senderSockAddr != sendingNode->getPublicSocket()) {
|
||||
sendingNode->setSymmetricSocket(senderSockAddr);
|
||||
}
|
||||
case PacketType::PingReply: {
|
||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||
|
||||
if (sendingNode) {
|
||||
sendingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
// activate the appropriate socket for this node, if not yet updated
|
||||
activateSocketFromNodeCommunication(packet, sendingNode);
|
||||
|
||||
// set the ping time for this node for stat collection
|
||||
timePingReply(packet, sendingNode);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PacketType::ICEPing: {
|
||||
// send back a reply
|
||||
auto replyPacket = constructICEPingReplyPacket(packet, _domainHandler.getICEClientID());
|
||||
sendPacket(std::move(replyPacket), senderSockAddr);
|
||||
break;
|
||||
}
|
||||
case PacketType::ICEPingReply: {
|
||||
qCDebug(networking) << "Received reply from domain-server on" << senderSockAddr;
|
||||
|
||||
if (_domainHandler.getIP().isNull()) {
|
||||
// for now we're unsafely assuming this came back from the domain
|
||||
if (senderSockAddr == _domainHandler.getICEPeer().getLocalSocket()) {
|
||||
qCDebug(networking) << "Connecting to domain using local socket";
|
||||
_domainHandler.activateICELocalSocket();
|
||||
} else if (senderSockAddr == _domainHandler.getICEPeer().getPublicSocket()) {
|
||||
qCDebug(networking) << "Conecting to domain using public socket";
|
||||
_domainHandler.activateICEPublicSocket();
|
||||
} else {
|
||||
qCDebug(networking) << "Reply does not match either local or public socket for domain. Will not connect.";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
case PacketType::StunResponse: {
|
||||
// a STUN packet begins with 00, we've checked the second zero with packetVersionMatch
|
||||
// pass it along so it can be processed into our public address and port
|
||||
processSTUNResponse(packet);
|
||||
break;
|
||||
}
|
||||
case PacketType::DomainServerPathResponse: {
|
||||
handleDSPathQueryResponse(packet);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LimitedNodeList::processNodeData(senderSockAddr, packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::processPingReplyPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
// activate the appropriate socket for this node, if not yet updated
|
||||
activateSocketFromNodeCommunication(packet, sendingNode);
|
||||
|
||||
// set the ping time for this node for stat collection
|
||||
timePingReply(packet, sendingNode);
|
||||
}
|
||||
|
||||
void NodeList::processICEPingPacket(QSharedPointer<NLPacket> packet) {
|
||||
// send back a reply
|
||||
auto replyPacket = constructICEPingReplyPacket(*packet, _domainHandler.getICEClientID());
|
||||
sendPacket(std::move(replyPacket), packet->getSenderSockAddr());
|
||||
}
|
||||
|
||||
void NodeList::reset() {
|
||||
LimitedNodeList::reset();
|
||||
|
||||
|
@ -419,43 +359,35 @@ void NodeList::sendDSPathQuery(const QString& newPath) {
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::handleDSPathQueryResponse(const QByteArray& packet) {
|
||||
void NodeList::processDomainServerPathQueryResponse(QSharedPointer<NLPacket> packet) {
|
||||
// This is a response to a path query we theoretically made.
|
||||
// In the future we may want to check that this was actually from our DS and for a query we actually made.
|
||||
|
||||
int numHeaderBytes = numBytesForPacketHeaderGivenPacketType(PacketType::DomainServerPathResponse);
|
||||
const char* startPosition = packet.data() + numHeaderBytes;
|
||||
const char* currentPosition = startPosition;
|
||||
|
||||
// figure out how many bytes the path query is
|
||||
qint16 numPathBytes;
|
||||
memcpy(&numPathBytes, currentPosition, sizeof(numPathBytes));
|
||||
currentPosition += sizeof(numPathBytes);
|
||||
packet->readPrimitive(&numPathBytes);
|
||||
|
||||
// make sure it is safe to pull the path
|
||||
if (numPathBytes <= packet.size() - numHeaderBytes - (currentPosition - startPosition)) {
|
||||
// pull the path from the packet
|
||||
QString pathQuery = QString::fromUtf8(currentPosition, numPathBytes);
|
||||
currentPosition += numPathBytes;
|
||||
// pull the path from the packet
|
||||
QString pathQuery = QString::fromUtf8(packet->read(numPathBytes));
|
||||
|
||||
// figure out how many bytes the viewpoint is
|
||||
qint16 numViewpointBytes;
|
||||
memcpy(&numViewpointBytes, currentPosition, sizeof(numViewpointBytes));
|
||||
currentPosition += sizeof(numViewpointBytes);
|
||||
// figure out how many bytes the viewpoint is
|
||||
qint16 numViewpointBytes;
|
||||
packet->readPrimitive(&numViewpointBytes);
|
||||
|
||||
// make sure it is safe to pull the viewpoint
|
||||
if (numViewpointBytes <= packet.size() - numHeaderBytes - (currentPosition - startPosition)) {
|
||||
// pull the viewpoint from the packet
|
||||
QString viewpoint = QString::fromUtf8(currentPosition, numViewpointBytes);
|
||||
// pull the viewpoint from the packet
|
||||
auto stringData = packet->read(numViewpointBytes);
|
||||
if (stringData.size() == numViewpointBytes) {
|
||||
QString viewpoint = QString::fromUtf8(stringData);
|
||||
|
||||
// Hand it off to the AddressManager so it can handle it as a relative viewpoint
|
||||
if (DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pathQuery)) {
|
||||
qCDebug(networking) << "Going to viewpoint" << viewpoint << "which was the lookup result for path" << pathQuery;
|
||||
} else {
|
||||
qCDebug(networking) << "Could not go to viewpoint" << viewpoint
|
||||
<< "which was the lookup result for path" << pathQuery;
|
||||
}
|
||||
// Hand it off to the AddressManager so it can handle it as a relative viewpoint
|
||||
if (DependencyManager::get<AddressManager>()->goToViewpointForPath(viewpoint, pathQuery)) {
|
||||
qCDebug(networking) << "Going to viewpoint" << viewpoint << "which was the lookup result for path" << pathQuery;
|
||||
} else {
|
||||
qCDebug(networking) << "Could not go to viewpoint" << viewpoint
|
||||
<< "which was the lookup result for path" << pathQuery;
|
||||
}
|
||||
} else {
|
||||
qCDebug(networking) << "Error loading viewpoint from path query response";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,49 +442,51 @@ void NodeList::pingPunchForDomainServer() {
|
|||
}
|
||||
}
|
||||
|
||||
int NodeList::processDomainServerList(const QByteArray& packet) {
|
||||
void NodeList::processDomainServerList(QSharedPointer<NLPacket> packet) {
|
||||
if (_domainHandler.getSockAddr().isNull()) {
|
||||
// refuse to process this packet if we aren't currently connected to the DS
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a packet from the domain server, reset the count of un-replied check-ins
|
||||
_numNoReplyDomainCheckIns = 0;
|
||||
|
||||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList);
|
||||
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
// grab the domain's ID from the beginning of the packet
|
||||
QUuid domainUUID;
|
||||
packetStream >> domainUUID;
|
||||
|
||||
// if this was the first domain-server list from this domain, we've now connected
|
||||
if (!_domainHandler.isConnected()) {
|
||||
_domainHandler.setUUID(uuidFromPacketHeader(packet));
|
||||
_domainHandler.setUUID(domainUUID);
|
||||
_domainHandler.setIsConnected(true);
|
||||
}
|
||||
|
||||
int readNodes = 0;
|
||||
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
|
||||
// pull our owner UUID from the packet, it's always the first thing
|
||||
QUuid newUUID;
|
||||
packetStream >> newUUID;
|
||||
setSessionUUID(newUUID);
|
||||
|
||||
// TODO: when fixing this read these are actually chars now, not bools
|
||||
bool thisNodeCanAdjustLocks;
|
||||
quint8 thisNodeCanAdjustLocks;
|
||||
packetStream >> thisNodeCanAdjustLocks;
|
||||
setThisNodeCanAdjustLocks(thisNodeCanAdjustLocks);
|
||||
setThisNodeCanAdjustLocks((bool) thisNodeCanAdjustLocks);
|
||||
|
||||
bool thisNodeCanRez;
|
||||
quint8 thisNodeCanRez;
|
||||
packetStream >> thisNodeCanRez;
|
||||
setThisNodeCanRez(thisNodeCanRez);
|
||||
setThisNodeCanRez((bool) thisNodeCanRez);
|
||||
|
||||
// pull each node in the packet
|
||||
while (packetStream.device()->pos() < packet.size()) {
|
||||
while (packetStream.device()->pos() < packet->getSizeUsed()) {
|
||||
parseNodeFromPacketStream(packetStream);
|
||||
}
|
||||
|
||||
return readNodes;
|
||||
}
|
||||
|
||||
void NodeList::processDomainServerAddedNode(const QByteArray& packet) {
|
||||
// setup a QDataStream, skip the header
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
void NodeList::processDomainServerAddedNode(QSharedPointer<NLPacket> packet) {
|
||||
// setup a QDataStream
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
// use our shared method to pull out the new node
|
||||
parseNodeFromPacketStream(packetStream);
|
||||
|
@ -646,10 +580,9 @@ void NodeList::handleNodePingTimeout() {
|
|||
}
|
||||
}
|
||||
|
||||
void NodeList::activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode) {
|
||||
void NodeList::activateSocketFromNodeCommunication(QSharedPointer<NLPacket> packet, const SharedNodePointer& sendingNode) {
|
||||
// deconstruct this ping packet to see if it is a public or local reply
|
||||
QDataStream packetStream(packet);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||
QDataStream packetStream(packet.data());
|
||||
|
||||
quint8 pingType;
|
||||
packetStream >> pingType;
|
||||
|
|
|
@ -38,6 +38,7 @@ const quint64 DOMAIN_SERVER_CHECK_IN_MSECS = 1 * 1000;
|
|||
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
||||
|
||||
using NodePacketPair = std::pair<SharedNodePointer, std::unique_ptr<NLPacket>>;
|
||||
using NodeSharedPacketPair = std::pair<SharedNodePointer, QSharedPointer<NLPacket>>;
|
||||
|
||||
class Application;
|
||||
class Assignment;
|
||||
|
@ -61,7 +62,7 @@ public:
|
|||
void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes);
|
||||
void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); }
|
||||
|
||||
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||
void processReceivedPacket(std::unique_ptr<NLPacket>, HifiSockAddr senderSockAddr);
|
||||
|
||||
void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; }
|
||||
void sendAssignment(Assignment& assignment);
|
||||
|
@ -70,6 +71,15 @@ public slots:
|
|||
void reset();
|
||||
void sendDomainServerCheckIn();
|
||||
void handleDSPathQuery(const QString& newPath);
|
||||
|
||||
void processDomainServerList(QSharedPointer<NLPacket> packet);
|
||||
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
|
||||
void processDomainServerPathQueryResponse(QSharedPointer<NLPacket> packet);
|
||||
|
||||
void processPingPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
void processPingReplyPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
void processICEPingPacket(QSharedPointer<NLPacket> packet);
|
||||
signals:
|
||||
void limitOfSilentDomainCheckInsReached();
|
||||
private slots:
|
||||
|
@ -88,15 +98,11 @@ private:
|
|||
|
||||
void processDomainServerAuthRequest(const QByteArray& packet);
|
||||
void requestAuthForDomainServer();
|
||||
void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode);
|
||||
|
||||
void handleDSPathQueryResponse(const QByteArray& packet);
|
||||
void activateSocketFromNodeCommunication(QSharedPointer<NLPacket> packet, const SharedNodePointer& sendingNode);
|
||||
void timePingReply(QSharedPointer<NLPacket> packet, const SharedNodePointer& sendingNode);
|
||||
|
||||
void sendDSPathQuery(const QString& newPath);
|
||||
|
||||
int processDomainServerList(const QByteArray& packet);
|
||||
void processDomainServerAddedNode(const QByteArray& packet);
|
||||
|
||||
void parseNodeFromPacketStream(QDataStream& packetStream);
|
||||
|
||||
void pingPunchForInactiveNode(const SharedNodePointer& node);
|
||||
|
@ -106,8 +112,6 @@ private:
|
|||
DomainHandler _domainHandler;
|
||||
int _numNoReplyDomainCheckIns;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
|
||||
friend class Application;
|
||||
};
|
||||
|
||||
#endif // hifi_NodeList_h
|
||||
|
|
18
libraries/networking/src/PacketListener.cpp
Normal file
18
libraries/networking/src/PacketListener.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// PacketListener.cpp
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 07/14/15.
|
||||
// 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 "PacketListener.h"
|
||||
|
||||
#include "NodeList.h"
|
||||
|
||||
PacketListener::~PacketListener() {
|
||||
DependencyManager::get<NodeList>()->getPacketReceiver().unregisterListener(this);
|
||||
}
|
22
libraries/networking/src/PacketListener.h
Normal file
22
libraries/networking/src/PacketListener.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// PacketListener.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 07/14/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_PacketListener_h
|
||||
#define hifi_PacketListener_h
|
||||
|
||||
#pragma once
|
||||
|
||||
class PacketListener {
|
||||
public:
|
||||
virtual ~PacketListener();
|
||||
};
|
||||
|
||||
#endif // hifi_PacketListener_h
|
272
libraries/networking/src/PacketReceiver.cpp
Normal file
272
libraries/networking/src/PacketReceiver.cpp
Normal file
|
@ -0,0 +1,272 @@
|
|||
//
|
||||
// PacketReceiver.cpp
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/23/2014.
|
||||
// Update by Ryan Huffman on 7/8/2015.
|
||||
// Copyright 2014 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 "PacketReceiver.h"
|
||||
|
||||
#include "DependencyManager.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include "NodeList.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
PacketReceiver::PacketReceiver(QObject* parent) :
|
||||
QObject(parent),
|
||||
_packetListenerMap()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PacketReceiver::registerListenerForTypes(const QSet<PacketType::Value>& types, PacketListener* listener, const char* slot) {
|
||||
QSet<PacketType::Value> nonSourcedTypes;
|
||||
QSet<PacketType::Value> sourcedTypes;
|
||||
|
||||
foreach(PacketType::Value type, types) {
|
||||
if (NON_SOURCED_PACKETS.contains(type)) {
|
||||
nonSourcedTypes << type;
|
||||
} else {
|
||||
sourcedTypes << type;
|
||||
}
|
||||
}
|
||||
|
||||
QObject* object = dynamic_cast<QObject*>(listener);
|
||||
Q_ASSERT(object);
|
||||
|
||||
if (nonSourcedTypes.size() > 0) {
|
||||
QMetaMethod nonSourcedMethod = matchingMethodForListener(*nonSourcedTypes.begin(), object, slot);
|
||||
foreach(PacketType::Value type, nonSourcedTypes) {
|
||||
registerVerifiedListener(type, object, nonSourcedMethod);
|
||||
}
|
||||
}
|
||||
|
||||
if (sourcedTypes.size() > 0) {
|
||||
QMetaMethod sourcedMethod = matchingMethodForListener(*sourcedTypes.begin(), object, slot);
|
||||
foreach(PacketType::Value type, sourcedTypes) {
|
||||
registerVerifiedListener(type, object, sourcedMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PacketReceiver::registerListener(PacketType::Value type, PacketListener* listener, const char* slot) {
|
||||
QObject* object = dynamic_cast<QObject*>(listener);
|
||||
Q_ASSERT(object);
|
||||
|
||||
QMetaMethod matchingMethod = matchingMethodForListener(type, object, slot);
|
||||
|
||||
if (matchingMethod.isValid()) {
|
||||
registerVerifiedListener(type, object, matchingMethod);
|
||||
}
|
||||
}
|
||||
|
||||
QMetaMethod PacketReceiver::matchingMethodForListener(PacketType::Value type, QObject* object, const char* slot) const {
|
||||
Q_ASSERT(object);
|
||||
|
||||
// normalize the slot with the expected parameters
|
||||
|
||||
const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer<NLPacket>";
|
||||
|
||||
QSet<QString> possibleSignatures { QString("%1(%2)").arg(slot).arg(NON_SOURCED_PACKET_LISTENER_PARAMETERS) };
|
||||
|
||||
if (!NON_SOURCED_PACKETS.contains(type)) {
|
||||
const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer<NLPacket>,QSharedPointer<Node>";
|
||||
|
||||
// a sourced packet must take the shared pointer to the packet but optionally could include
|
||||
// a shared pointer to the node
|
||||
|
||||
possibleSignatures << QString("%1(%2)").arg(slot).arg(SOURCED_PACKET_LISTENER_PARAMETERS);
|
||||
}
|
||||
|
||||
int methodIndex = -1;
|
||||
|
||||
foreach(const QString& signature, possibleSignatures) {
|
||||
QByteArray normalizedSlot =
|
||||
QMetaObject::normalizedSignature(signature.toStdString().c_str());
|
||||
|
||||
// does the constructed normalized method exist?
|
||||
methodIndex = object->metaObject()->indexOfSlot(normalizedSlot.toStdString().c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (methodIndex < 0) {
|
||||
qDebug() << "PacketReceiver::registerListener expected a method with one of the following signatures:"
|
||||
<< possibleSignatures << "- but such a method was not found.";
|
||||
}
|
||||
|
||||
Q_ASSERT(methodIndex >= 0);
|
||||
|
||||
// return the converted QMetaMethod
|
||||
if (methodIndex >= 0) {
|
||||
return object->metaObject()->method(methodIndex);
|
||||
} else {
|
||||
// if somehow (scripting?) something bad gets in here at runtime that doesn't hit the asserts above
|
||||
// return a non-valid QMetaMethod
|
||||
return QMetaMethod();
|
||||
}
|
||||
}
|
||||
|
||||
void PacketReceiver::registerVerifiedListener(PacketType::Value type, QObject* object, const QMetaMethod& slot) {
|
||||
_packetListenerLock.lock();
|
||||
|
||||
if (_packetListenerMap.contains(type)) {
|
||||
qDebug() << "Warning: Registering a packet listener for packet type " << type
|
||||
<< "that will remove a previously registered listener";
|
||||
}
|
||||
|
||||
// add the mapping
|
||||
_packetListenerMap[type] = ObjectMethodPair(object, slot);
|
||||
|
||||
_packetListenerLock.unlock();
|
||||
|
||||
}
|
||||
|
||||
void PacketReceiver::unregisterListener(PacketListener* listener) {
|
||||
_packetListenerLock.lock();
|
||||
|
||||
auto it = _packetListenerMap.begin();
|
||||
|
||||
while (it != _packetListenerMap.end()) {
|
||||
if (it.value().first == dynamic_cast<QObject*>(listener)) {
|
||||
// this listener matches - erase it
|
||||
it = _packetListenerMap.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
_packetListenerLock.unlock();
|
||||
}
|
||||
|
||||
bool PacketReceiver::packetVersionMatch(const NLPacket& packet) {
|
||||
|
||||
if (packet.getVersion() != versionForPacketType(packet.getType())
|
||||
&& packet.getType() != PacketType::StunResponse) {
|
||||
|
||||
static QMultiMap<QUuid, PacketType::Value> versionDebugSuppressMap;
|
||||
|
||||
const QUuid& senderID = packet.getSourceID();
|
||||
|
||||
if (!versionDebugSuppressMap.contains(senderID, packet.getType())) {
|
||||
|
||||
qCDebug(networking) << "Packet version mismatch on" << packet.getType() << "- Sender"
|
||||
<< senderID << "sent" << qPrintable(QString::number(packet.getVersion())) << "but"
|
||||
<< qPrintable(QString::number(versionForPacketType(packet.getType()))) << "expected.";
|
||||
|
||||
emit packetVersionMismatch(packet.getType());
|
||||
|
||||
versionDebugSuppressMap.insert(senderID, packet.getType());
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketReceiver::processDatagrams() {
|
||||
//PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
//"PacketReceiver::processDatagrams()");
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
// setup a buffer to read the packet into
|
||||
int packetSizeWithHeader = nodeList->getNodeSocket().pendingDatagramSize();
|
||||
std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[packetSizeWithHeader]);
|
||||
|
||||
// if we're supposed to drop this packet then break out here
|
||||
if (_shouldDropPackets) {
|
||||
break;
|
||||
}
|
||||
|
||||
// setup a HifiSockAddr to read into
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
// pull the datagram
|
||||
nodeList->getNodeSocket().readDatagram(buffer.get(), packetSizeWithHeader,
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
|
||||
// setup an NLPacket from the data we just read
|
||||
auto packet = NLPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
|
||||
_inPacketCount++;
|
||||
_inByteCount += packetSizeWithHeader;
|
||||
|
||||
if (packetVersionMatch(*packet)) {
|
||||
|
||||
SharedNodePointer matchingNode;
|
||||
if (nodeList->packetSourceAndHashMatch(*packet, matchingNode)) {
|
||||
|
||||
if (matchingNode) {
|
||||
// No matter if this packet is handled or not, we update the timestamp for the last time we heard
|
||||
// from this sending node
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
|
||||
_packetListenerLock.lock();
|
||||
|
||||
auto it = _packetListenerMap.find(packet->getType());
|
||||
|
||||
if (it != _packetListenerMap.end()) {
|
||||
|
||||
auto listener = it.value();
|
||||
|
||||
if (listener.first) {
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (matchingNode) {
|
||||
// if this was a sequence numbered packet we should store the last seq number for
|
||||
// a packet of this type for this node
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packet->getType())) {
|
||||
matchingNode->setLastSequenceNumberForPacketType(packet->readSequenceNumber(), packet->getType());
|
||||
}
|
||||
|
||||
emit dataReceived(matchingNode->getType(), packet->getSizeWithHeader());
|
||||
QMetaMethod metaMethod = listener.second;
|
||||
|
||||
static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer<Node>");
|
||||
|
||||
if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) {
|
||||
success = metaMethod.invoke(listener.first,
|
||||
Q_ARG(QSharedPointer<NLPacket>, QSharedPointer<NLPacket>(packet.release())),
|
||||
Q_ARG(SharedNodePointer, matchingNode));
|
||||
|
||||
} else {
|
||||
success = metaMethod.invoke(listener.first,
|
||||
Q_ARG(QSharedPointer<NLPacket>, QSharedPointer<NLPacket>(packet.release())));
|
||||
}
|
||||
} else {
|
||||
emit dataReceived(NodeType::Unassigned, packet->getSizeWithHeader());
|
||||
|
||||
success = listener.second.invoke(listener.first,
|
||||
Q_ARG(QSharedPointer<NLPacket>, QSharedPointer<NLPacket>(packet.release())));
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
qDebug() << "Error delivering packet " << nameForPacketType(packet->getType()) << " to listener: "
|
||||
<< listener.first->objectName() << "::" << listener.second.name();
|
||||
}
|
||||
|
||||
} else {
|
||||
// we have a dead listener - remove this mapping from the _packetListenerMap
|
||||
qDebug() << "Listener for packet type" << nameForPacketType(packet->getType())
|
||||
<< "has been destroyed - removing mapping.";
|
||||
_packetListenerMap.erase(it);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "No listener found for packet type " << nameForPacketType(packet->getType());
|
||||
}
|
||||
|
||||
_packetListenerLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
libraries/networking/src/PacketReceiver.h
Normal file
69
libraries/networking/src/PacketReceiver.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// PacketReceiver.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 1/23/2014.
|
||||
// Update by Ryan Huffman on 7/8/2015.
|
||||
// Copyright 2014 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_PacketReceiver_h
|
||||
#define hifi_PacketReceiver_h
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QMetaMethod>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSet>
|
||||
|
||||
#include "NLPacket.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
class PacketListener;
|
||||
|
||||
class PacketReceiver : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PacketReceiver(QObject* parent = 0);
|
||||
PacketReceiver(const PacketReceiver&) = delete;
|
||||
|
||||
PacketReceiver& operator=(const PacketReceiver&) = delete;
|
||||
|
||||
int getInPacketCount() const { return _inPacketCount; }
|
||||
int getInByteCount() const { return _inByteCount; }
|
||||
|
||||
void setShouldDropPackets(bool shouldDropPackets) { _shouldDropPackets = shouldDropPackets; }
|
||||
|
||||
void resetCounters() { _inPacketCount = 0; _inByteCount = 0; }
|
||||
|
||||
void registerListenerForTypes(const QSet<PacketType::Value>& types, PacketListener* listener, const char* slot);
|
||||
void registerListener(PacketType::Value type, PacketListener* listener, const char* slot);
|
||||
void unregisterListener(PacketListener* listener);
|
||||
|
||||
public slots:
|
||||
void processDatagrams();
|
||||
|
||||
signals:
|
||||
void dataSent(quint8 channelType, int bytes);
|
||||
void dataReceived(quint8 channelType, int bytes);
|
||||
void packetVersionMismatch(PacketType::Value type);
|
||||
|
||||
private:
|
||||
bool packetVersionMatch(const NLPacket& packet);
|
||||
|
||||
QMetaMethod matchingMethodForListener(PacketType::Value type, QObject* object, const char* slot) const;
|
||||
void registerVerifiedListener(PacketType::Value type, QObject* listener, const QMetaMethod& slot);
|
||||
|
||||
using ObjectMethodPair = std::pair<QObject*, QMetaMethod>;
|
||||
|
||||
QMutex _packetListenerLock;
|
||||
QHash<PacketType::Value, ObjectMethodPair> _packetListenerMap;
|
||||
int _inPacketCount = 0;
|
||||
int _inByteCount = 0;
|
||||
bool _shouldDropPackets = false;
|
||||
};
|
||||
|
||||
#endif // hifi_PacketReceiver_h
|
|
@ -24,15 +24,9 @@ void ReceivedPacketProcessor::terminating() {
|
|||
_hasPackets.wakeAll();
|
||||
}
|
||||
|
||||
void ReceivedPacketProcessor::queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
sendingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
// TODO: fix the NodePacketPair once we've figured out receive API
|
||||
NodePacketPair networkPacket(sendingNode, NLPacket::create(PacketType::OctreeStats));
|
||||
|
||||
void ReceivedPacketProcessor::queueReceivedPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
lock();
|
||||
_packets.push_back(std::move(networkPacket));
|
||||
_packets.push_back({ sendingNode, packet });
|
||||
_nodePacketCounts[sendingNode->getUUID()]++;
|
||||
_lastWindowIncomingPackets++;
|
||||
unlock();
|
||||
|
@ -73,13 +67,12 @@ bool ReceivedPacketProcessor::process() {
|
|||
}
|
||||
|
||||
lock();
|
||||
std::list<NodePacketPair> currentPackets;
|
||||
std::list<NodeSharedPacketPair> currentPackets;
|
||||
currentPackets.swap(_packets);
|
||||
unlock();
|
||||
|
||||
for(auto& packetPair : currentPackets) {
|
||||
// TODO: Replace QByteArray() once NLPacket is coming through on receive side
|
||||
processPacket(packetPair.first, QByteArray());
|
||||
processPacket(packetPair.second, packetPair.first);
|
||||
_lastWindowProcessedPackets++;
|
||||
midProcess();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
ReceivedPacketProcessor();
|
||||
|
||||
/// Add packet from network receive thread to the processing queue.
|
||||
void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
void queueReceivedPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
/// Are there received packets waiting to be processed
|
||||
bool hasPacketsToProcess() const { return _packets.size() > 0; }
|
||||
|
@ -58,7 +58,7 @@ protected:
|
|||
/// Callback for processing of recieved packets. Implement this to process the incoming packets.
|
||||
/// \param SharedNodePointer& sendingNode the node that sent this packet
|
||||
/// \param QByteArray& the packet to be processed
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) = 0;
|
||||
virtual void processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) = 0;
|
||||
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
@ -76,7 +76,7 @@ protected:
|
|||
virtual void postProcess() { }
|
||||
|
||||
protected:
|
||||
std::list<NodePacketPair> _packets;
|
||||
std::list<NodeSharedPacketPair> _packets;
|
||||
QHash<QUuid, int> _nodePacketCounts;
|
||||
|
||||
QWaitCondition _hasPackets;
|
||||
|
|
|
@ -13,8 +13,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <qbytearray.h>
|
||||
#include "RingBufferHistory.h"
|
||||
|
||||
#include "NLPacket.h"
|
||||
#include "RingBufferHistory.h"
|
||||
#include "SequenceNumberStats.h"
|
||||
|
||||
class NLPacket;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
#include "ThreadedAssignment.h"
|
||||
|
||||
ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) :
|
||||
ThreadedAssignment::ThreadedAssignment(NLPacket& packet) :
|
||||
Assignment(packet),
|
||||
_isFinished(false),
|
||||
_datagramProcessingThread(NULL)
|
||||
_isFinished(false)
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,14 @@ void ThreadedAssignment::setFinished(bool isFinished) {
|
|||
|
||||
qDebug() << "ThreadedAssignment::setFinished(true) called - finishing up.";
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
|
||||
// we should de-register immediately for any of our packets
|
||||
packetReceiver.unregisterListener(this);
|
||||
|
||||
// we should also tell the packet receiver to drop packets while we're cleaning up
|
||||
packetReceiver.setShouldDropPackets(true);
|
||||
|
||||
if (_domainServerTimer) {
|
||||
_domainServerTimer->stop();
|
||||
}
|
||||
|
@ -42,31 +50,9 @@ void ThreadedAssignment::setFinished(bool isFinished) {
|
|||
_statsTimer->stop();
|
||||
}
|
||||
|
||||
// stop processing datagrams from the node socket
|
||||
// this ensures we won't process a domain list while we are going down
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
disconnect(&nodeList->getNodeSocket(), 0, this, 0);
|
||||
|
||||
// call our virtual aboutToFinish method - this gives the ThreadedAssignment subclass a chance to cleanup
|
||||
aboutToFinish();
|
||||
|
||||
// if we have a datagram processing thread, quit it and wait on it to make sure that
|
||||
// the node socket is back on the same thread as the NodeList
|
||||
|
||||
|
||||
if (_datagramProcessingThread) {
|
||||
// tell the datagram processing thread to quit and wait until it is done,
|
||||
// then return the node socket to the NodeList
|
||||
_datagramProcessingThread->quit();
|
||||
_datagramProcessingThread->wait();
|
||||
|
||||
// set node socket parent back to NodeList
|
||||
nodeList->getNodeSocket().setParent(nodeList.data());
|
||||
}
|
||||
|
||||
// move the NodeList back to the QCoreApplication instance's thread
|
||||
nodeList->moveToThread(QCoreApplication::instance()->thread());
|
||||
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
@ -79,9 +65,6 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
nodeList->setOwnerType(nodeType);
|
||||
|
||||
// this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread
|
||||
nodeList->rebindNodeSocket();
|
||||
|
||||
_domainServerTimer = new QTimer();
|
||||
connect(_domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit()));
|
||||
_domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||
|
@ -120,16 +103,3 @@ void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
|||
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadedAssignment::readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||
destinationByteArray.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||
nodeList->getNodeSocket().readDatagram(destinationByteArray.data(), destinationByteArray.size(),
|
||||
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ThreadedAssignment.h
|
||||
// libraries/shared/src
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Stephen Birarda on 12/3/2013.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
|
@ -14,12 +14,14 @@
|
|||
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "PacketListener.h"
|
||||
|
||||
#include "Assignment.h"
|
||||
|
||||
class ThreadedAssignment : public Assignment {
|
||||
class ThreadedAssignment : public Assignment, public PacketListener {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ThreadedAssignment(const QByteArray& packet);
|
||||
ThreadedAssignment(NLPacket& packet);
|
||||
~ThreadedAssignment() { stop(); }
|
||||
|
||||
void setFinished(bool isFinished);
|
||||
|
@ -30,17 +32,14 @@ public slots:
|
|||
/// threaded run of assignment
|
||||
virtual void run() = 0;
|
||||
Q_INVOKABLE virtual void stop() { setFinished(true); }
|
||||
virtual void readPendingDatagrams() = 0;
|
||||
virtual void sendStatsPacket();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr);
|
||||
void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true);
|
||||
bool _isFinished;
|
||||
QThread* _datagramProcessingThread;
|
||||
QTimer* _domainServerTimer = nullptr;
|
||||
QTimer* _statsTimer = nullptr;
|
||||
|
||||
|
|
|
@ -25,6 +25,14 @@ std::unique_ptr<Packet> Packet::create(PacketType::Value type, qint64 size) {
|
|||
return std::unique_ptr<Packet>(new Packet(type, size));
|
||||
}
|
||||
|
||||
std::unique_ptr<Packet> Packet::fromReceivedPacket(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr) {
|
||||
// Fail with invalid size
|
||||
Q_ASSERT(size >= 0);
|
||||
|
||||
// allocate memory
|
||||
return std::unique_ptr<Packet>(new Packet(std::move(data), size, senderSockAddr));
|
||||
}
|
||||
|
||||
std::unique_ptr<Packet> Packet::createCopy(const Packet& other) {
|
||||
return std::unique_ptr<Packet>(new Packet(other));
|
||||
}
|
||||
|
@ -39,6 +47,7 @@ qint64 Packet::localHeaderSize() const {
|
|||
|
||||
Packet::Packet(PacketType::Value type, qint64 size) :
|
||||
_type(type),
|
||||
_version(0),
|
||||
_packetSize(localHeaderSize(_type) + size),
|
||||
_packet(new char(_packetSize)),
|
||||
_payloadStart(_packet.get() + localHeaderSize(_type)),
|
||||
|
@ -62,6 +71,18 @@ Packet::Packet(PacketType::Value type, qint64 size) :
|
|||
}
|
||||
}
|
||||
|
||||
Packet::Packet(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr) :
|
||||
_packetSize(size),
|
||||
_packet(std::move(data)),
|
||||
_senderSockAddr(senderSockAddr)
|
||||
{
|
||||
_type = readType();
|
||||
_version = readVersion();
|
||||
_capacity = _packetSize - localHeaderSize(_type);
|
||||
_sizeUsed = _capacity;
|
||||
_payloadStart = _packet.get() + (_packetSize - _capacity);
|
||||
}
|
||||
|
||||
Packet::Packet(const Packet& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <QIODevice>
|
||||
|
||||
#include "HifiSockAddr.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
class Packet : public QIODevice {
|
||||
|
@ -24,6 +25,8 @@ public:
|
|||
using SequenceNumber = uint16_t;
|
||||
|
||||
static std::unique_ptr<Packet> create(PacketType::Value type, qint64 size = -1);
|
||||
static std::unique_ptr<Packet> fromReceivedPacket(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
||||
|
||||
// Provided for convenience, try to limit use
|
||||
static std::unique_ptr<Packet> createCopy(const Packet& other);
|
||||
|
||||
|
@ -43,14 +46,16 @@ public:
|
|||
|
||||
PacketType::Value getType() const { return _type; }
|
||||
void setType(PacketType::Value type);
|
||||
|
||||
|
||||
PacketVersion getVersion() const { return _version; }
|
||||
|
||||
qint64 getSizeWithHeader() const { return localHeaderSize() + getSizeUsed(); }
|
||||
qint64 getSizeUsed() const { return _sizeUsed; }
|
||||
void setSizeUsed(qint64 sizeUsed) { _sizeUsed = sizeUsed; }
|
||||
|
||||
// Header readers
|
||||
PacketType::Value readType() const;
|
||||
PacketVersion readVersion() const;
|
||||
HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; }
|
||||
const HifiSockAddr& getSenderSockAddr() const { return _senderSockAddr; }
|
||||
|
||||
SequenceNumber readSequenceNumber() const;
|
||||
bool readIsControlPacket() const;
|
||||
|
||||
|
@ -60,16 +65,22 @@ public:
|
|||
virtual bool reset() { setSizeUsed(0); return QIODevice::reset(); }
|
||||
virtual qint64 size() const { return _capacity; }
|
||||
|
||||
template<typename T> qint64 peekPrimitive(T* data);
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
template<typename T> qint64 writePrimitive(const T& data);
|
||||
|
||||
protected:
|
||||
Packet(PacketType::Value type, int64_t size);
|
||||
Packet(std::unique_ptr<char> data, qint64 size, const HifiSockAddr& senderSockAddr);
|
||||
Packet(const Packet& other);
|
||||
Packet& operator=(const Packet& other);
|
||||
Packet(Packet&& other);
|
||||
Packet& operator=(Packet&& other);
|
||||
|
||||
// Header readers
|
||||
PacketType::Value readType() const;
|
||||
PacketVersion readVersion() const;
|
||||
|
||||
// QIODevice virtual functions
|
||||
virtual qint64 writeData(const char* data, qint64 maxSize);
|
||||
virtual qint64 readData(char* data, qint64 maxSize);
|
||||
|
@ -79,6 +90,7 @@ protected:
|
|||
void writeSequenceNumber(SequenceNumber seqNum);
|
||||
|
||||
PacketType::Value _type; // Packet type
|
||||
PacketVersion _version; // Packet version
|
||||
|
||||
qint64 _packetSize = 0; // Total size of the allocated memory
|
||||
std::unique_ptr<char> _packet; // Allocated memory
|
||||
|
@ -87,9 +99,15 @@ protected:
|
|||
qint64 _capacity = 0; // Total capacity of the payload
|
||||
|
||||
qint64 _sizeUsed = 0; // How much of the payload is actually used
|
||||
|
||||
HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end)
|
||||
};
|
||||
|
||||
|
||||
template<typename T> qint64 Packet::peekPrimitive(T* data) {
|
||||
return QIODevice::peek(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T> qint64 Packet::readPrimitive(T* data) {
|
||||
return QIODevice::read(reinterpret_cast<char*>(data), sizeof(T));
|
||||
}
|
||||
|
|
|
@ -18,21 +18,23 @@
|
|||
using namespace PacketType;
|
||||
|
||||
const QSet<PacketType::Value> NON_VERIFIED_PACKETS = QSet<PacketType::Value>()
|
||||
<< DomainServerRequireDTLS << DomainConnectRequest
|
||||
<< DomainList << DomainListRequest << DomainConnectionDenied
|
||||
<< CreateAssignment << RequestAssignment << StunResponse
|
||||
<< NodeJsonStats << EntityQuery
|
||||
<< OctreeDataNack << EntityEditNack
|
||||
<< DomainListRequest
|
||||
<< Ping
|
||||
<< PingReply << StopNode
|
||||
<< DomainServerPathQuery << DomainServerPathResponse
|
||||
<< DomainServerAddedNode;
|
||||
<< PingReply << StopNode;
|
||||
|
||||
const QSet<PacketType::Value> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType::Value>() << AvatarData;
|
||||
|
||||
const QSet<PacketType::Value> NON_SOURCED_PACKETS = QSet<PacketType::Value>()
|
||||
<< DomainServerRequireDTLS << DomainConnectRequest
|
||||
<< DomainList << DomainConnectionDenied
|
||||
<< DomainServerPathQuery << DomainServerPathResponse
|
||||
<< DomainServerAddedNode
|
||||
<< ICEServerPeerInformation << ICEServerQuery << ICEServerHeartbeat
|
||||
<< ICEPing << ICEPingReply << DomainConnectRequest;
|
||||
<< ICEPing << ICEPingReply
|
||||
<< AssignmentClientStatus;
|
||||
|
||||
int arithmeticCodingValueFromBuffer(const char* checkValue) {
|
||||
if (((uchar) *checkValue) < 255) {
|
||||
|
@ -208,15 +210,6 @@ int sequenceNumberOffsetForPacketType(PacketType::Value packetType) {
|
|||
return numBytesForPacketHeaderGivenPacketType(packetType) - sizeof(PacketSequenceNumber);
|
||||
}
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet) {
|
||||
return packet.mid(hashOffsetForPacketType(packetTypeForPacket(packet)), NUM_BYTES_MD5_HASH);
|
||||
}
|
||||
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID) {
|
||||
return QCryptographicHash::hash(packet.mid(numBytesForPacketHeader(packet)) + connectionUUID.toRfc4122(),
|
||||
QCryptographicHash::Md5);
|
||||
}
|
||||
|
||||
PacketSequenceNumber sequenceNumberFromHeader(const QByteArray& packet, PacketType::Value packetType) {
|
||||
if (packetType == PacketType::Unknown) {
|
||||
packetType = packetTypeForPacket(packet);
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace PacketType {
|
|||
OctreeStats,
|
||||
Jurisdiction,
|
||||
JurisdictionRequest,
|
||||
UNUSED_6,
|
||||
AssignmentClientStatus,
|
||||
UNUSED_7, // 30
|
||||
UNUSED_8,
|
||||
UNUSED_9,
|
||||
|
@ -122,9 +122,6 @@ QUuid uuidFromPacketHeader(const QByteArray& packet);
|
|||
int hashOffsetForPacketType(PacketType::Value packetType);
|
||||
int sequenceNumberOffsetForPacketType(PacketType::Value packetType);
|
||||
|
||||
QByteArray hashFromPacketHeader(const QByteArray& packet);
|
||||
QByteArray hashForPacketAndConnectionUUID(const QByteArray& packet, const QUuid& connectionUUID);
|
||||
|
||||
// NOTE: The following four methods accept a PacketType::Value which defaults to PacketType::Unknown.
|
||||
// If the caller has already looked at the packet type and can provide it then the methods below won't have to look it up.
|
||||
|
||||
|
|
|
@ -56,12 +56,11 @@ bool JurisdictionListener::queueJurisdictionRequest() {
|
|||
return isStillRunning();
|
||||
}
|
||||
|
||||
void JurisdictionListener::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
if (packetTypeForPacket(packet) == PacketType::Jurisdiction && sendingNode) {
|
||||
QUuid nodeUUID = sendingNode->getUUID();
|
||||
void JurisdictionListener::processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
if (packet->getType() == PacketType::Jurisdiction) {
|
||||
JurisdictionMap map;
|
||||
map.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
_jurisdictions[nodeUUID] = map;
|
||||
map.unpackFromPacket(*packet);
|
||||
_jurisdictions[packet->getSourceID()] = map;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public slots:
|
|||
protected:
|
||||
/// Callback for processing of received packets. Will process any queued PacketType::_JURISDICTION and update the
|
||||
/// jurisdiction map member variable
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
virtual void processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
NodeToJurisdictionMap _jurisdictions;
|
||||
|
|
|
@ -280,7 +280,7 @@ std::unique_ptr<NLPacket> JurisdictionMap::packEmptyJurisdictionIntoMessage(Node
|
|||
return std::move(packet); // includes header!
|
||||
}
|
||||
|
||||
std::unique_ptr<NLPacket> JurisdictionMap::packIntoMessage() {
|
||||
std::unique_ptr<NLPacket> JurisdictionMap::packIntoPacket() {
|
||||
auto packet = NLPacket::create(PacketType::Jurisdiction);
|
||||
|
||||
// Pack the Node Type in first byte
|
||||
|
@ -315,42 +315,28 @@ std::unique_ptr<NLPacket> JurisdictionMap::packIntoMessage() {
|
|||
return std::move(packet);
|
||||
}
|
||||
|
||||
int JurisdictionMap::unpackFromMessage(const unsigned char* sourceBuffer, int availableBytes) {
|
||||
int JurisdictionMap::unpackFromPacket(NLPacket& packet) {
|
||||
clear();
|
||||
const unsigned char* startPosition = sourceBuffer;
|
||||
|
||||
// increment to push past the packet header
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(reinterpret_cast<const char*>(sourceBuffer));
|
||||
sourceBuffer += numBytesPacketHeader;
|
||||
int remainingBytes = availableBytes - numBytesPacketHeader;
|
||||
|
||||
|
||||
// read the root jurisdiction
|
||||
int bytes = 0;
|
||||
memcpy(&bytes, sourceBuffer, sizeof(bytes));
|
||||
sourceBuffer += sizeof(bytes);
|
||||
remainingBytes -= sizeof(bytes);
|
||||
packet.readPrimitive(&bytes);
|
||||
|
||||
if (bytes > 0 && bytes <= remainingBytes) {
|
||||
if (bytes > 0 && bytes <= packet.bytesAvailable()) {
|
||||
_rootOctalCode = new unsigned char[bytes];
|
||||
memcpy(_rootOctalCode, sourceBuffer, bytes);
|
||||
sourceBuffer += bytes;
|
||||
remainingBytes -= bytes;
|
||||
packet.read(reinterpret_cast<char*>(_rootOctalCode), bytes);
|
||||
|
||||
// if and only if there's a root jurisdiction, also include the end nodes
|
||||
int endNodeCount = 0;
|
||||
memcpy(&endNodeCount, sourceBuffer, sizeof(endNodeCount));
|
||||
sourceBuffer += sizeof(endNodeCount);
|
||||
for (int i=0; i < endNodeCount; i++) {
|
||||
packet.readPrimitive(&endNodeCount);
|
||||
|
||||
for (int i = 0; i < endNodeCount; i++) {
|
||||
int bytes = 0;
|
||||
memcpy(&bytes, sourceBuffer, sizeof(bytes));
|
||||
sourceBuffer += sizeof(bytes);
|
||||
remainingBytes -= sizeof(bytes);
|
||||
packet.readPrimitive(&bytes);
|
||||
|
||||
if (bytes <= remainingBytes) {
|
||||
if (bytes <= packet.bytesAvailable()) {
|
||||
unsigned char* endNodeCode = new unsigned char[bytes];
|
||||
memcpy(endNodeCode, sourceBuffer, bytes);
|
||||
sourceBuffer += bytes;
|
||||
remainingBytes -= bytes;
|
||||
packet.read(reinterpret_cast<char*>(endNodeCode), bytes);
|
||||
|
||||
// if the endNodeCode was 0 length then don't add it
|
||||
if (bytes > 0) {
|
||||
|
@ -360,5 +346,5 @@ int JurisdictionMap::unpackFromMessage(const unsigned char* sourceBuffer, int av
|
|||
}
|
||||
}
|
||||
|
||||
return sourceBuffer - startPosition; // includes header!
|
||||
return packet.pos(); // excludes header
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ public:
|
|||
|
||||
void copyContents(unsigned char* rootCodeIn, const std::vector<unsigned char*>& endNodesIn);
|
||||
|
||||
int unpackFromMessage(const unsigned char* sourceBuffer, int availableBytes);
|
||||
std::unique_ptr<NLPacket> packIntoMessage();
|
||||
int unpackFromPacket(NLPacket& packet);
|
||||
std::unique_ptr<NLPacket> packIntoPacket();
|
||||
|
||||
/// Available to pack an empty or unknown jurisdiction into a network packet, used when no JurisdictionMap is available
|
||||
static std::unique_ptr<NLPacket> packEmptyJurisdictionIntoMessage(NodeType_t type);
|
||||
|
|
|
@ -28,13 +28,11 @@ JurisdictionSender::JurisdictionSender(JurisdictionMap* map, NodeType_t type) :
|
|||
JurisdictionSender::~JurisdictionSender() {
|
||||
}
|
||||
|
||||
void JurisdictionSender::processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet) {
|
||||
if (packetTypeForPacket(packet) == PacketType::JurisdictionRequest) {
|
||||
if (sendingNode) {
|
||||
lockRequestingNodes();
|
||||
_nodesRequestingJurisdictions.push(sendingNode->getUUID());
|
||||
unlockRequestingNodes();
|
||||
}
|
||||
void JurisdictionSender::processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode) {
|
||||
if (packet->getType() == PacketType::JurisdictionRequest) {
|
||||
lockRequestingNodes();
|
||||
_nodesRequestingJurisdictions.push(sendingNode->getUUID());
|
||||
unlockRequestingNodes();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +41,7 @@ bool JurisdictionSender::process() {
|
|||
|
||||
// call our ReceivedPacketProcessor base class process so we'll get any pending packets
|
||||
if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) {
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoMessage()
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||
int nodeCount = 0;
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
void setNodeType(NodeType_t type) { _nodeType = type; }
|
||||
|
||||
protected:
|
||||
virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet);
|
||||
virtual void processPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||
|
||||
/// Locks all the resources of the thread.
|
||||
void lockRequestingNodes() { _requestingNodeMutex.lock(); }
|
||||
|
|
|
@ -229,12 +229,12 @@ public:
|
|||
// own definition. Implement these to allow your octree based server to support editing
|
||||
virtual bool getWantSVOfileVersions() const { return false; }
|
||||
virtual PacketType::Value expectedDataPacketType() const { return PacketType::Unknown; }
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const {
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const {
|
||||
return thisVersion == versionForPacketType(expectedDataPacketType()); }
|
||||
virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); }
|
||||
virtual bool handlesEditPacketType(PacketType::Value packetType) const { return false; }
|
||||
virtual int processEditPacketData(PacketType::Value packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& sourceNode) { return 0; }
|
||||
virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& sourceNode) { return 0; }
|
||||
|
||||
virtual bool recurseChildrenWithData() const { return true; }
|
||||
virtual bool rootElementHasData() const { return false; }
|
||||
|
@ -304,16 +304,16 @@ public:
|
|||
} lockType;
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElement*& node, float& distance, BoxFace& face,
|
||||
OctreeElement*& node, float& distance, BoxFace& face,
|
||||
void** intersectedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
bool precisionPicking = false);
|
||||
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL,
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration,
|
||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
||||
/// \param cube query cube in world-frame (meters)
|
||||
|
@ -323,7 +323,7 @@ public:
|
|||
/// \param point query point in world-frame (meters)
|
||||
/// \param lockType how to lock the tree (Lock, TryLock, NoLock)
|
||||
/// \param[out] accurateResult pointer to output result, will be set "true" or "false" if non-null
|
||||
OctreeElement* getElementEnclosingPoint(const glm::vec3& point,
|
||||
OctreeElement* getElementEnclosingPoint(const glm::vec3& point,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
||||
// Note: this assumes the fileFormat is the HIO individual voxels code files
|
||||
|
@ -411,7 +411,7 @@ protected:
|
|||
|
||||
QReadWriteLock _lock;
|
||||
|
||||
bool _isViewing;
|
||||
bool _isViewing;
|
||||
bool _isServer;
|
||||
};
|
||||
|
||||
|
|
|
@ -225,10 +225,10 @@ void OctreeHeadlessViewer::queryOctree() {
|
|||
}
|
||||
|
||||
|
||||
int OctreeHeadlessViewer::parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sourceNode) {
|
||||
int OctreeHeadlessViewer::parseOctreeStats(QSharedPointer<NLPacket> packet, SharedNodePointer sourceNode) {
|
||||
|
||||
OctreeSceneStats temp;
|
||||
int statsMessageLength = temp.unpackFromMessage(reinterpret_cast<const unsigned char*>(packet.data()), packet.size());
|
||||
int statsMessageLength = temp.unpackFromPacket(*packet);
|
||||
|
||||
// TODO: actually do something with these stats, like expose them to JS...
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
|
||||
void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; }
|
||||
|
||||
static int parseOctreeStats(const QByteArray& packet, const SharedNodePointer& sourceNode);
|
||||
static int parseOctreeStats(QSharedPointer<NLPacket> packet, SharedNodePointer sourceNode);
|
||||
static void trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket);
|
||||
|
||||
public slots:
|
||||
|
|
|
@ -64,13 +64,10 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
}
|
||||
|
||||
// called on the other nodes - assigns it to my views of the others
|
||||
int OctreeQuery::parseData(const QByteArray& packet) {
|
||||
|
||||
// increment to push past the packet header
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packet);
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.data());
|
||||
const unsigned char* sourceBuffer = startPosition + numBytesPacketHeader;
|
||||
int OctreeQuery::parseData(NLPacket& packet) {
|
||||
|
||||
const unsigned char* startPosition = reinterpret_cast<const unsigned char*>(packet.getPayload());
|
||||
const unsigned char* sourceBuffer = startPosition;
|
||||
|
||||
// camera details
|
||||
memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue