diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 7b909b4e11..4d0577b960 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 497797d2e8..bff0b529f8 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 df6ea65bc2..4f17cd2221 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,33 @@ void Application::editPreferences() { if (dialog.exec() != QDialog::Accepted) { return; } + + + 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); + } + QUrl url(avatarURL->text()); _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); + _headCameraPitchYawScale = headCameraPitchYawScale->value(); _myAvatar.setLeanScale(leanScale->value()); _audioJitterBufferSamples = audioJitterBufferSamples->value(); @@ -1926,8 +1956,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()) { @@ -1936,8 +1966,8 @@ void Application::update(float deltaTime) { avatar->simulate(deltaTime, NULL); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } + node->unlock(); } - nodeList->unlock(); // Simulate myself if (_gravityUse->isChecked()) { @@ -2426,8 +2456,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()) { @@ -2436,8 +2468,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) { @@ -3207,11 +3240,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, diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 73f971b7da..63fc24f56d 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 = *(sockaddr_in*) 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((sockaddr*) &audioSocket, + 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..f7c9758fd0 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..aa88cb158c 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 391e22a915..004568584d 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,17 +63,37 @@ 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() { delete _nodeTypesOfInterest; + clear(); + // stop the spawned threads, if they were started stopSilentNodeRemovalThread(); +} + +void NodeList::setDomainHostname(const char* domainHostname) { + memset(_domainHostname, 0, sizeof(_domainHostname)); + memcpy(_domainHostname, domainHostname, strlen(domainHostname)); - pthread_mutex_destroy(&mutex); + // reset the domain IP so the hostname is checked again + setDomainIP(""); +} + +void NodeList::setDomainIP(const char* domainIP) { + memset(_domainIP, 0, sizeof(_domainIP)); + memcpy(_domainIP, domainIP, strlen(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) { @@ -92,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: { @@ -110,7 +137,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); @@ -118,38 +144,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)); - } - - unlock(); + } } int NodeList::updateNodeWithData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { @@ -164,6 +189,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()) { @@ -174,7 +201,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) { @@ -209,6 +240,21 @@ 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]; + + node->lock(); + delete node; + + node = NULL; + } + + _numNodes = 0; +} + void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) { delete _nodeTypesOfInterest; @@ -221,18 +267,19 @@ 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) { + printf("Looking up %s\n", _domainHostname); 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; } @@ -279,7 +326,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 da9c4a556a..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 #include #include +#include #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; } @@ -65,8 +75,7 @@ public: int size() { return _numNodes; } int getNumAliveNodes() const; - void lock() { pthread_mutex_lock(&mutex); } - void unlock() { pthread_mutex_unlock(&mutex); } + void clear(); void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest); void sendDomainServerCheckIn(); @@ -101,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; @@ -111,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;