remove 16-bit node IDs and replace with UUIDs

This commit is contained in:
Stephen Birarda 2013-10-17 11:49:41 -07:00
parent 6805b0e2c6
commit fa146e302d
45 changed files with 1295 additions and 610 deletions

View file

@ -39,6 +39,7 @@
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <StdDev.h>
#include <UUID.h>
#include "AudioRingBuffer.h"
@ -168,167 +169,166 @@ void AudioMixer::run() {
&& (otherNode != node || (otherNode == node && nodeRingBuffer->shouldLoopbackForNode()))) {
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) otherNode->getLinkedData();
// based on our listen mode we will do this mixing...
if (nodeRingBuffer->isListeningToNode(*otherNode)) {
float bearingRelativeAngleToSource = 0.0f;
float attenuationCoefficient = 1.0f;
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f;
float bearingRelativeAngleToSource = 0.0f;
float attenuationCoefficient = 1.0f;
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f;
stk::TwoPole* otherNodeTwoPole = NULL;
if (otherNode != node) {
stk::TwoPole* otherNodeTwoPole = NULL;
glm::vec3 listenerPosition = nodeRingBuffer->getPosition();
glm::vec3 relativePosition = otherNodeBuffer->getPosition() - nodeRingBuffer->getPosition();
glm::quat inverseOrientation = glm::inverse(nodeRingBuffer->getOrientation());
// only do axis/distance attenuation when in normal mode
if (otherNode != node && nodeRingBuffer->getListeningMode() == AudioRingBuffer::NORMAL) {
glm::vec3 listenerPosition = nodeRingBuffer->getPosition();
glm::vec3 relativePosition = otherNodeBuffer->getPosition() - nodeRingBuffer->getPosition();
glm::quat inverseOrientation = glm::inverse(nodeRingBuffer->getOrientation());
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
float radius = 0.0f;
if (otherNode->getType() == NODE_TYPE_AUDIO_INJECTOR) {
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherNodeBuffer;
radius = injectedBuffer->getRadius();
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
}
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
// this is either not a spherical source, or the listener is outside the sphere
if (radius > 0) {
// this is a spherical source - the distance used for the coefficient
// needs to be the closest point on the boundary to the source
// ovveride the distance to the node with the distance to the point on the
// boundary of the sphere
distanceSquareToSource -= (radius * radius);
} else {
// calculate the angle delivery for off-axis attenuation
glm::vec3 rotatedListenerPosition = glm::inverse(otherNodeBuffer->getOrientation())
* relativePosition;
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedListenerPosition));
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f));
// multiply the current attenuation coefficient by the calculated off axis coefficient
attenuationCoefficient *= offAxisCoefficient;
}
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
const float DISTANCE_SCALE = 2.5f;
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
const float DISTANCE_LOG_BASE = 2.5f;
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
// calculate the distance coefficient using the distance to this node
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
DISTANCE_SCALE_LOG +
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
distanceCoefficient = std::min(1.0f, distanceCoefficient);
// multiply the current attenuation coefficient by the distance coefficient
attenuationCoefficient *= distanceCoefficient;
// project the rotated source position vector onto the XZ plane
rotatedSourcePosition.y = 0.0f;
// produce an oriented angle about the y-axis
bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedSourcePosition),
glm::vec3(0.0f, 1.0f, 0.0f));
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
// figure out the number of samples of delay and the ratio of the amplitude
// in the weak channel for audio spatialization
float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource)));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
// grab the TwoPole object for this source, add it if it doesn't exist
TwoPoleNodeMap& nodeTwoPoles = nodeRingBuffer->getTwoPoles();
TwoPoleNodeMap::iterator twoPoleIterator = nodeTwoPoles.find(otherNode->getNodeID());
if (twoPoleIterator == nodeTwoPoles.end()) {
// setup the freeVerb effect for this source for this client
otherNodeTwoPole = nodeTwoPoles[otherNode->getNodeID()] = new stk::TwoPole;
} else {
otherNodeTwoPole = twoPoleIterator->second;
}
// calculate the reasonance for this TwoPole based on angle to source
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
otherNodeTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
TWO_POLE_MAX_FILTER_STRENGTH
* fabsf(bearingRelativeAngleToSource) / 180.0f,
true);
}
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
float radius = 0.0f;
if (otherNode->getType() == NODE_TYPE_AUDIO_INJECTOR) {
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherNodeBuffer;
radius = injectedBuffer->getRadius();
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
}
int16_t* sourceBuffer = otherNodeBuffer->getNextOutput();
int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f)
? clientSamples
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
int16_t* delayedChannel = (bearingRelativeAngleToSource > 0.0f)
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientSamples;
int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer()
? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
: otherNodeBuffer->getNextOutput() - numSamplesDelay;
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
// load up the stkFrameBuffer with this source's samples
stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s];
}
// perform the TwoPole effect on the stkFrameBuffer
if (otherNodeTwoPole) {
otherNodeTwoPole->tick(stkFrameBuffer);
}
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
if (s < numSamplesDelay) {
// pull the earlier sample for the delayed channel
int earlierSample = delaySamplePointer[s] * attenuationCoefficient * weakChannelAmplitudeRatio;
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
// this is either not a spherical source, or the listener is outside the sphere
if (radius > 0) {
// this is a spherical source - the distance used for the coefficient
// needs to be the closest point on the boundary to the source
delayedChannel[s] = glm::clamp(delayedChannel[s] + earlierSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
// ovveride the distance to the node with the distance to the point on the
// boundary of the sphere
distanceSquareToSource -= (radius * radius);
} else {
// calculate the angle delivery for off-axis attenuation
glm::vec3 rotatedListenerPosition = glm::inverse(otherNodeBuffer->getOrientation())
* relativePosition;
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedListenerPosition));
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f));
// multiply the current attenuation coefficient by the calculated off axis coefficient
attenuationCoefficient *= offAxisCoefficient;
}
int16_t currentSample = stkFrameBuffer[s] * attenuationCoefficient;
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
goodChannel[s] = glm::clamp(goodChannel[s] + currentSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
const float DISTANCE_SCALE = 2.5f;
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
const float DISTANCE_LOG_BASE = 2.5f;
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
int sumSample = delayedChannel[s + numSamplesDelay]
+ (currentSample * weakChannelAmplitudeRatio);
delayedChannel[s + numSamplesDelay] = glm::clamp(sumSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
// calculate the distance coefficient using the distance to this node
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
DISTANCE_SCALE_LOG +
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
distanceCoefficient = std::min(1.0f, distanceCoefficient);
// multiply the current attenuation coefficient by the distance coefficient
attenuationCoefficient *= distanceCoefficient;
// project the rotated source position vector onto the XZ plane
rotatedSourcePosition.y = 0.0f;
// produce an oriented angle about the y-axis
bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f),
glm::normalize(rotatedSourcePosition),
glm::vec3(0.0f, 1.0f, 0.0f));
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
// figure out the number of samples of delay and the ratio of the amplitude
// in the weak channel for audio spatialization
float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource)));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
// grab the TwoPole object for this source, add it if it doesn't exist
TwoPoleNodeMap& nodeTwoPoles = nodeRingBuffer->getTwoPoles();
TwoPoleNodeMap::iterator twoPoleIterator = nodeTwoPoles.find(otherNode->getUUID());
if (twoPoleIterator == nodeTwoPoles.end()) {
// setup the freeVerb effect for this source for this client
otherNodeTwoPole = nodeTwoPoles[otherNode->getUUID()] = new stk::TwoPole;
} else {
otherNodeTwoPole = twoPoleIterator->second;
}
if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) {
// this could be a delayed sample on the next pass
// so store the affected back in the ARB
otherNodeBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
}
// calculate the reasonance for this TwoPole based on angle to source
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
otherNodeTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
TWO_POLE_MAX_FILTER_STRENGTH
* fabsf(bearingRelativeAngleToSource) / 180.0f,
true);
}
}
int16_t* sourceBuffer = otherNodeBuffer->getNextOutput();
int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f)
? clientSamples
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
int16_t* delayedChannel = (bearingRelativeAngleToSource > 0.0f)
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientSamples;
int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer()
? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
: otherNodeBuffer->getNextOutput() - numSamplesDelay;
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
// load up the stkFrameBuffer with this source's samples
stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s];
}
// perform the TwoPole effect on the stkFrameBuffer
if (otherNodeTwoPole) {
otherNodeTwoPole->tick(stkFrameBuffer);
}
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
if (s < numSamplesDelay) {
// pull the earlier sample for the delayed channel
int earlierSample = delaySamplePointer[s] * attenuationCoefficient * weakChannelAmplitudeRatio;
delayedChannel[s] = glm::clamp(delayedChannel[s] + earlierSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
}
int16_t currentSample = stkFrameBuffer[s] * attenuationCoefficient;
goodChannel[s] = glm::clamp(goodChannel[s] + currentSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
int sumSample = delayedChannel[s + numSamplesDelay]
+ (currentSample * weakChannelAmplitudeRatio);
delayedChannel[s + numSamplesDelay] = glm::clamp(sumSample,
MIN_SAMPLE_VALUE,
MAX_SAMPLE_VALUE);
}
if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) {
// this could be a delayed sample on the next pass
// so store the affected back in the ARB
otherNodeBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
}
}
}
}
@ -357,13 +357,12 @@ void AudioMixer::run() {
packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO) {
unsigned char* currentBuffer = packetData + numBytesForPacketHeader(packetData);
uint16_t sourceID;
memcpy(&sourceID, currentBuffer, sizeof(sourceID));
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) currentBuffer, NUM_BYTES_RFC4122_UUID));
Node* avatarNode = nodeList->addOrUpdateNode(nodeAddress,
nodeAddress,
Node* avatarNode = nodeList->addOrUpdateNode(nodeUUID,
NODE_TYPE_AGENT,
sourceID);
nodeAddress,
nodeAddress);
nodeList->updateNodeWithData(nodeAddress, packetData, receivedBytes);
@ -372,30 +371,13 @@ void AudioMixer::run() {
avatarNode->setAlive(false);
}
} else if (packetData[0] == PACKET_TYPE_INJECT_AUDIO) {
Node* matchingInjector = NULL;
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
NUM_BYTES_RFC4122_UUID));
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getLinkedData()) {
InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) node->getLinkedData();
if (memcmp(ringBuffer->getStreamIdentifier(),
packetData + numBytesForPacketHeader(packetData),
STREAM_IDENTIFIER_NUM_BYTES) == 0) {
// this is the matching stream, assign to matchingInjector and stop looking
matchingInjector = &*node;
break;
}
}
}
if (!matchingInjector) {
matchingInjector = nodeList->addOrUpdateNode(NULL,
NULL,
NODE_TYPE_AUDIO_INJECTOR,
nodeList->getLastNodeID());
nodeList->increaseNodeID();
}
Node* matchingInjector = nodeList->addOrUpdateNode(nodeUUID,
NODE_TYPE_AUDIO_INJECTOR,
NULL,
NULL);
// give the new audio data to the matching injector node
nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes);

View file

@ -12,9 +12,11 @@
#include <Stk.h>
#include <TwoPole.h>
#include <QtCore/QUuid>
#include "PositionalAudioRingBuffer.h"
typedef std::map<uint16_t, stk::TwoPole*> TwoPoleNodeMap;
typedef std::map<QUuid, stk::TwoPole*> TwoPoleNodeMap;
class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
public:

View file

@ -14,6 +14,7 @@
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include "AvatarData.h"
@ -22,7 +23,9 @@
const char AVATAR_MIXER_LOGGING_NAME[] = "avatar-mixer";
unsigned char* addNodeToBroadcastPacket(unsigned char *currentPosition, Node *nodeToAdd) {
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
QByteArray rfcUUID = nodeToAdd->getUUID().toRfc4122();
memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size());
currentPosition += rfcUUID.size();
AvatarData *nodeData = (AvatarData *)nodeToAdd->getLinkedData();
currentPosition += nodeData->getBroadcastData(currentPosition);
@ -103,7 +106,7 @@ void AvatarMixer::run() {
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
uint16_t nodeID = 0;
QUuid nodeUUID;
Node* avatarNode = NULL;
timeval lastDomainServerCheckIn = {};
@ -124,11 +127,11 @@ void AvatarMixer::run() {
packetVersionMatch(packetData)) {
switch (packetData[0]) {
case PACKET_TYPE_HEAD_DATA:
// grab the node ID from the packet
unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
NUM_BYTES_RFC4122_UUID));
// add or update the node in our list
avatarNode = nodeList->addOrUpdateNode(&nodeAddress, &nodeAddress, NODE_TYPE_AGENT, nodeID);
avatarNode = nodeList->addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, &nodeAddress, &nodeAddress);
// parse positional data from an node
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
@ -137,12 +140,11 @@ void AvatarMixer::run() {
break;
case PACKET_TYPE_AVATAR_URLS:
case PACKET_TYPE_AVATAR_FACE_VIDEO:
// grab the node ID from the packet
unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
NUM_BYTES_RFC4122_UUID));
// let everyone else know about the update
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getActiveSocket() && node->getNodeID() != nodeID) {
if (node->getActiveSocket() && node->getUUID() != nodeUUID) {
nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
}
}

View file

@ -91,6 +91,8 @@ void childClient() {
nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket));
nodeList->setDomainPort(ntohs(senderSocket.sin_port));
nodeList->setOwnerUUID(deployedAssignment->getUUID());
qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str());
// run the deployed assignment

View file

@ -154,7 +154,7 @@ void DomainServer::civetwebUploadHandler(struct mg_connection *connection, const
}
void DomainServer::nodeAdded(Node* node) {
NodeList::getInstance()->increaseNodeID();
}
void DomainServer::nodeKilled(Node* node) {
@ -187,7 +187,11 @@ void DomainServer::nodeKilled(Node* node) {
unsigned char* DomainServer::addNodeToBroadcastPacket(unsigned char* currentPosition, Node* nodeToAdd) {
*currentPosition++ = nodeToAdd->getType();
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
QByteArray rfcUUID = nodeToAdd->getUUID().toRfc4122();
memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size());
currentPosition += rfcUUID.size();
currentPosition += packSocket(currentPosition, nodeToAdd->getPublicSocket());
currentPosition += packSocket(currentPosition, nodeToAdd->getLocalSocket());
@ -291,11 +295,8 @@ void DomainServer::prepopulateStaticAssignmentFile() {
_staticAssignmentFile.close();
}
Assignment* DomainServer::matchingStaticAssignmentForCheckIn(NODE_TYPE nodeType, const uchar* checkInData) {
Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NODE_TYPE nodeType) {
// pull the UUID passed with the check in
QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) checkInData + numBytesForPacketHeader(checkInData) +
sizeof(NODE_TYPE),
NUM_BYTES_RFC4122_UUID));
if (_hasCompletedRestartHold) {
_assignmentQueueMutex.lock();
@ -395,19 +396,14 @@ void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) {
bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket,
sockaddr* nodeLocalSocket,
const uchar* checkInData) {
// pull the UUID passed with the check in
QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) checkInData + numBytesForPacketHeader(checkInData) +
sizeof(NODE_TYPE),
NUM_BYTES_RFC4122_UUID));
const QUuid& checkInUUID) {
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getLinkedData()
&& socketMatch(node->getPublicSocket(), nodePublicSocket)
&& socketMatch(node->getLocalSocket(), nodeLocalSocket)
&& ((Assignment*) node->getLinkedData())->getUUID() == checkInUUID) {
&& node->getUUID() == checkInUUID) {
// this is a matching existing node if the public socket, local socket, and UUID match
return true;
}
@ -515,7 +511,9 @@ int DomainServer::run() {
nodeType = *(packetData + numBytesSenderHeader);
int packetIndex = numBytesSenderHeader + sizeof(NODE_TYPE) + NUM_BYTES_RFC4122_UUID;
int packetIndex = numBytesSenderHeader + sizeof(NODE_TYPE);
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray(((char*) packetData + packetIndex), NUM_BYTES_RFC4122_UUID));
packetIndex += NUM_BYTES_RFC4122_UUID;
int numBytesPrivateSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodePublicAddress);
packetIndex += numBytesPrivateSocket;
@ -531,16 +529,16 @@ int DomainServer::run() {
Assignment* matchingStaticAssignment = NULL;
if (memchr(STATICALLY_ASSIGNED_NODES, nodeType, sizeof(STATICALLY_ASSIGNED_NODES)) == NULL ||
((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeType, packetData)) ||
checkInWithUUIDMatchesExistingNode((sockaddr*) &nodePublicAddress,
(sockaddr*) &nodeLocalAddress,
packetData))) {
Node* checkInNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
(sockaddr*) &nodeLocalAddress,
if (memchr(STATICALLY_ASSIGNED_NODES, nodeType, sizeof(STATICALLY_ASSIGNED_NODES)) == NULL
|| ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|| checkInWithUUIDMatchesExistingNode((sockaddr*) &nodePublicAddress,
(sockaddr*) &nodeLocalAddress,
nodeUUID)))
{
Node* checkInNode = nodeList->addOrUpdateNode(nodeUUID,
nodeType,
nodeList->getLastNodeID());
(sockaddr*) &nodePublicAddress,
(sockaddr*) &nodeLocalAddress);
if (matchingStaticAssignment) {
// this was a newly added node with a matching static assignment
@ -584,9 +582,6 @@ int DomainServer::run() {
uint64_t timeNow = usecTimestampNow();
checkInNode->setLastHeardMicrostamp(timeNow);
// add the node ID to the end of the pointer
currentBufferPos += packNodeId(currentBufferPos, checkInNode->getNodeID());
// send the constructed list back to this node
nodeList->getNodeSocket()->send((sockaddr*)&senderAddress,
broadcastPacket,

View file

@ -42,10 +42,10 @@ private:
static DomainServer* domainServerInstance;
void prepopulateStaticAssignmentFile();
Assignment* matchingStaticAssignmentForCheckIn(NODE_TYPE nodeType, const uchar* checkInUUID);
Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NODE_TYPE nodeType);
Assignment* deployableAssignmentForRequest(Assignment& requestAssignment);
void removeAssignmentFromQueue(Assignment* removableAssignment);
bool checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, sockaddr* nodeLocalSocket, const uchar* checkInData);
bool checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, sockaddr* nodeLocalSocket, const QUuid& checkInUUI);
void possiblyAddStaticAssignmentsBackToQueueAfterRestart(timeval* startTime);
void cleanup();

View file

@ -54,7 +54,7 @@
#include <PacketHeaders.h>
#include <PairingHandler.h>
#include <PerfStat.h>
#include <UUID.h>
#include <VoxelSceneStats.h>
#include "Application.h"
@ -1160,8 +1160,9 @@ void Application::sendAvatarFaceVideoMessage(int frameCount, const QByteArray& d
packetPosition += populateTypeAndVersion(packetPosition, PACKET_TYPE_AVATAR_FACE_VIDEO);
*(uint16_t*)packetPosition = NodeList::getInstance()->getOwnerID();
packetPosition += sizeof(uint16_t);
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
memcpy(packetPosition, rfcUUID.constData(), rfcUUID.size());
packetPosition += rfcUUID.size();
*(uint32_t*)packetPosition = frameCount;
packetPosition += sizeof(uint32_t);
@ -1295,12 +1296,13 @@ static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& da
dataBytes -= numBytesPacketHeader;
// read the node id
uint16_t nodeID = *(uint16_t*)packetData;
packetData += sizeof(nodeID);
dataBytes -= sizeof(nodeID);
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData, NUM_BYTES_RFC4122_UUID));
packetData += NUM_BYTES_RFC4122_UUID;
dataBytes -= NUM_BYTES_RFC4122_UUID;
// make sure the node exists
Node* node = NodeList::getInstance()->nodeWithID(nodeID);
Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
if (!node || !node->getLinkedData()) {
return NULL;
}
@ -1560,29 +1562,6 @@ void Application::deleteVoxels() {
deleteVoxelUnderCursor();
}
void Application::setListenModeNormal() {
_audio.setListenMode(AudioRingBuffer::NORMAL);
}
void Application::setListenModePoint() {
_audio.setListenMode(AudioRingBuffer::OMNI_DIRECTIONAL_POINT);
_audio.setListenRadius(1.0);
}
void Application::setListenModeSingleSource() {
_audio.setListenMode(AudioRingBuffer::SELECTED_SOURCES);
_audio.clearListenSources();
glm::vec3 mouseRayOrigin = _myAvatar.getMouseRayOrigin();
glm::vec3 mouseRayDirection = _myAvatar.getMouseRayDirection();
glm::vec3 eyePositionIgnored;
uint16_t nodeID;
if (findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
_audio.addListenSource(nodeID);
}
}
void Application::initDisplay() {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
@ -1688,7 +1667,7 @@ const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
const float HEAD_SPHERE_RADIUS = 0.07;
static uint16_t DEFAULT_NODE_ID_REF = 1;
static QUuid DEFAULT_NODE_ID_REF;
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition) {
@ -1697,7 +1676,7 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons
}
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
@ -1710,7 +1689,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con
eyePosition = avatar->getHead().getEyePosition();
_lookatIndicatorScale = avatar->getHead().getScale();
_lookatOtherPosition = headPosition;
nodeID = avatar->getOwningNode()->getNodeID();
nodeUUID = avatar->getOwningNode()->getUUID();
return avatar;
}
}
@ -1759,12 +1738,12 @@ void Application::renderFollowIndicator() {
Avatar* avatar = (Avatar *) node->getLinkedData();
Avatar* leader = NULL;
if (avatar->getLeaderID() != UNKNOWN_NODE_ID) {
if (avatar->getLeaderID() == NodeList::getInstance()->getOwnerID()) {
if (!avatar->getLeaderUUID().isNull()) {
if (avatar->getLeaderUUID() == NodeList::getInstance()->getOwnerUUID()) {
leader = &_myAvatar;
} else {
for (NodeList::iterator it = nodeList->begin(); it != nodeList->end(); ++it) {
if(it->getNodeID() == avatar->getLeaderID()
if(it->getUUID() == avatar->getLeaderUUID()
&& it->getType() == NODE_TYPE_AGENT) {
leader = (Avatar*) it->getLinkedData();
}
@ -2244,26 +2223,27 @@ void Application::updateAvatar(float deltaTime) {
_myAvatar.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
NodeList* nodeList = NodeList::getInstance();
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID) {
// if I know my ID, send head/hand data to the avatar mixer and voxel server
unsigned char broadcastString[MAX_PACKET_SIZE];
unsigned char* endOfBroadcastStringWrite = broadcastString;
endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA);
endOfBroadcastStringWrite += packNodeId(endOfBroadcastStringWrite, nodeList->getOwnerID());
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
const char nodeTypesOfInterest[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AVATAR_MIXER };
controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString,
nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
// once in a while, send my urls
const float AVATAR_URLS_SEND_INTERVAL = 1.0f; // seconds
if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) {
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
}
// send head/hand data to the avatar mixer and voxel server
unsigned char broadcastString[MAX_PACKET_SIZE];
unsigned char* endOfBroadcastStringWrite = broadcastString;
endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA);
QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122();
memcpy(endOfBroadcastStringWrite, ownerUUID.constData(), ownerUUID.size());
endOfBroadcastStringWrite += ownerUUID.size();
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
const char nodeTypesOfInterest[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AVATAR_MIXER };
controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString,
nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
// once in a while, send my urls
const float AVATAR_URLS_SEND_INTERVAL = 1.0f; // seconds
if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) {
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
}
}
@ -3557,8 +3537,8 @@ void Application::toggleFollowMode() {
_pieMenu.getY() / (float)_glWidget->height(),
mouseRayOrigin, mouseRayDirection);
glm::vec3 eyePositionIgnored;
uint16_t nodeIDIgnored;
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeIDIgnored);
QUuid nodeUUIDIgnored;
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeUUIDIgnored);
_myAvatar.follow(leadingAvatar);
}
@ -3626,10 +3606,10 @@ void Application::nodeAdded(Node* node) {
void Application::nodeKilled(Node* node) {
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
uint16_t nodeID = node->getNodeID();
QUuid nodeUUID = node->getUUID();
// see if this is the first we've heard of this node...
if (_voxelServerJurisdictions.find(nodeID) != _voxelServerJurisdictions.end()) {
unsigned char* rootCode = _voxelServerJurisdictions[nodeID].getRootOctalCode();
if (_voxelServerJurisdictions.find(nodeUUID) != _voxelServerJurisdictions.end()) {
unsigned char* rootCode = _voxelServerJurisdictions[nodeUUID].getRootOctalCode();
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
@ -3659,13 +3639,13 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
// quick fix for crash... why would voxelServer be NULL?
if (voxelServer) {
uint16_t nodeID = voxelServer->getNodeID();
QUuid nodeUUID = voxelServer->getUUID();
VoxelPositionSize rootDetails;
voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), rootDetails);
// see if this is the first we've heard of this node...
if (_voxelServerJurisdictions.find(nodeID) == _voxelServerJurisdictions.end()) {
if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) {
printf("stats from new voxel server... v[%f, %f, %f, %f]\n",
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
@ -3682,7 +3662,7 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
// details from the VoxelSceneStats to construct the JurisdictionMap
JurisdictionMap jurisdictionMap;
jurisdictionMap.copyContents(_voxelSceneStats.getJurisdictionRoot(), _voxelSceneStats.getJurisdictionEndNodes());
_voxelServerJurisdictions[nodeID] = jurisdictionMap;
_voxelServerJurisdictions[nodeUUID] = jurisdictionMap;
}
return statsMessageLength;
}

View file

@ -171,9 +171,6 @@ public slots:
void doKillLocalVoxels();
void decreaseVoxelSize();
void increaseVoxelSize();
void setListenModeNormal();
void setListenModePoint();
void setListenModeSingleSource();
private slots:
@ -213,7 +210,7 @@ private:
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition);
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition, uint16_t& nodeID);
glm::vec3& eyePosition, QUuid &nodeUUID);
bool isLookingAtMyAvatar(Avatar* avatar);
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);

View file

@ -124,31 +124,10 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, packetType);
// pack Source Data
uint16_t ownerID = NodeList::getInstance()->getOwnerID();
memcpy(currentPacketPtr, &ownerID, sizeof(ownerID));
currentPacketPtr += (sizeof(ownerID));
leadingBytes += (sizeof(ownerID));
// pack Listen Mode Data
memcpy(currentPacketPtr, &_listenMode, sizeof(_listenMode));
currentPacketPtr += (sizeof(_listenMode));
leadingBytes += (sizeof(_listenMode));
if (_listenMode == AudioRingBuffer::OMNI_DIRECTIONAL_POINT) {
memcpy(currentPacketPtr, &_listenRadius, sizeof(_listenRadius));
currentPacketPtr += (sizeof(_listenRadius));
leadingBytes += (sizeof(_listenRadius));
} else if (_listenMode == AudioRingBuffer::SELECTED_SOURCES) {
int listenSourceCount = _listenSources.size();
memcpy(currentPacketPtr, &listenSourceCount, sizeof(listenSourceCount));
currentPacketPtr += (sizeof(listenSourceCount));
leadingBytes += (sizeof(listenSourceCount));
for (int i = 0; i < listenSourceCount; i++) {
memcpy(currentPacketPtr, &_listenSources[i], sizeof(_listenSources[i]));
currentPacketPtr += sizeof(_listenSources[i]);
leadingBytes += sizeof(_listenSources[i]);
}
}
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
memcpy(currentPacketPtr, rfcUUID.constData(), rfcUUID.size());
currentPacketPtr += rfcUUID.size();
leadingBytes += rfcUUID.size();
// memcpy the three float positions
memcpy(currentPacketPtr, &headPosition, sizeof(headPosition));
@ -347,24 +326,6 @@ void Audio::reset() {
_ringBuffer.reset();
}
void Audio::addListenSource(int sourceID) {
_listenSources.push_back(sourceID);
}
void Audio::clearListenSources() {
_listenSources.clear();
}
void Audio::removeListenSource(int sourceID) {
for (int i = 0; i < _listenSources.size(); i++) {
if (_listenSources[i] == sourceID) {
_listenSources.erase(_listenSources.begin() + i);
return;
}
}
}
Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
_stream(NULL),
_ringBuffer(true),
@ -395,9 +356,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
_collisionSoundDuration(0.0f),
_proceduralEffectSample(0),
_heartbeatMagnitude(0.0f),
_muted(false),
_listenMode(AudioRingBuffer::NORMAL),
_listenRadius(0.0f)
_muted(false)
{
outputPortAudioError(Pa_Initialize());

View file

@ -68,13 +68,6 @@ public:
// in which case 'true' is returned - otherwise the return value is 'false'.
// The results of the analysis are written to the log.
bool eventuallyAnalyzePing();
void setListenMode(AudioRingBuffer::ListenMode mode) { _listenMode = mode; }
void setListenRadius(float radius) { _listenRadius = radius; }
void addListenSource(int sourceID);
void removeListenSource(int sourceID);
void clearListenSources();
private:
PaStream* _stream;
@ -117,10 +110,6 @@ private:
GLuint _muteTextureId;
QRect _iconBounds;
AudioRingBuffer::ListenMode _listenMode;
float _listenRadius;
std::vector<int> _listenSources;
// Audio callback in class context.
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);

View file

@ -442,21 +442,6 @@ Menu::Menu() :
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
addActionToQMenuAndActionHash(audioDebugMenu,
MenuOption::ListenModeNormal,
Qt::CTRL | Qt::Key_1,
appInstance,
SLOT(setListenModeNormal()));
addActionToQMenuAndActionHash(audioDebugMenu,
MenuOption::ListenModePoint,
Qt::CTRL | Qt::Key_2,
appInstance,
SLOT(setListenModePoint()));
addActionToQMenuAndActionHash(audioDebugMenu,
MenuOption::ListenModeSingleSource,
Qt::CTRL | Qt::Key_3,
appInstance,
SLOT(setListenModeSingleSource()));
QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options");

View file

@ -176,9 +176,6 @@ namespace MenuOption {
const QString Gravity = "Use Gravity";
const QString GroundPlane = "Ground Plane";
const QString ParticleCloud = "Particle Cloud";
const QString ListenModeNormal = "Listen Mode Normal";
const QString ListenModePoint = "Listen Mode Point";
const QString ListenModeSingleSource = "Listen Mode Single Source";
const QString Log = "Log";
const QString Login = "Login";
const QString LookAtIndicator = "Look-at Indicator";

View file

@ -47,13 +47,11 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
int nodeID = voxelServer->getNodeID();
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
app->_environment.parseData(&senderAddress, packetData, messageLength);
} else {
app->_voxels.setDataSourceID(nodeID);
app->_voxels.parseData(packetData, messageLength);
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
app->_voxels.setDataSourceID(0);
}
}
}

View file

@ -82,7 +82,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
VoxelNode::addUpdateHook(this);
_abandonedVBOSlots = 0;
_falseColorizeBySource = false;
_dataSourceID = UNKNOWN_NODE_ID;
_dataSourceID = 0;
_voxelServerCount = 0;
_viewFrustum = Application::getInstance()->getViewFrustum();
@ -1442,7 +1442,7 @@ void VoxelSystem::falseColorizeBySource() {
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
uint16_t nodeID = node->getNodeID();
uint16_t nodeID = 0; // hardcoded since removal of 16 bit node IDs
int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;
args.colors[nodeID] = groupColors[groupColor];
@ -2299,8 +2299,7 @@ void VoxelSystem::falseColorizeOccludedV2() {
void VoxelSystem::nodeAdded(Node* node) {
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
uint16_t nodeID = node->getNodeID();
qDebug("VoxelSystem... voxel server %u added...\n", nodeID);
qDebug("VoxelSystem... voxel server %s added...\n", node->getUUID().toString().toLocal8Bit().constData());
_voxelServerCount++;
}
}
@ -2322,14 +2321,14 @@ bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) {
void VoxelSystem::nodeKilled(Node* node) {
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
_voxelServerCount--;
uint16_t nodeID = node->getNodeID();
qDebug("VoxelSystem... voxel server %u removed...\n", nodeID);
qDebug("VoxelSystem... voxel server %s removed...\n", node->getUUID().toString().toLocal8Bit().constData());
if (_voxelServerCount > 0) {
// Kill any voxels from the local tree that match this nodeID
pthread_mutex_lock(&_treeLock);
_tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeID);
pthread_mutex_unlock(&_treeLock);
// commenting out for removal of 16 bit node IDs
// pthread_mutex_lock(&_treeLock);
// _tree->recurseTreeWithOperation(killSourceVoxelsOperation, 0);
// pthread_mutex_unlock(&_treeLock);
_tree->setDirtyBit();
setupNewVoxelsForDrawing();
} else {

View file

@ -61,19 +61,13 @@ const float chatMessageScale = 0.0015;
const float chatMessageHeight = 0.20;
void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) {
uint16_t ownerID = NodeList::getInstance()->getOwnerID();
if (ownerID == UNKNOWN_NODE_ID) {
return; // we don't yet know who we are
}
QByteArray message;
char packetHeader[MAX_PACKET_HEADER_BYTES];
int numBytesPacketHeader = populateTypeAndVersion((unsigned char*) packetHeader, PACKET_TYPE_AVATAR_URLS);
message.append(packetHeader, numBytesPacketHeader);
message.append((const char*)&ownerID, sizeof(ownerID));
message.append(NodeList::getInstance()->getOwnerUUID().toRfc4122());
QDataStream out(&message, QIODevice::WriteOnly | QIODevice::Append);
out << voxelURL;
@ -283,13 +277,13 @@ void Avatar::follow(Avatar* leadingAvatar) {
_leadingAvatar = leadingAvatar;
if (_leadingAvatar != NULL) {
_leaderID = leadingAvatar->getOwningNode()->getNodeID();
_leaderUUID = leadingAvatar->getOwningNode()->getUUID();
_stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale;
if (_stringLength > MAX_STRING_LENGTH) {
_stringLength = MAX_STRING_LENGTH;
}
} else {
_leaderID = UNKNOWN_NODE_ID;
_leaderUUID = QUuid();
}
}

View file

@ -329,16 +329,7 @@ void Head::setScale (float scale) {
void Head::createMohawk() {
uint16_t nodeId = UNKNOWN_NODE_ID;
if (_owningAvatar->getOwningNode()) {
nodeId = _owningAvatar->getOwningNode()->getNodeID();
} else {
nodeId = NodeList::getInstance()->getOwnerID();
if (nodeId == UNKNOWN_NODE_ID) {
return;
}
}
srand(nodeId);
srand(time(NULL));
float height = _scale * (0.08f + randFloat() * 0.05f);
float variance = 0.03 + randFloat() * 0.03f;
const float RAD_PER_TRIANGLE = (2.3f + randFloat() * 0.2f) / (float)MOHAWK_TRIANGLES;

View file

@ -10,8 +10,10 @@
#include <fstream>
#include <limits>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include "AudioInjector.h"
@ -23,8 +25,6 @@ AudioInjector::AudioInjector(const char* filename) :
_indexOfNextSlot(0),
_isInjectingAudio(false)
{
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
std::fstream sourceFile;
sourceFile.open(filename, std::ios::in | std::ios::binary);
@ -53,8 +53,6 @@ AudioInjector::AudioInjector(int maxNumSamples) :
_indexOfNextSlot(0),
_isInjectingAudio(false)
{
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
_audioSampleArray = new int16_t[maxNumSamples];
memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t));
}
@ -71,7 +69,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
// calculate the number of bytes required for additional data
int leadingBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO)
+ sizeof(_streamIdentifier)
+ NUM_BYTES_RFC4122_UUID
+ sizeof(_position)
+ sizeof(_orientation)
+ sizeof(_radius)
@ -82,8 +80,9 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, PACKET_TYPE_INJECT_AUDIO);
// copy the identifier for this injector
memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier));
currentPacketPtr += sizeof(_streamIdentifier);
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
memcpy(currentPacketPtr, rfcUUID.constData(), rfcUUID.size());
currentPacketPtr += rfcUUID.size();
memcpy(currentPacketPtr, &_position, sizeof(_position));
currentPacketPtr += sizeof(_position);

View file

@ -19,8 +19,6 @@
#include "AudioRingBuffer.h"
const int STREAM_IDENTIFIER_NUM_BYTES = 8;
const int MAX_INJECTOR_VOLUME = 0xFF;
const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000);
@ -61,7 +59,6 @@ public slots:
int16_t& sampleAt(const int index);
void insertSample(const int index, int sample);
private:
unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES];
int16_t* _audioSampleArray;
int _numTotalSamples;
glm::vec3 _position;

View file

@ -14,8 +14,7 @@
InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
_radius(0.0f),
_attenuationRatio(0),
_streamIdentifier()
_attenuationRatio(0)
{
}
@ -23,10 +22,6 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
// pull stream identifier from the packet
memcpy(&_streamIdentifier, currentBuffer, sizeof(_streamIdentifier));
currentBuffer += sizeof(_streamIdentifier);
// use parsePositionalData in parent PostionalAudioRingBuffer class to pull common positional data
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));

View file

@ -21,7 +21,6 @@ public:
float getRadius() const { return _radius; }
float getAttenuationRatio() const { return _attenuationRatio; }
const unsigned char* getStreamIdentifier() const { return _streamIdentifier; }
private:
// disallow copying of InjectedAudioRingBuffer objects
InjectedAudioRingBuffer(const InjectedAudioRingBuffer&);
@ -29,7 +28,6 @@ private:
float _radius;
float _attenuationRatio;
unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES];
};
#endif /* defined(__hifi__InjectedAudioRingBuffer__) */

View file

@ -17,9 +17,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer() :
AudioRingBuffer(false),
_position(0.0f, 0.0f, 0.0f),
_orientation(0.0f, 0.0f, 0.0f, 0.0f),
_willBeAddedToMix(false),
_listenMode(AudioRingBuffer::NORMAL),
_listenRadius(0.0f)
_willBeAddedToMix(false)
{
}
@ -27,65 +25,15 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer() :
PositionalAudioRingBuffer::~PositionalAudioRingBuffer() {
}
bool PositionalAudioRingBuffer::isListeningToNode(Node& other) const {
switch (_listenMode) {
default:
case AudioRingBuffer::NORMAL:
return true;
break;
case AudioRingBuffer::OMNI_DIRECTIONAL_POINT: {
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) other.getLinkedData();
float distance = glm::distance(_position, otherNodeBuffer->_position);
return distance <= _listenRadius;
break;
}
case AudioRingBuffer::SELECTED_SOURCES:
for (int i = 0; i < _listenSources.size(); i++) {
if (other.getNodeID() == _listenSources[i]) {
return true;
}
}
return false;
break;
}
}
int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
currentBuffer += sizeof(uint16_t); // the source ID
currentBuffer += parseListenModeData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
return currentBuffer - sourceBuffer;
}
int PositionalAudioRingBuffer::parseListenModeData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer;
memcpy(&_listenMode, currentBuffer, sizeof(_listenMode));
currentBuffer += sizeof(_listenMode);
if (_listenMode == AudioRingBuffer::OMNI_DIRECTIONAL_POINT) {
memcpy(&_listenRadius, currentBuffer, sizeof(_listenRadius));
currentBuffer += sizeof(_listenRadius);
} else if (_listenMode == AudioRingBuffer::SELECTED_SOURCES) {
int listenSourcesCount;
memcpy(&listenSourcesCount, currentBuffer, sizeof(listenSourcesCount));
currentBuffer += sizeof(listenSourcesCount);
for (int i = 0; i < listenSourcesCount; i++) {
int sourceID;
memcpy(&sourceID, currentBuffer, sizeof(sourceID));
currentBuffer += sizeof(sourceID);
_listenSources.push_back(sourceID);
}
}
return currentBuffer - sourceBuffer;
}
int PositionalAudioRingBuffer::parsePositionalData(unsigned char* sourceBuffer, int numBytes) {
unsigned char* currentBuffer = sourceBuffer;

View file

@ -30,9 +30,6 @@ public:
const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; }
bool isListeningToNode(Node& other) const;
ListenMode getListeningMode() const { return _listenMode; }
protected:
// disallow copying of PositionalAudioRingBuffer objects
@ -42,10 +39,6 @@ protected:
glm::vec3 _position;
glm::quat _orientation;
bool _willBeAddedToMix;
ListenMode _listenMode;
float _listenRadius;
std::vector<int> _listenSources;
};
#endif /* defined(__hifi__PositionalAudioRingBuffer__) */

View file

@ -13,9 +13,10 @@
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include <UUID.h>
#include <VoxelConstants.h>
#include "AvatarData.h"
#include <VoxelConstants.h>
using namespace std;
@ -29,7 +30,7 @@ AvatarData::AvatarData(Node* owningNode) :
_bodyPitch(0.0),
_bodyRoll(0.0),
_newScale(1.0f),
_leaderID(UNKNOWN_NODE_ID),
_leaderUUID(),
_handState(0),
_cameraPosition(0,0,0),
_cameraOrientation(),
@ -61,7 +62,10 @@ void AvatarData::sendData() {
unsigned char* endOfPacket = packet;
endOfPacket += populateTypeAndVersion(endOfPacket, PACKET_TYPE_HEAD_DATA);
endOfPacket += packNodeId(endOfPacket, NodeList::getInstance()->getOwnerID());
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
memcpy(endOfPacket, rfcUUID.constData(), rfcUUID.size());
endOfPacket += rfcUUID.size();
int numPacketBytes = (endOfPacket - packet) + getBroadcastData(endOfPacket);
@ -103,8 +107,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _newScale);
// Follow mode info
memcpy(destinationBuffer, &_leaderID, sizeof(uint16_t));
destinationBuffer += sizeof(uint16_t);
memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
destinationBuffer += sizeof(NUM_BYTES_RFC4122_UUID);
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw);
@ -224,7 +228,6 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
sourceBuffer += sizeof(uint16_t);
// UUID
const int NUM_BYTES_RFC4122_UUID = 16;
_uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
sourceBuffer += NUM_BYTES_RFC4122_UUID;
@ -241,8 +244,8 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _newScale);
// Follow mode info
memcpy(&_leaderID, sourceBuffer, sizeof(uint16_t));
sourceBuffer += sizeof(uint16_t);
_leaderUUID = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
sourceBuffer += NUM_BYTES_RFC4122_UUID;
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
float headYaw, headPitch, headRoll;

View file

@ -120,7 +120,7 @@ public:
bool getWantDelta() const { return _wantDelta; }
bool getWantLowResMoving() const { return _wantLowResMoving; }
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
uint16_t getLeaderID() const { return _leaderID; }
const QUuid& getLeaderUUID() const { return _leaderUUID; }
void setHeadData(HeadData* headData) { _headData = headData; }
void setHandData(HandData* handData) { _handData = handData; }
@ -147,7 +147,7 @@ protected:
float _newScale;
// Following mode infos
uint16_t _leaderID;
QUuid _leaderUUID;
// Hand state (are we grabbing something or not)
char _handState;

View file

@ -0,0 +1,873 @@
//
// NodeList.cpp
// hifi
//
// Created by Stephen Birarda on 2/15/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <pthread.h>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <QtCore/QDebug>
#include <QtNetwork/QHostInfo>
#include "Assignment.h"
#include "Logging.h"
#include "NodeList.h"
#include "NodeTypes.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
#ifdef _WIN32
#include "Syssocket.h"
#else
#include <arpa/inet.h>
#endif
const char SOLO_NODE_TYPES[2] = {
NODE_TYPE_AVATAR_MIXER,
NODE_TYPE_AUDIO_MIXER
};
const QString DEFAULT_DOMAIN_HOSTNAME = "root.highfidelity.io";
const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102;
bool silentNodeThreadStopFlag = false;
bool pingUnknownNodeThreadStopFlag = false;
NodeList* NodeList::_sharedInstance = NULL;
NodeList* NodeList::createInstance(char ownerType, unsigned short int socketListenPort) {
if (!_sharedInstance) {
_sharedInstance = new NodeList(ownerType, socketListenPort);
} else {
qDebug("NodeList createInstance called with existing instance.");
}
return _sharedInstance;
}
NodeList* NodeList::getInstance() {
if (!_sharedInstance) {
qDebug("NodeList getInstance called before call to createInstance. Returning NULL pointer.");
}
return _sharedInstance;
}
NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
_domainHostname(DEFAULT_DOMAIN_HOSTNAME),
_domainIP(),
_domainPort(DEFAULT_DOMAIN_SERVER_PORT),
_nodeBuckets(),
_numNodes(0),
_nodeSocket(newSocketListenPort),
_ownerType(newOwnerType),
_nodeTypesOfInterest(NULL),
_ownerID(UNKNOWN_NODE_ID),
_lastNodeID(UNKNOWN_NODE_ID + 1),
_numNoReplyDomainCheckIns(0),
_assignmentServerSocket(NULL),
_checkInPacket(NULL),
_numBytesCheckInPacket(0),
_publicAddress(),
_publicPort(0)
{
}
NodeList::~NodeList() {
delete _nodeTypesOfInterest;
clear();
// stop the spawned threads, if they were started
stopSilentNodeRemovalThread();
}
void NodeList::setDomainHostname(const QString& domainHostname) {
if (domainHostname != _domainHostname) {
int colonIndex = domainHostname.indexOf(':');
if (colonIndex > 0) {
// the user has included a custom DS port with the hostname
// the new hostname is everything up to the colon
_domainHostname = domainHostname.left(colonIndex);
// grab the port by reading the string after the colon
_domainPort = atoi(domainHostname.mid(colonIndex + 1, domainHostname.size()).toLocal8Bit().constData());
qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainPort << "\n";
} else {
// no port included with the hostname, simply set the member variable and reset the domain server port to default
_domainHostname = domainHostname;
_domainPort = DEFAULT_DOMAIN_SERVER_PORT;
}
// clear the NodeList so nodes from this domain are killed
clear();
// reset our _domainIP to the null address so that a lookup happens on next check in
_domainIP.clear();
notifyDomainChanged();
}
}
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (socketMatch(node->getPublicSocket(), nodeAddress) ||
socketMatch(node->getLocalSocket(), nodeAddress)) {
int pingTime = usecTimestampNow() - *(uint64_t*)(packetData + numBytesForPacketHeader(packetData));
node->setPingMs(pingTime / 1000);
break;
}
}
}
void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetData, size_t dataBytes) {
switch (packetData[0]) {
case PACKET_TYPE_DOMAIN: {
// only process the DS if this is our current domain server
if (_domainIP == QHostAddress(senderAddress)) {
processDomainServerList(packetData, dataBytes);
}
break;
}
case PACKET_TYPE_PING: {
// send it right back
populateTypeAndVersion(packetData, PACKET_TYPE_PING_REPLY);
_nodeSocket.send(senderAddress, packetData, dataBytes);
break;
}
case PACKET_TYPE_PING_REPLY: {
// activate the appropriate socket for this node, if not yet updated
activateSocketFromPingReply(senderAddress);
// set the ping time for this node for stat collection
timePingReply(senderAddress, packetData);
break;
}
case PACKET_TYPE_STUN_RESPONSE: {
// 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(packetData, dataBytes);
break;
}
}
}
void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) {
// find the avatar mixer in our node list and update the lastRecvTime from it
Node* bulkSendNode = nodeWithAddress(senderAddress);
if (bulkSendNode) {
bulkSendNode->setLastHeardMicrostamp(usecTimestampNow());
bulkSendNode->recordBytesReceived(numTotalBytes);
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
unsigned char* startPosition = packetData;
unsigned char* currentPosition = startPosition + numBytesPacketHeader;
unsigned char packetHolder[numTotalBytes];
// we've already verified packet version for the bulk packet, so all head data in the packet is also up to date
populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA);
uint16_t nodeID = -1;
while ((currentPosition - startPosition) < numTotalBytes) {
unpackNodeId(currentPosition, &nodeID);
memcpy(packetHolder + numBytesPacketHeader,
currentPosition,
numTotalBytes - (currentPosition - startPosition));
Node* matchingNode = nodeWithID(nodeID);
if (!matchingNode) {
// we're missing this node, we need to add it to the list
matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID);
}
currentPosition += updateNodeWithData(matchingNode,
packetHolder,
numTotalBytes - (currentPosition - startPosition));
}
}
}
int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
// find the node by the sockaddr
Node* matchingNode = nodeWithAddress(senderAddress);
if (matchingNode) {
return updateNodeWithData(matchingNode, packetData, dataBytes);
} else {
return 0;
}
}
int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int dataBytes) {
node->lock();
node->setLastHeardMicrostamp(usecTimestampNow());
if (node->getActiveSocket()) {
node->recordBytesReceived(dataBytes);
}
if (!node->getLinkedData() && linkedDataCreateCallback) {
linkedDataCreateCallback(node);
}
int numParsedBytes = node->getLinkedData()->parseData(packetData, dataBytes);
node->unlock();
return numParsedBytes;
}
Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) {
return &(*node);
}
}
return NULL;
}
Node* NodeList::nodeWithUUID(uint16_t nodeID) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (node->getNodeID() == nodeID) {
return &(*node);
}
}
return NULL;
}
int NodeList::getNumAliveNodes() const {
int numAliveNodes = 0;
for (NodeList::iterator node = begin(); node != end(); node++) {
if (node->isAlive()) {
++numAliveNodes;
}
}
return numAliveNodes;
}
void NodeList::clear() {
qDebug() << "Clearing the NodeList. Deleting all nodes in list.\n";
// delete all of the nodes in the list, set the pointers back to NULL and the number of nodes to 0
for (int i = 0; i < _numNodes; i++) {
Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET];
Node* node = nodeBucket[i % NODES_PER_BUCKET];
node->lock();
delete node;
node = NULL;
}
_numNodes = 0;
}
void NodeList::reset() {
clear();
_numNoReplyDomainCheckIns = 0;
delete[] _checkInPacket;
_checkInPacket = NULL;
_numBytesCheckInPacket = 0;
delete _nodeTypesOfInterest;
_nodeTypesOfInterest = NULL;
}
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
delete _nodeTypesOfInterest;
_nodeTypesOfInterest = new char[numNodeTypesOfInterest + sizeof(char)];
memcpy(_nodeTypesOfInterest, nodeTypesOfInterest, numNodeTypesOfInterest);
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
}
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(0x2112A442);
const int NUM_BYTES_STUN_HEADER = 20;
void NodeList::sendSTUNRequest() {
const char STUN_SERVER_HOSTNAME[] = "root.highfidelity.io";
const unsigned short STUN_SERVER_PORT = 3478;
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
int packetIndex = 0;
// leading zeros + message type
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
// message length (no additional attributes are included)
uint16_t messageLength = 0;
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
packetIndex += sizeof(messageLength);
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
// transaction ID (random 12-byte unsigned integer)
const uint NUM_TRANSACTION_ID_BYTES = 12;
unsigned char transactionID[NUM_TRANSACTION_ID_BYTES];
loadRandomIdentifier(transactionID, NUM_TRANSACTION_ID_BYTES);
memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID));
// lookup the IP for the STUN server
static QHostInfo stunInfo = QHostInfo::fromName(STUN_SERVER_HOSTNAME);
for (int i = 0; i < stunInfo.addresses().size(); i++) {
if (stunInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
QString stunIPAddress = stunInfo.addresses()[i].toString();
qDebug("Sending a stun request to %s\n", stunIPAddress.toLocal8Bit().constData());
_nodeSocket.send(stunIPAddress.toLocal8Bit().constData(),
STUN_SERVER_PORT,
stunRequestPacket,
sizeof(stunRequestPacket));
break;
}
}
}
void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) {
// 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;
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
if (memcmp(packetData + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0
&& memcmp(packetData + NUM_BYTES_STUN_HEADER, &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;
int byteIndex = NUM_BYTES_STUN_HEADER + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
uint8_t addressFamily = 0;
memcpy(&addressFamily, packetData + byteIndex, sizeof(addressFamily));
byteIndex += sizeof(addressFamily);
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
// grab the X-Port
uint16_t xorMappedPort = 0;
memcpy(&xorMappedPort, packetData + byteIndex, sizeof(xorMappedPort));
_publicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
byteIndex += sizeof(xorMappedPort);
// grab the X-Address
uint32_t xorMappedAddress = 0;
memcpy(&xorMappedAddress, packetData + byteIndex, sizeof(xorMappedAddress));
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
_publicAddress = QHostAddress(stunAddress);
qDebug("Public socket received from STUN server is %s:%hu\n",
_publicAddress.toString().toLocal8Bit().constData(),
_publicPort);
}
}
}
void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
static bool printedDomainServerIP = false;
// Lookup the IP address of the domain server if we need to
if (_domainIP.isNull()) {
qDebug("Looking up DS hostname %s.\n", _domainHostname.toLocal8Bit().constData());
QHostInfo domainServerHostInfo = QHostInfo::fromName(_domainHostname);
for (int i = 0; i < domainServerHostInfo.addresses().size(); i++) {
if (domainServerHostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
_domainIP = domainServerHostInfo.addresses()[i];
qDebug("DS at %s is at %s\n", _domainHostname.toLocal8Bit().constData(),
_domainIP.toString().toLocal8Bit().constData());
printedDomainServerIP = true;
break;
}
// if we got here without a break out of the for loop then we failed to lookup the address
if (i == domainServerHostInfo.addresses().size() - 1) {
qDebug("Failed domain server lookup\n");
}
}
} else if (!printedDomainServerIP) {
qDebug("Domain Server IP: %s\n", _domainIP.toString().toLocal8Bit().constData());
printedDomainServerIP = true;
}
if (_publicAddress.isNull()) {
// we don't know our public socket and we need to send it to the domain server
// send a STUN request to figure it out
sendSTUNRequest();
} else {
// construct the DS check in packet if we need to
if (!_checkInPacket) {
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
const int IP_ADDRESS_BYTES = 4;
// check in packet has header, optional UUID, node type, port, IP, node types of interest, null termination
int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) +
NUM_BYTES_RFC4122_UUID + (2 * (sizeof(uint16_t) + IP_ADDRESS_BYTES)) +
numBytesNodesOfInterest + sizeof(unsigned char);
_checkInPacket = new unsigned char[numPacketBytes];
unsigned char* packetPosition = _checkInPacket;
PACKET_TYPE nodePacketType = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES)))
? PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
: PACKET_TYPE_DOMAIN_LIST_REQUEST;
packetPosition += populateTypeAndVersion(packetPosition, nodePacketType);
*(packetPosition++) = _ownerType;
if (!assignmentUUID) {
// if we don't have an assignment UUID just send the null one
assignmentUUID = QUuid().toRfc4122().constData();
}
// send our assignment UUID or the null one
memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID);
packetPosition += NUM_BYTES_RFC4122_UUID;
// pack our public address to send to domain-server
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
htonl(_publicAddress.toIPv4Address()), htons(_publicPort));
// pack our local address to send to domain-server
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
getLocalAddress(),
htons(_nodeSocket.getListeningPort()));
// add the number of bytes for node types of interest
*(packetPosition++) = numBytesNodesOfInterest;
// copy over the bytes for node types of interest, if required
if (numBytesNodesOfInterest > 0) {
memcpy(packetPosition,
_nodeTypesOfInterest,
numBytesNodesOfInterest);
packetPosition += numBytesNodesOfInterest;
}
_numBytesCheckInPacket = packetPosition - _checkInPacket;
}
_nodeSocket.send(_domainIP.toString().toLocal8Bit().constData(), _domainPort, _checkInPacket, _numBytesCheckInPacket);
// increment the count of un-replied check-ins
_numNoReplyDomainCheckIns++;
}
}
int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) {
// this is a packet from the domain server, reset the count of un-replied check-ins
_numNoReplyDomainCheckIns = 0;
int readNodes = 0;
char nodeType;
uint16_t nodeId;
// assumes only IPv4 addresses
sockaddr_in nodePublicSocket;
nodePublicSocket.sin_family = AF_INET;
sockaddr_in nodeLocalSocket;
nodeLocalSocket.sin_family = AF_INET;
unsigned char* readPtr = packetData + numBytesForPacketHeader(packetData);
unsigned char* startPtr = packetData;
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
nodeType = *readPtr++;
readPtr += unpackNodeId(readPtr, (uint16_t*) &nodeId);
readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket);
readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket);
// if the public socket address is 0 then it's reachable at the same IP
// as the domain server
if (nodePublicSocket.sin_addr.s_addr == 0) {
nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address());
}
addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
}
// read out our ID from the packet
unpackNodeId(readPtr, &_ownerID);
return readNodes;
}
const sockaddr_in DEFAULT_LOCAL_ASSIGNMENT_SOCKET = socketForHostnameAndHostOrderPort(LOCAL_ASSIGNMENT_SERVER_HOSTNAME,
DEFAULT_DOMAIN_SERVER_PORT);
void NodeList::sendAssignment(Assignment& assignment) {
unsigned char assignmentPacket[MAX_PACKET_SIZE];
PACKET_TYPE assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand
? PACKET_TYPE_CREATE_ASSIGNMENT
: PACKET_TYPE_REQUEST_ASSIGNMENT;
int numHeaderBytes = populateTypeAndVersion(assignmentPacket, assignmentPacketType);
int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes);
sockaddr* assignmentServerSocket = (_assignmentServerSocket == NULL)
? (sockaddr*) &DEFAULT_LOCAL_ASSIGNMENT_SOCKET
: _assignmentServerSocket;
_nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes);
}
void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const {
uint64_t currentTime = 0;
// setup a ping packet to send to this node
unsigned char pingPacket[numBytesForPacketHeader((uchar*) &PACKET_TYPE_PING) + sizeof(currentTime)];
int numHeaderBytes = populateTypeAndVersion(pingPacket, PACKET_TYPE_PING);
currentTime = usecTimestampNow();
memcpy(pingPacket + numHeaderBytes, &currentTime, sizeof(currentTime));
// send the ping packet to the local and public sockets for this node
_nodeSocket.send(node->getLocalSocket(), pingPacket, sizeof(pingPacket));
_nodeSocket.send(node->getPublicSocket(), pingPacket, sizeof(pingPacket));
}
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
NodeList::iterator node = end();
if (publicSocket) {
for (node = begin(); node != end(); node++) {
if (node->matches(publicSocket, localSocket, nodeType)) {
// we already have this node, stop checking
break;
}
}
}
if (node == end()) {
// we didn't have this node, so add them
Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
addNodeToList(newNode);
return newNode;
} else {
if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
node->getType() == NODE_TYPE_VOXEL_SERVER) {
// until the Audio class also uses our nodeList, we need to update
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
node->setLastHeardMicrostamp(usecTimestampNow());
}
// we had this node already, do nothing for now
return &*node;
}
}
void NodeList::addNodeToList(Node* newNode) {
// find the correct array to add this node to
int bucketIndex = _numNodes / NODES_PER_BUCKET;
if (!_nodeBuckets[bucketIndex]) {
_nodeBuckets[bucketIndex] = new Node*[NODES_PER_BUCKET]();
}
_nodeBuckets[bucketIndex][_numNodes % NODES_PER_BUCKET] = newNode;
++_numNodes;
qDebug() << "Added" << *newNode << "\n";
notifyHooksOfAddedNode(newNode);
}
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
unsigned n = 0;
for(NodeList::iterator node = begin(); node != end(); node++) {
// only send to the NodeTypes we are asked to send to.
if (node->getActiveSocket() != NULL) {
if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
// we know which socket is good for this node, send there
_nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
++n;
}
} else {
// we don't have an active link to this node, ping it to set that up
pingPublicAndLocalSocketsForInactiveNode(&(*node));
}
}
return n;
}
void NodeList::activateSocketFromPingReply(sockaddr *nodeAddress) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (!node->getActiveSocket()) {
// check both the public and local addresses for each node to see if we find a match
// prioritize the private address so that we prune erroneous local matches
if (socketMatch(node->getPublicSocket(), nodeAddress)) {
node->activatePublicSocket();
break;
} else if (socketMatch(node->getLocalSocket(), nodeAddress)) {
node->activateLocalSocket();
break;
}
}
}
}
Node* NodeList::soloNodeOfType(char nodeType) {
if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (node->getType() == nodeType) {
return &(*node);
}
}
}
return NULL;
}
void* removeSilentNodes(void *args) {
NodeList* nodeList = (NodeList*) args;
uint64_t checkTimeUsecs = 0;
int sleepTime = 0;
while (!silentNodeThreadStopFlag) {
checkTimeUsecs = usecTimestampNow();
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
node->lock();
if ((usecTimestampNow() - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) {
qDebug() << "Killed " << *node << "\n";
nodeList->notifyHooksOfKilledNode(&*node);
node->setAlive(false);
}
node->unlock();
}
sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUsecs);
#ifdef _WIN32
Sleep( static_cast<int>(1000.0f*sleepTime) );
#else
if (sleepTime > 0) {
usleep(sleepTime);
}
#endif
}
pthread_exit(0);
return NULL;
}
void NodeList::startSilentNodeRemovalThread() {
pthread_create(&removeSilentNodesThread, NULL, removeSilentNodes, (void*) this);
}
void NodeList::stopSilentNodeRemovalThread() {
silentNodeThreadStopFlag = true;
pthread_join(removeSilentNodesThread, NULL);
}
const QString QSETTINGS_GROUP_NAME = "NodeList";
const QString DOMAIN_SERVER_SETTING_KEY = "domainServerHostname";
void NodeList::loadData(QSettings *settings) {
settings->beginGroup(DOMAIN_SERVER_SETTING_KEY);
QString domainServerHostname = settings->value(DOMAIN_SERVER_SETTING_KEY).toString();
if (domainServerHostname.size() > 0) {
_domainHostname = domainServerHostname;
notifyDomainChanged();
}
settings->endGroup();
}
void NodeList::saveData(QSettings* settings) {
settings->beginGroup(DOMAIN_SERVER_SETTING_KEY);
if (_domainHostname != DEFAULT_DOMAIN_HOSTNAME) {
// the user is using a different hostname, store it
settings->setValue(DOMAIN_SERVER_SETTING_KEY, QVariant(_domainHostname));
} else {
// the user has switched back to default, remove the current setting
settings->remove(DOMAIN_SERVER_SETTING_KEY);
}
settings->endGroup();
}
NodeList::iterator NodeList::begin() const {
Node** nodeBucket = NULL;
for (int i = 0; i < _numNodes; i++) {
if (i % NODES_PER_BUCKET == 0) {
nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET];
}
if (nodeBucket[i % NODES_PER_BUCKET]->isAlive()) {
return NodeListIterator(this, i);
}
}
// there's no alive node to start from - return the end
return end();
}
NodeList::iterator NodeList::end() const {
return NodeListIterator(this, _numNodes);
}
NodeListIterator::NodeListIterator(const NodeList* nodeList, int nodeIndex) :
_nodeIndex(nodeIndex) {
_nodeList = nodeList;
}
NodeListIterator& NodeListIterator::operator=(const NodeListIterator& otherValue) {
_nodeList = otherValue._nodeList;
_nodeIndex = otherValue._nodeIndex;
return *this;
}
bool NodeListIterator::operator==(const NodeListIterator &otherValue) {
return _nodeIndex == otherValue._nodeIndex;
}
bool NodeListIterator::operator!=(const NodeListIterator &otherValue) {
return !(*this == otherValue);
}
Node& NodeListIterator::operator*() {
Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
return *nodeBucket[_nodeIndex % NODES_PER_BUCKET];
}
Node* NodeListIterator::operator->() {
Node** nodeBucket = _nodeList->_nodeBuckets[_nodeIndex / NODES_PER_BUCKET];
return nodeBucket[_nodeIndex % NODES_PER_BUCKET];
}
NodeListIterator& NodeListIterator::operator++() {
skipDeadAndStopIncrement();
return *this;
}
NodeList::iterator NodeListIterator::operator++(int) {
NodeListIterator newIterator = NodeListIterator(*this);
skipDeadAndStopIncrement();
return newIterator;
}
void NodeListIterator::skipDeadAndStopIncrement() {
while (_nodeIndex != _nodeList->_numNodes) {
++_nodeIndex;
if (_nodeIndex == _nodeList->_numNodes) {
break;
} else if ((*(*this)).isAlive()) {
// skip over the dead nodes
break;
}
}
}
void NodeList::addDomainListener(DomainChangeListener* listener) {
_domainListeners.push_back(listener);
QString domain = _domainHostname.isEmpty() ? _domainIP.toString() : _domainHostname;
listener->domainChanged(domain);
}
void NodeList::removeDomainListener(DomainChangeListener* listener) {
for (int i = 0; i < _domainListeners.size(); i++) {
if (_domainListeners[i] == listener) {
_domainListeners.erase(_domainListeners.begin() + i);
return;
}
}
}
void NodeList::addHook(NodeListHook* hook) {
_hooks.push_back(hook);
}
void NodeList::removeHook(NodeListHook* hook) {
for (int i = 0; i < _hooks.size(); i++) {
if (_hooks[i] == hook) {
_hooks.erase(_hooks.begin() + i);
return;
}
}
}
void NodeList::notifyHooksOfAddedNode(Node* node) {
for (int i = 0; i < _hooks.size(); i++) {
//printf("NodeList::notifyHooksOfAddedNode() i=%d\n", i);
_hooks[i]->nodeAdded(node);
}
}
void NodeList::notifyHooksOfKilledNode(Node* node) {
for (int i = 0; i < _hooks.size(); i++) {
//printf("NodeList::notifyHooksOfKilledNode() i=%d\n", i);
_hooks[i]->nodeKilled(node);
}
}
void NodeList::notifyDomainChanged() {
for (int i = 0; i < _domainListeners.size(); i++) {
_domainListeners[i]->domainChanged(_domainHostname);
}
}

View file

@ -8,6 +8,7 @@
#include "PacketHeaders.h"
#include "SharedUtil.h"
#include "UUID.h"
#include <QtCore/QDataStream>

View file

@ -15,7 +15,6 @@
#include "NodeList.h"
const int NUM_BYTES_RFC4122_UUID = 16;
const int MAX_PAYLOAD_BYTES = 1024;
/// Holds information used for request, creation, and deployment of assignments

View file

@ -23,19 +23,9 @@
#include <QtCore/QDebug>
int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) {
memcpy(nodeId, packedData, sizeof(uint16_t));
return sizeof(uint16_t);
}
int packNodeId(unsigned char* packStore, uint16_t nodeId) {
memcpy(packStore, &nodeId, sizeof(uint16_t));
return sizeof(uint16_t);
}
Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID) :
Node::Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket) :
_type(type),
_nodeID(nodeID),
_uuid(uuid),
_wakeMicrostamp(usecTimestampNow()),
_lastHeardMicrostamp(usecTimestampNow()),
_activeSocket(NULL),
@ -157,7 +147,8 @@ QDebug operator<<(QDebug debug, const Node &node) {
char localAddressBuffer[16] = {'\0'};
unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.getLocalSocket());
debug << "#" << node.getNodeID() << node.getTypeName() << node.getType();
debug.nospace() << node.getTypeName() << " (" << node.getType() << ")";
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " ";
debug.nospace() << publicAddressBuffer << ":" << publicAddressPort;
debug.nospace() << " / " << localAddressBuffer << ":" << localAddressPort;
return debug.nospace();

View file

@ -19,13 +19,14 @@
#endif
#include <QtCore/QDebug>
#include <QtCore/QUuid>
#include "NodeData.h"
#include "SimpleMovingAverage.h"
class Node {
public:
Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID);
Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket);
~Node();
bool operator==(const Node& otherNode);
@ -36,8 +37,8 @@ public:
void setType(char type) { _type = type; }
const char* getTypeName() const;
uint16_t getNodeID() const { return _nodeID; }
void setNodeID(uint16_t nodeID) { _nodeID = nodeID;}
const QUuid& getUUID() const { return _uuid; }
void setUUID(const QUuid& uuid) { _uuid = uuid; }
uint64_t getWakeMicrostamp() const { return _wakeMicrostamp; }
void setWakeMicrostamp(uint64_t wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
@ -78,7 +79,7 @@ private:
Node& operator=(Node otherNode);
char _type;
uint16_t _nodeID;
QUuid _uuid;
uint64_t _wakeMicrostamp;
uint64_t _lastHeardMicrostamp;
sockaddr* _publicSocket;

View file

@ -20,6 +20,7 @@
#include "NodeTypes.h"
#include "PacketHeaders.h"
#include "SharedUtil.h"
#include "UUID.h"
#ifdef _WIN32
#include "Syssocket.h"
@ -67,8 +68,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
_nodeSocket(newSocketListenPort),
_ownerType(newOwnerType),
_nodeTypesOfInterest(NULL),
_ownerID(UNKNOWN_NODE_ID),
_lastNodeID(UNKNOWN_NODE_ID + 1),
_ownerUUID(QUuid::createUuid()),
_numNoReplyDomainCheckIns(0),
_assignmentServerSocket(NULL),
_checkInPacket(NULL),
@ -183,19 +183,18 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe
// we've already verified packet version for the bulk packet, so all head data in the packet is also up to date
populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA);
uint16_t nodeID = -1;
while ((currentPosition - startPosition) < numTotalBytes) {
unpackNodeId(currentPosition, &nodeID);
memcpy(packetHolder + numBytesPacketHeader,
currentPosition,
numTotalBytes - (currentPosition - startPosition));
Node* matchingNode = nodeWithID(nodeID);
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)currentPosition, NUM_BYTES_RFC4122_UUID));
Node* matchingNode = nodeWithUUID(nodeUUID);
if (!matchingNode) {
// we're missing this node, we need to add it to the list
matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID);
matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, NULL, NULL);
}
currentPosition += updateNodeWithData(matchingNode,
@ -247,9 +246,9 @@ Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
return NULL;
}
Node* NodeList::nodeWithID(uint16_t nodeID) {
Node* NodeList::nodeWithUUID(const QUuid& nodeUUID) {
for(NodeList::iterator node = begin(); node != end(); node++) {
if (node->getNodeID() == nodeID) {
if (node->getUUID() == nodeUUID) {
return &(*node);
}
}
@ -297,6 +296,9 @@ void NodeList::reset() {
delete _nodeTypesOfInterest;
_nodeTypesOfInterest = NULL;
// refresh the owner UUID
_ownerUUID = QUuid::createUuid();
}
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
@ -362,46 +364,63 @@ void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes)
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
if (memcmp(packetData + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0
&& memcmp(packetData + NUM_BYTES_STUN_HEADER, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 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;
int byteIndex = NUM_BYTES_STUN_HEADER + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
uint8_t addressFamily = 0;
memcpy(&addressFamily, packetData + byteIndex, sizeof(addressFamily));
byteIndex += sizeof(addressFamily);
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
// grab the X-Port
uint16_t xorMappedPort = 0;
memcpy(&xorMappedPort, packetData + byteIndex, sizeof(xorMappedPort));
_publicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
byteIndex += sizeof(xorMappedPort);
// grab the X-Address
uint32_t xorMappedAddress = 0;
memcpy(&xorMappedAddress, packetData + byteIndex, sizeof(xorMappedAddress));
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
_publicAddress = QHostAddress(stunAddress);
qDebug("Public socket received from STUN server is %s:%hu\n",
_publicAddress.toString().toLocal8Bit().constData(),
_publicPort);
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
while (attributeStartIndex < dataBytes) {
if (memcmp(packetData + 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;
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
uint8_t addressFamily = 0;
memcpy(&addressFamily, packetData + byteIndex, sizeof(addressFamily));
byteIndex += sizeof(addressFamily);
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
// grab the X-Port
uint16_t xorMappedPort = 0;
memcpy(&xorMappedPort, packetData + byteIndex, sizeof(xorMappedPort));
_publicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
byteIndex += sizeof(xorMappedPort);
// grab the X-Address
uint32_t xorMappedAddress = 0;
memcpy(&xorMappedAddress, packetData + byteIndex, sizeof(xorMappedAddress));
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
_publicAddress = QHostAddress(stunAddress);
qDebug("Public socket received from STUN server is %s:%hu\n",
_publicAddress.toString().toLocal8Bit().constData(),
_publicPort);
break;
}
} else {
// push forward attributeStartIndex by the length of this attribute
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
uint16_t attributeLength = 0;
memcpy(&attributeLength, packetData + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE, sizeof(attributeLength));
attributeLength = ntohs(attributeLength);
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
}
}
}
}
void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
void NodeList::sendDomainServerCheckIn() {
static bool printedDomainServerIP = false;
// Lookup the IP address of the domain server if we need to
@ -459,14 +478,10 @@ void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
*(packetPosition++) = _ownerType;
if (!assignmentUUID) {
// if we don't have an assignment UUID just send the null one
assignmentUUID = QUuid().toRfc4122().constData();
}
// send our assignment UUID or the null one
memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID);
packetPosition += NUM_BYTES_RFC4122_UUID;
// send our owner UUID or the null one
QByteArray rfcOwnerUUID = _ownerUUID.toRfc4122();
memcpy(packetPosition, rfcOwnerUUID.constData(), rfcOwnerUUID.size());
packetPosition += rfcOwnerUUID.size();
// pack our public address to send to domain-server
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
@ -505,7 +520,6 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
int readNodes = 0;
char nodeType;
uint16_t nodeId;
// assumes only IPv4 addresses
sockaddr_in nodePublicSocket;
@ -518,7 +532,9 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
nodeType = *readPtr++;
readPtr += unpackNodeId(readPtr, (uint16_t*) &nodeId);
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) readPtr, NUM_BYTES_RFC4122_UUID));
readPtr += NUM_BYTES_RFC4122_UUID;
readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket);
readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket);
@ -528,11 +544,9 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address());
}
addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
addOrUpdateNode(nodeUUID, nodeType, (sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket);
}
// read out our ID from the packet
unpackNodeId(readPtr, &_ownerID);
return readNodes;
}
@ -572,7 +586,7 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const {
_nodeSocket.send(node->getPublicSocket(), pingPacket, sizeof(pingPacket));
}
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket) {
NodeList::iterator node = end();
if (publicSocket) {
@ -586,7 +600,7 @@ Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, c
if (node == end()) {
// we didn't have this node, so add them
Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
addNodeToList(newNode);

View file

@ -42,8 +42,6 @@ extern const unsigned short DEFAULT_DOMAIN_SERVER_PORT;
const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
const int UNKNOWN_NODE_ID = 0;
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
class Assignment;
@ -83,12 +81,9 @@ public:
unsigned short getDomainPort() const { return _domainPort; }
void setDomainPort(unsigned short domainPort) { _domainPort = domainPort; }
uint16_t getLastNodeID() const { return _lastNodeID; }
void increaseNodeID() { (++_lastNodeID == UNKNOWN_NODE_ID) ? ++_lastNodeID : _lastNodeID; }
uint16_t getOwnerID() const { return _ownerID; }
void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; }
const QUuid& getOwnerUUID() const { return _ownerUUID; }
void setOwnerUUID(const QUuid& ownerUUID) { _ownerUUID = ownerUUID; }
UDPSocket* getNodeSocket() { return &_nodeSocket; }
@ -106,7 +101,7 @@ public:
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
void sendDomainServerCheckIn(const char* assignmentUUID = NULL);
void sendDomainServerCheckIn();
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; }
@ -115,9 +110,9 @@ public:
void pingPublicAndLocalSocketsForInactiveNode(Node* node) const;
Node* nodeWithAddress(sockaddr *senderAddress);
Node* nodeWithID(uint16_t nodeID);
Node* nodeWithUUID(const QUuid& nodeUUID);
Node* addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId);
Node* addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket);
void processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
void processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes);
@ -166,8 +161,7 @@ private:
UDPSocket _nodeSocket;
char _ownerType;
char* _nodeTypesOfInterest;
uint16_t _ownerID;
uint16_t _lastNodeID;
QUuid _ownerUUID;
pthread_t removeSilentNodesThread;
pthread_t checkInWithDomainServerThread;
int _numNoReplyDomainCheckIns;

View file

@ -11,6 +11,8 @@
#include <QtCore/QUuid>
const int NUM_BYTES_RFC4122_UUID = 16;
QString uuidStringWithoutCurlyBraces(const QUuid& uuid);
#endif /* defined(__hifi__UUID__) */

View file

@ -32,8 +32,8 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
// Create voxel sending thread...
uint16_t nodeID = getOwningNode()->getNodeID();
_voxelSendThread = new VoxelSendThread(nodeID, voxelServer);
QUuid nodeUUID = getOwningNode()->getUUID();
_voxelSendThread = new VoxelSendThread(nodeUUID, voxelServer);
_voxelSendThread->initialize(true);
}

View file

@ -18,15 +18,15 @@ extern EnvironmentData environmentData[3];
#include "VoxelServer.h"
#include "VoxelServerConsts.h"
VoxelSendThread::VoxelSendThread(uint16_t nodeID, VoxelServer* myServer) :
_nodeID(nodeID),
VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) :
_nodeUUID(nodeUUID),
_myServer(myServer) {
}
bool VoxelSendThread::process() {
uint64_t lastSendTime = usecTimestampNow();
Node* node = NodeList::getInstance()->nodeWithID(_nodeID);
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
VoxelNodeData* nodeData = NULL;
if (node) {

View file

@ -21,13 +21,13 @@
/// Threaded processor for sending voxel packets to a single client
class VoxelSendThread : public virtual GenericThread {
public:
VoxelSendThread(uint16_t nodeID, VoxelServer* myServer);
VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer);
protected:
/// Implements generic processing behavior for this thread.
virtual bool process();
private:
uint16_t _nodeID;
QUuid _nodeUUID;
VoxelServer* _myServer;
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);

View file

@ -11,8 +11,9 @@
#include <cstring>
#include <cstdio>
#include <QDebug>
#include <QString>
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtCore/QUuid>
#include <Logging.h>
#include <OctalCode.h>
@ -25,6 +26,7 @@
#include <SceneUtils.h>
#include <PerfStat.h>
#include <JurisdictionSender.h>
#include <UUID.h>
#ifdef _WIN32
#include "Syssocket.h"
@ -384,12 +386,13 @@ void VoxelServer::run() {
if (packetData[0] == PACKET_TYPE_HEAD_DATA) {
// If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
// need to make sure we have it in our nodeList.
uint16_t nodeID = 0;
unpackNodeId(packetData + numBytesPacketHeader, &nodeID);
Node* node = NodeList::getInstance()->addOrUpdateNode(&senderAddress,
&senderAddress,
NODE_TYPE_AGENT,
nodeID);
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader,
NUM_BYTES_RFC4122_UUID));
Node* node = NodeList::getInstance()->addOrUpdateNode(nodeUUID,
NODE_TYPE_AGENT,
&senderAddress,
&senderAddress);
NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength);

View file

@ -33,7 +33,7 @@ void JurisdictionListener::nodeAdded(Node* node) {
}
void JurisdictionListener::nodeKilled(Node* node) {
_jurisdictions.erase(_jurisdictions.find(node->getNodeID()));
_jurisdictions.erase(_jurisdictions.find(node->getUUID()));
}
bool JurisdictionListener::queueJurisdictionRequest() {
@ -66,10 +66,10 @@ void JurisdictionListener::processPacket(sockaddr& senderAddress, unsigned char*
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (node) {
uint16_t nodeID = node->getNodeID();
QUuid nodeUUID = node->getUUID();
JurisdictionMap map;
map.unpackFromMessage(packetData, packetLength);
_jurisdictions[nodeID] = map;
_jurisdictions[nodeUUID] = map;
}
}
}

View file

@ -12,7 +12,9 @@
#include <map>
#include <stdint.h>
#include <vector>
#include <QtCore/QString>
#include <QtCore/QUuid>
class JurisdictionMap {
public:
@ -71,7 +73,7 @@ private:
/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are
/// managing which jurisdictions.
typedef std::map<uint16_t, JurisdictionMap> NodeToJurisdictionMap;
typedef std::map<QUuid, JurisdictionMap> NodeToJurisdictionMap;
#endif /* defined(__hifi__JurisdictionMap__) */

View file

@ -27,9 +27,9 @@ void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char*
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
if (node) {
uint16_t nodeID = node->getNodeID();
QUuid nodeUUID = node->getUUID();
lock();
_nodesRequestingJurisdictions.insert(nodeID);
_nodesRequestingJurisdictions.insert(nodeUUID);
unlock();
}
}
@ -52,11 +52,11 @@ bool JurisdictionSender::process() {
}
int nodeCount = 0;
for (std::set<uint16_t>::iterator nodeIterator = _nodesRequestingJurisdictions.begin();
for (std::set<QUuid>::iterator nodeIterator = _nodesRequestingJurisdictions.begin();
nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) {
uint16_t nodeID = *nodeIterator;
Node* node = NodeList::getInstance()->nodeWithID(nodeID);
QUuid nodeUUID = *nodeIterator;
Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
if (node->getActiveSocket() != NULL) {
sockaddr* nodeAddress = node->getActiveSocket();

View file

@ -35,6 +35,6 @@ protected:
private:
JurisdictionMap* _jurisdictionMap;
std::set<uint16_t> _nodesRequestingJurisdictions;
std::set<QUuid> _nodesRequestingJurisdictions;
};
#endif // __shared__JurisdictionSender__

View file

@ -17,8 +17,8 @@
#include "VoxelEditPacketSender.h"
EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssize_t length, uint16_t nodeID) {
_nodeID = nodeID;
EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssize_t length, QUuid nodeUUID) {
_nodeUUID = nodeUUID;
_currentType = type;
_currentSize = length;
memcpy(_currentBuffer, buffer, length);
@ -98,12 +98,12 @@ bool VoxelEditPacketSender::voxelServersExist() const {
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
// a known nodeID. However, we also want to handle the case where the
void VoxelEditPacketSender::queuePacketToNode(uint16_t nodeID, unsigned char* buffer, ssize_t length) {
void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER &&
((node->getNodeID() == nodeID) || (nodeID == (uint16_t)UNKNOWN_NODE_ID)) ) {
((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
sockaddr* nodeAddress = node->getActiveSocket();
queuePacketForSending(*nodeAddress, buffer, length);
}
@ -170,14 +170,14 @@ void VoxelEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t le
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
uint16_t nodeID = node->getNodeID();
QUuid nodeUUID = node->getUUID();
bool isMyJurisdiction = true;
// we need to get the jurisdiction for this
// here we need to get the "pending packet" for this server
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeID];
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
if (isMyJurisdiction) {
queuePacketToNode(nodeID, buffer, length);
queuePacketToNode(nodeUUID, buffer, length);
}
}
}
@ -216,18 +216,18 @@ void VoxelEditPacketSender::queueVoxelEditMessage(PACKET_TYPE type, unsigned cha
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
uint16_t nodeID = node->getNodeID();
QUuid nodeUUID = node->getUUID();
bool isMyJurisdiction = true;
if (_voxelServerJurisdictions) {
// we need to get the jurisdiction for this
// here we need to get the "pending packet" for this server
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeID];
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
}
if (isMyJurisdiction) {
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeID];
packetBuffer._nodeID = nodeID;
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID];
packetBuffer._nodeUUID = nodeUUID;
// If we're switching type, then we send the last one and start over
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
@ -255,14 +255,14 @@ void VoxelEditPacketSender::releaseQueuedMessages() {
if (!voxelServersExist()) {
_releaseQueuedMessagesPending = true;
} else {
for (std::map<uint16_t,EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
for (std::map<QUuid, EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
releaseQueuedPacket(i->second);
}
}
}
void VoxelEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) {
queuePacketToNode(packetBuffer._nodeID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
packetBuffer._currentSize = 0;
packetBuffer._currentType = PACKET_TYPE_UNKNOWN;
}

View file

@ -19,9 +19,9 @@
/// Used for construction of edit voxel packets
class EditPacketBuffer {
public:
EditPacketBuffer() { _currentSize = 0; _currentType = PACKET_TYPE_UNKNOWN; _nodeID = UNKNOWN_NODE_ID; }
EditPacketBuffer(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length, uint16_t nodeID = UNKNOWN_NODE_ID);
uint16_t _nodeID;
EditPacketBuffer() : _nodeUUID(), _currentType(PACKET_TYPE_UNKNOWN), _currentSize(0) { }
EditPacketBuffer(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length, const QUuid nodeUUID = QUuid());
QUuid _nodeUUID;
PACKET_TYPE _currentType;
unsigned char _currentBuffer[MAX_PACKET_SIZE];
ssize_t _currentSize;
@ -86,7 +86,7 @@ public:
private:
bool _shouldSend;
void queuePacketToNode(uint16_t nodeID, unsigned char* buffer, ssize_t length);
void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length);
void queuePacketToNodes(unsigned char* buffer, ssize_t length);
void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type);
void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
@ -94,7 +94,7 @@ private:
void processPreServerExistsPackets();
// These are packets which are destined from know servers but haven't been released because they're still too small
std::map<uint16_t,EditPacketBuffer> _pendingEditPackets;
std::map<QUuid, EditPacketBuffer> _pendingEditPackets;
// These are packets that are waiting to be processed because we don't yet know if there are voxel servers
int _maxPendingMessages;

View file

@ -56,7 +56,7 @@ void VoxelNode::init(unsigned char * octalCode) {
_voxelSystem = NULL;
_isDirty = true;
_shouldRender = false;
_sourceID = UNKNOWN_NODE_ID;
_sourceID = 0; // hardcoded to 0 for removal of 16 bit node ID
calculateAABox();
markWithChangedTime();

View file

@ -1555,7 +1555,7 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
unsigned char* entireFile = new unsigned char[fileLength];
file.read((char*)entireFile, fileLength);
bool wantImportProgress = true;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, UNKNOWN_NODE_ID, wantImportProgress);
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, wantImportProgress);
readBitstreamToTree(entireFile, fileLength, args);
delete[] entireFile;
@ -1815,7 +1815,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin
// ask destination tree to read the bitstream
bool wantImportProgress = true;
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, UNKNOWN_NODE_ID, wantImportProgress);
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress);
readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
}
}

View file

@ -108,7 +108,7 @@ public:
bool includeColor = WANT_COLOR,
bool includeExistsBits = WANT_EXISTS_BITS,
VoxelNode* destinationNode = NULL,
uint16_t sourceID = UNKNOWN_NODE_ID,
uint16_t sourceID = 0, // hardcoded to 0 for removal of 16 bit node ID
bool wantImportProgress = false) :
includeColor(includeColor),
includeExistsBits(includeExistsBits),