From 12697c6b141475d491ff2a314d7e58f79f192778 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 14:30:13 -0700 Subject: [PATCH 01/11] add method to clear the NodeList --- libraries/shared/src/NodeList.cpp | 15 +++++++++++++++ libraries/shared/src/NodeList.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 391e22a915..b4e3112768 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -70,6 +70,8 @@ NodeList::NodeList(char newOwnerType, unsigned int newSocketListenPort) : NodeList::~NodeList() { delete _nodeTypesOfInterest; + clear(); + // stop the spawned threads, if they were started stopSilentNodeRemovalThread(); @@ -209,6 +211,19 @@ int NodeList::getNumAliveNodes() const { return numAliveNodes; } +void NodeList::clear() { + // 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]; + + delete node; + node = NULL; + } + + _numNodes = 0; +} + void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) { delete _nodeTypesOfInterest; diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index da9c4a556a..57f8083113 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -65,6 +65,8 @@ public: int size() { return _numNodes; } int getNumAliveNodes() const; + void clear(); + void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } From d389dc6e3ad73ece5fa78f6835a0a41d07713a83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:17:10 -0700 Subject: [PATCH 02/11] add method to NodeList to set domain IP to local, move mutex lock to node --- animation-server/src/main.cpp | 3 +- audio-mixer/src/main.cpp | 9 +++--- avatar-mixer/src/main.cpp | 3 +- interface/src/Application.cpp | 27 +++++++++++----- interface/src/Audio.cpp | 4 +-- libraries/shared/src/Node.cpp | 4 +++ libraries/shared/src/Node.h | 4 +++ libraries/shared/src/NodeList.cpp | 51 ++++++++++++++++++++----------- libraries/shared/src/NodeList.h | 22 ++++++++----- voxel-server/src/main.cpp | 3 +- 10 files changed, 85 insertions(+), 45 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 126216ea9b..c6c38d8748 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -697,8 +697,7 @@ int main(int argc, const char * argv[]) ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = NULL; // do we need a callback? diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index b900c48479..239eb7a32d 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -70,16 +70,15 @@ bool wantLocalDomain = false; int main(int argc, const char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT); + // Handle Local Domain testing with the --local command line const char* local = "--local"; ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); - } - - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT); + nodeList->setDomainIPToLocalhost(); + } ssize_t receivedBytes = 0; diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index f2fd031526..b24fb7dcbc 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -60,8 +60,7 @@ int main(int argc, const char* argv[]) { const char* local = "--local"; if (cmdOptionExists(argc, argv, local)) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = attachAvatarDataToNode; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75f45e8d91..6504c2d87f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -227,14 +227,14 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : const char* domainIP = getCmdOption(argc, constArgv, "--domain"); if (domainIP) { - strcpy(DOMAIN_IP, domainIP); + NodeList::getInstance()->setDomainIP(domainIP); } // Handle Local Domain testing with the --local command line if (cmdOptionExists(argc, constArgv, "--local")) { printLog("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + + NodeList::getInstance()->setDomainIPToLocalhost(); } // Check to see if the user passed in a command line option for loading a local @@ -1101,8 +1101,14 @@ void Application::editPreferences() { QFormLayout* form = new QFormLayout(); layout->addLayout(form, 1); + const int QLINE_MINIMUM_WIDTH = 400; + + QLineEdit* domainServerHostname = new QLineEdit(QString(NodeList::getInstance()->getDomainHostname())); + domainServerHostname->setMinimumWidth(QLINE_MINIMUM_WIDTH); + form->addRow("Domain server:", domainServerHostname); + QLineEdit* avatarURL = new QLineEdit(_myAvatar.getVoxels()->getVoxelURL().toString()); - avatarURL->setMinimumWidth(400); + avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH); form->addRow("Avatar URL:", avatarURL); QSpinBox* horizontalFieldOfView = new QSpinBox(); @@ -1133,9 +1139,11 @@ void Application::editPreferences() { if (dialog.exec() != QDialog::Accepted) { return; } + QUrl url(avatarURL->text()); _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); + _headCameraPitchYawScale = headCameraPitchYawScale->value(); _myAvatar.setLeanScale(leanScale->value()); _audioJitterBufferSamples = audioJitterBufferSamples->value(); @@ -1956,8 +1964,8 @@ void Application::update(float deltaTime) { //loop through all the other avatars and simulate them... NodeList* nodeList = NodeList::getInstance(); - nodeList->lock(); for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + node->lock(); if (node->getLinkedData() != NULL) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -1966,8 +1974,8 @@ void Application::update(float deltaTime) { avatar->simulate(deltaTime, NULL); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } + node->unlock(); } - nodeList->unlock(); // Simulate myself if (_gravityUse->isChecked()) { @@ -2456,8 +2464,10 @@ void Application::displaySide(Camera& whichCamera) { if (_renderAvatarsOn->isChecked()) { // Render avatars of other nodes NodeList* nodeList = NodeList::getInstance(); - nodeList->lock(); + for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { + node->lock(); + if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) { Avatar *avatar = (Avatar *)node->getLinkedData(); if (!avatar->isInitialized()) { @@ -2466,8 +2476,9 @@ void Application::displaySide(Camera& whichCamera) { avatar->render(false, _renderAvatarBalls->isChecked()); avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked()); } + + node->unlock(); } - nodeList->unlock(); // Render my own Avatar if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 73f971b7da..0e07f50693 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -126,8 +126,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); - interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) - .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + + leadingBytes); } } diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 3fddc71ad1..a023a70326 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -53,6 +53,8 @@ Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t no } else { _localSocket = NULL; } + + pthread_mutex_init(&mutex, 0); } Node::~Node() { @@ -60,6 +62,8 @@ Node::~Node() { delete _localSocket; delete _linkedData; delete _bytesReceivedMovingAverage; + + pthread_mutex_destroy(&mutex); } // Names of Node Types diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index de43558b7a..d61657d730 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -65,6 +65,9 @@ public: int getPingMs() const { return _pingMs; }; void setPingMs(int pingMs) { _pingMs = pingMs; }; + + void lock() { pthread_mutex_lock(&mutex); } + void unlock() { pthread_mutex_unlock(&mutex); } static void printLog(Node const&); private: @@ -83,6 +86,7 @@ private: NodeData* _linkedData; bool _isAlive; int _pingMs; + pthread_mutex_t mutex; }; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index b4e3112768..7e34f37535 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -29,9 +29,9 @@ const char SOLO_NODE_TYPES[3] = { NODE_TYPE_VOXEL_SERVER }; -char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; -char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup -const int DOMAINSERVER_PORT = 40102; +const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES] = "root.highfidelity.io"; +const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN] = ""; // IP Address will be re-set by lookup on startup +const int DEFAULT_DOMAINSERVER_PORT = 40102; bool silentNodeThreadStopFlag = false; bool pingUnknownNodeThreadStopFlag = false; @@ -63,8 +63,10 @@ NodeList::NodeList(char newOwnerType, unsigned int newSocketListenPort) : _ownerType(newOwnerType), _nodeTypesOfInterest(NULL), _ownerID(UNKNOWN_NODE_ID), - _lastNodeID(0) { - pthread_mutex_init(&mutex, 0); + _lastNodeID(0) +{ + memcpy(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, sizeof(DEFAULT_DOMAIN_HOSTNAME)); + memcpy(_domainIP, DEFAULT_DOMAIN_IP, sizeof(DEFAULT_DOMAIN_IP)); } NodeList::~NodeList() { @@ -74,8 +76,19 @@ NodeList::~NodeList() { // stop the spawned threads, if they were started stopSilentNodeRemovalThread(); - - pthread_mutex_destroy(&mutex); +} + +void NodeList::setDomainHostname(const char* domainHostname) { + memcpy(_domainHostname, domainHostname, sizeof(&domainHostname)); +} + +void NodeList::setDomainIP(const char* domainIP) { + memcpy(_domainIP, domainIP, sizeof(&domainIP)); +} + +void NodeList::setDomainIPToLocalhost() { + int ip = getLocalAddress(); + sprintf(_domainIP, "%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); } void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { @@ -112,7 +125,6 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat } void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes) { - lock(); // find the avatar mixer in our node list and update the lastRecvTime from it Node* bulkSendNode = nodeWithAddress(senderAddress); @@ -149,9 +161,8 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe currentPosition += updateNodeWithData(matchingNode, packetHolder, numTotalBytes - (currentPosition - startPosition)); + } - - unlock(); } int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { @@ -166,6 +177,8 @@ int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetD } int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int dataBytes) { + node->lock(); + node->setLastHeardMicrostamp(usecTimestampNow()); if (node->getActiveSocket()) { @@ -176,7 +189,11 @@ int NodeList::updateNodeWithData(Node *node, unsigned char *packetData, int data linkedDataCreateCallback(node); } - return node->getLinkedData()->parseData(packetData, dataBytes); + int numParsedBytes = node->getLinkedData()->parseData(packetData, dataBytes); + + node->unlock(); + + return numParsedBytes; } Node* NodeList::nodeWithAddress(sockaddr *senderAddress) { @@ -236,18 +253,18 @@ void NodeList::sendDomainServerCheckIn() { static bool printedDomainServerIP = false; // Lookup the IP address of the domain server if we need to - if (atoi(DOMAIN_IP) == 0) { + if (atoi(_domainIP) == 0) { struct hostent* pHostInfo; - if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) { + if ((pHostInfo = gethostbyname(_domainHostname)) != NULL) { sockaddr_in tempAddress; memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); - strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); - printLog("Domain Server: %s \n", DOMAIN_HOSTNAME); + strcpy(_domainIP, inet_ntoa(tempAddress.sin_addr)); + printLog("Domain Server: %s \n", _domainHostname); } else { printLog("Failed domain server lookup\n"); } } else if (!printedDomainServerIP) { - printLog("Domain Server IP: %s\n", DOMAIN_IP); + printLog("Domain Server IP: %s\n", _domainIP); printedDomainServerIP = true; } @@ -294,7 +311,7 @@ void NodeList::sendDomainServerCheckIn() { checkInPacketSize = packetPosition - checkInPacket; } - _nodeSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); + _nodeSocket.send(_domainIP, DEFAULT_DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); } int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 57f8083113..20eaddc738 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -9,8 +9,10 @@ #ifndef __hifi__NodeList__ #define __hifi__NodeList__ +#include <netinet/in.h> #include <stdint.h> #include <iterator> +#include <unistd.h> #include "Node.h" #include "UDPSocket.h" @@ -30,9 +32,11 @@ const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; extern const char SOLO_NODE_TYPES[3]; -extern char DOMAIN_HOSTNAME[]; -extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup -extern const int DOMAINSERVER_PORT; +const int MAX_HOSTNAME_BYTES = 255; + +extern const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES]; +extern const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN]; // IP Address will be re-set by lookup on startup +extern const int DEFAULT_DOMAINSERVER_PORT; const int UNKNOWN_NODE_ID = -1; @@ -48,6 +52,12 @@ public: NodeListIterator begin() const; NodeListIterator end() const; + const char* getDomainHostname() const { return _domainHostname; }; + void setDomainHostname(const char* domainHostname); + + void setDomainIP(const char* domainIP); + void setDomainIPToLocalhost(); + char getOwnerType() const { return _ownerType; } uint16_t getLastNodeID() const { return _lastNodeID; } @@ -67,9 +77,6 @@ public: void clear(); - void lock() { pthread_mutex_lock(&mutex); } - void unlock() { pthread_mutex_unlock(&mutex); } - void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); @@ -103,6 +110,8 @@ private: void addNodeToList(Node* newNode); + char _domainHostname[MAX_HOSTNAME_BYTES]; + char _domainIP[INET_ADDRSTRLEN]; Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET]; int _numNodes; UDPSocket _nodeSocket; @@ -113,7 +122,6 @@ private: uint16_t _lastNodeID; pthread_t removeSilentNodesThread; pthread_t checkInWithDomainServerThread; - pthread_mutex_t mutex; void handlePingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 254b1d2d96..4529d34bd8 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -383,8 +383,7 @@ int main(int argc, const char * argv[]) { ::wantLocalDomain = cmdOptionExists(argc, argv,local); if (::wantLocalDomain) { printf("Local Domain MODE!\n"); - int ip = getLocalAddress(); - sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)); + nodeList->setDomainIPToLocalhost(); } nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; From 94b6bfccf64f09fb7351bf919aeb42fb61b47dbb Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:17:53 -0700 Subject: [PATCH 03/11] update the private mutex node variable to standard --- libraries/shared/src/Node.cpp | 4 ++-- libraries/shared/src/Node.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index a023a70326..f7c9758fd0 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -54,7 +54,7 @@ Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t no _localSocket = NULL; } - pthread_mutex_init(&mutex, 0); + pthread_mutex_init(&_mutex, 0); } Node::~Node() { @@ -63,7 +63,7 @@ Node::~Node() { delete _linkedData; delete _bytesReceivedMovingAverage; - pthread_mutex_destroy(&mutex); + pthread_mutex_destroy(&_mutex); } // Names of Node Types diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index d61657d730..e5396a5b25 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -86,7 +86,7 @@ private: NodeData* _linkedData; bool _isAlive; int _pingMs; - pthread_mutex_t mutex; + pthread_mutex_t _mutex; }; From e3d1e5db5d3eda5254c3123f1e608c5560f5adcc Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:45:27 -0700 Subject: [PATCH 04/11] correct reference to mutex to lock in Node --- libraries/shared/src/Node.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index e5396a5b25..aa88cb158c 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -66,8 +66,8 @@ public: int getPingMs() const { return _pingMs; }; void setPingMs(int pingMs) { _pingMs = pingMs; }; - void lock() { pthread_mutex_lock(&mutex); } - void unlock() { pthread_mutex_unlock(&mutex); } + void lock() { pthread_mutex_lock(&_mutex); } + void unlock() { pthread_mutex_unlock(&_mutex); } static void printLog(Node const&); private: From 6b83f95f9e433a3007e136fca575f439b617fbfd Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:46:04 -0700 Subject: [PATCH 05/11] conditionally set a new hostname on preferences save --- interface/src/Application.cpp | 8 ++++ libraries/shared/src/NodeList.cpp | 70 +++++++++++++++++-------------- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6504c2d87f..998d2c9126 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1140,6 +1140,14 @@ void Application::editPreferences() { return; } + // check if the domain server hostname is new - if so we need to clear the nodelist and delete the local voxels + const char* newHostname = domainServerHostname->text().toLocal8Bit().data(); + + if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) { + NodeList::getInstance()->clear(); + NodeList::getInstance()->setDomainHostname(newHostname); + } + QUrl url(avatarURL->text()); _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 7e34f37535..2e12e8ab71 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -78,12 +78,17 @@ NodeList::~NodeList() { stopSilentNodeRemovalThread(); } -void NodeList::setDomainHostname(const char* domainHostname) { - memcpy(_domainHostname, domainHostname, sizeof(&domainHostname)); +void NodeList::setDomainHostname(const char* domainHostname) { + memset(_domainHostname, 0, sizeof(_domainHostname)); + memcpy(_domainHostname, domainHostname, strlen(domainHostname)); + + // reset the domain IP so the hostname is checked again + setDomainIP(""); } void NodeList::setDomainIP(const char* domainIP) { - memcpy(_domainIP, domainIP, sizeof(&domainIP)); + memset(_domainIP, 0, sizeof(_domainIP)); + memcpy(_domainIP, domainIP, strlen(domainIP)); } void NodeList::setDomainIPToLocalhost() { @@ -132,37 +137,37 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe 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); + int numBytesPacketHeader = numBytesForPacketHeader(packetData); - if (!matchingNode) { - // we're missing this node, we need to add it to the list - matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID); + 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)); + } - - currentPosition += updateNodeWithData(matchingNode, - packetHolder, - numTotalBytes - (currentPosition - startPosition)); - - } + } } int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { @@ -234,7 +239,9 @@ void NodeList::clear() { Node** nodeBucket = _nodeBuckets[i / NODES_PER_BUCKET]; Node* node = nodeBucket[i % NODES_PER_BUCKET]; + node->lock(); delete node; + node = NULL; } @@ -254,6 +261,7 @@ void NodeList::sendDomainServerCheckIn() { // Lookup the IP address of the domain server if we need to if (atoi(_domainIP) == 0) { + printf("Looking up %s\n", _domainHostname); struct hostent* pHostInfo; if ((pHostInfo = gethostbyname(_domainHostname)) != NULL) { sockaddr_in tempAddress; From 6c2682833ec0c05d3e9010e4c71f61a0d73d5bac Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:53:25 -0700 Subject: [PATCH 06/11] lock on the solo voxelServer before deleting local voxels --- interface/src/Application.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 998d2c9126..cbccb5135f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1140,10 +1140,24 @@ void Application::editPreferences() { return; } - // check if the domain server hostname is new - if so we need to clear the nodelist and delete the local voxels + const char* newHostname = domainServerHostname->text().toLocal8Bit().data(); + // check if the domain server hostname is new if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) { + // if so we need to clear the nodelist and delete the local voxels + Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + + if (voxelServer) { + voxelServer->lock(); + } + + _voxels.killLocalVoxels(); + + if (voxelServer) { + voxelServer->unlock(); + } + NodeList::getInstance()->clear(); NodeList::getInstance()->setDomainHostname(newHostname); } From 9fe1c7c63daddb204879745fa4c1e2a063625337 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 15:59:31 -0700 Subject: [PATCH 07/11] lock the voxel server when receiving data to avoid race crash --- interface/src/Application.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cbccb5135f..82851355b7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3270,11 +3270,21 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_VOXEL_DATA_MONOCHROME: case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: - app->_voxels.parseData(app->_incomingPacket, bytesReceived); - break; - case PACKET_TYPE_ENVIRONMENT_DATA: - app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + case PACKET_TYPE_ENVIRONMENT_DATA: { + Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + if (voxelServer) { + voxelServer->lock(); + + if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { + app->_environment.parseData(&senderAddress, app->_incomingPacket, bytesReceived); + } else { + app->_voxels.parseData(app->_incomingPacket, bytesReceived); + } + + voxelServer->unlock(); + } break; + } case PACKET_TYPE_BULK_AVATAR_DATA: NodeList::getInstance()->processBulkNodeData(&senderAddress, app->_incomingPacket, From a204a8b87238a9628f551ef40623b4e5c5f4d782 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 16:01:05 -0700 Subject: [PATCH 08/11] lock the audioMixer to avoid crash when grabbing socket --- interface/src/Audio.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0e07f50693..0307a2df3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -96,6 +96,10 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); if (audioMixer) { + audioMixer->lock(); + sockaddr_in audioSocket = *audioMixer->getActiveSocket(); + audioMixer->unlock(); + glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); @@ -122,12 +126,13 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); - nodeList->getNodeSocket()->send(audioMixer->getActiveSocket(), - dataPacket, - BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + nodeList->getNodeSocket()->send(audioSocket, + dataPacket, + BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); + } } From 33ddda25586e0411cf77fbbb2d5b96dd3a757771 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 16:02:36 -0700 Subject: [PATCH 09/11] correct reference to audio mixer sockaddr_in --- interface/src/Audio.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0307a2df3b..63fc24f56d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -97,7 +97,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o if (audioMixer) { audioMixer->lock(); - sockaddr_in audioSocket = *audioMixer->getActiveSocket(); + sockaddr_in audioSocket = *(sockaddr_in*) audioMixer->getActiveSocket(); audioMixer->unlock(); glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); @@ -126,7 +126,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL); - nodeList->getNodeSocket()->send(audioSocket, + nodeList->getNodeSocket()->send((sockaddr*) &audioSocket, dataPacket, BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); From 081a44dbff05d390473b280f60776b1b7b5203c1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 16:05:23 -0700 Subject: [PATCH 10/11] only process new domain list if it comes from current DS --- libraries/shared/src/NodeList.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2e12e8ab71..6d79b9471a 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -112,7 +112,14 @@ void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetData, size_t dataBytes) { switch (packetData[0]) { case PACKET_TYPE_DOMAIN: { - processDomainServerList(packetData, dataBytes); + // only process the DS if this is our current domain server + sockaddr_in domainServerSocket = *(sockaddr_in*) senderAddress; + const char* domainSenderIP = inet_ntoa(domainServerSocket.sin_addr); + + if (memcmp(domainSenderIP, _domainIP, strlen(domainSenderIP)) == 0) { + processDomainServerList(packetData, dataBytes); + } + break; } case PACKET_TYPE_PING: { From c27cd7ae426a49de46a45738d3e8b7f70b6c281a Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Mon, 15 Jul 2013 16:49:36 -0700 Subject: [PATCH 11/11] couple of type squishes in NodeList --- interface/src/Application.cpp | 2 +- libraries/shared/src/NodeList.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 82851355b7..a9313e7549 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3271,7 +3271,7 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_Z_COMMAND: case PACKET_TYPE_ERASE_VOXEL: case PACKET_TYPE_ENVIRONMENT_DATA: { - Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); + Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); if (voxelServer) { voxelServer->lock(); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 6d79b9471a..004568584d 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -147,8 +147,8 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe int numBytesPacketHeader = numBytesForPacketHeader(packetData); - unsigned char *startPosition = packetData; - unsigned char *currentPosition = startPosition + numBytesPacketHeader; + 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