From f581d4d97608c5181db0fd318ab80dbbbb4e7397 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 16:01:23 -0700 Subject: [PATCH 01/21] handle STUN request and response in NodeList --- libraries/shared/src/NodeList.cpp | 200 +++++++++++++++++++------ libraries/shared/src/NodeList.h | 5 + libraries/shared/src/PacketHeaders.cpp | 2 +- libraries/shared/src/PacketHeaders.h | 1 + 4 files changed, 161 insertions(+), 47 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 328e1f0faa..0ab4e7ab00 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -72,7 +72,9 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _numNoReplyDomainCheckIns(0), _assignmentServerSocket(NULL), _checkInPacket(NULL), - _numBytesCheckInPacket(0) + _numBytesCheckInPacket(0), + _publicAddress(), + _publicPort(0) { } @@ -153,6 +155,12 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat 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; + } } } @@ -298,6 +306,100 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo _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; @@ -329,56 +431,62 @@ void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) { printedDomainServerIP = true; } - // 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) + + 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 + 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; - - int numHeaderBytes = populateTypeAndVersion(packetPosition, nodePacketType); - packetPosition += numHeaderBytes; - - *(packetPosition++) = _ownerType; - - if (assignmentUUID) { - // if we've got an assignment UUID to send add that here - memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID); - packetPosition += NUM_BYTES_RFC4122_UUID; + + _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; + + int numHeaderBytes = populateTypeAndVersion(packetPosition, nodePacketType); + packetPosition += numHeaderBytes; + + *(packetPosition++) = _ownerType; + + if (assignmentUUID) { + // if we've got an assignment UUID to send add that here + memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID); + packetPosition += NUM_BYTES_RFC4122_UUID; + } + + 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; } - packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket), - getLocalAddress(), - htons(_nodeSocket.getListeningPort())); + _nodeSocket.send(_domainIP.toString().toLocal8Bit().constData(), _domainPort, _checkInPacket, _numBytesCheckInPacket); - // 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; + // increment the count of un-replied check-ins + _numNoReplyDomainCheckIns++; } - - _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) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 8d2bd16cae..69d6e428a9 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -153,6 +153,9 @@ private: void addNodeToList(Node* newNode); + void sendSTUNRequest(); + void processSTUNResponse(unsigned char* packetData, size_t dataBytes); + QString _domainHostname; QHostAddress _domainIP; unsigned short _domainPort; @@ -169,6 +172,8 @@ private: sockaddr* _assignmentServerSocket; uchar* _checkInPacket; int _numBytesCheckInPacket; + QHostAddress _publicAddress; + uint16_t _publicPort; void handlePingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 19efd7bd5a..a1320e84b8 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -38,7 +38,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { bool packetVersionMatch(unsigned char* packetHeader) { // currently this just checks if the version in the packet matches our return from versionForPacketType // may need to be expanded in the future for types and versions that take > than 1 byte - if (packetHeader[1] == versionForPacketType(packetHeader[0])) { + if (packetHeader[1] == versionForPacketType(packetHeader[0]) || packetHeader[0] == PACKET_TYPE_STUN_RESPONSE) { return true; } else { qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]); diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 254f2f74fc..2c4172ee55 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -14,6 +14,7 @@ typedef char PACKET_TYPE; const PACKET_TYPE PACKET_TYPE_UNKNOWN = 0; +const PACKET_TYPE PACKET_TYPE_STUN_RESPONSE = 1; const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D'; const PACKET_TYPE PACKET_TYPE_PING = 'P'; const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R'; From 224b0d9671cef9b3fc0639e3a151d8ab34ee8f83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 16:27:13 -0700 Subject: [PATCH 02/21] domain server accepts custom public address from node --- domain-server/src/DomainServer.cpp | 31 +++++++++----------------- libraries/shared/src/NodeList.cpp | 22 ++++++++++++------ libraries/shared/src/PacketHeaders.cpp | 5 +++++ 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 270608d07c..9e375e7d87 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -480,7 +480,8 @@ int DomainServer::run() { unsigned char* currentBufferPos; unsigned char* startPointer; - sockaddr_in nodePublicAddress, nodeLocalAddress, replyDestinationSocket; + sockaddr_in senderAddress, nodePublicAddress, nodeLocalAddress; + nodePublicAddress.sin_family = AF_INET; nodeLocalAddress.sin_family = AF_INET; in_addr_t serverLocalAddress = getLocalAddress(); @@ -507,7 +508,7 @@ int DomainServer::run() { gettimeofday(&startTime, NULL); while (true) { - while (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) && + while (nodeList->getNodeSocket()->receive((sockaddr *)&senderAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) { // this is an RFD or domain list request packet, and there is a version match @@ -515,19 +516,14 @@ int DomainServer::run() { int numBytesSenderHeader = numBytesForPacketHeader(packetData); nodeType = *(packetData + numBytesSenderHeader); - int numBytesSocket = unpackSocket(packetData + numBytesSenderHeader + sizeof(NODE_TYPE), - (sockaddr*) &nodeLocalAddress); - replyDestinationSocket = nodePublicAddress; + int packetIndex = numBytesSenderHeader + sizeof(NODE_TYPE) + NUM_BYTES_RFC4122_UUID; - // check the node public address - // if it matches our local address - // or if it's the loopback address we're on the same box - if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress || - nodePublicAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { - - nodePublicAddress.sin_addr.s_addr = 0; - } + int numBytesPrivateSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodePublicAddress); + packetIndex += numBytesPrivateSocket; + + int numBytesPublicSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodeLocalAddress); + packetIndex += numBytesPublicSocket; const char STATICALLY_ASSIGNED_NODES[3] = { NODE_TYPE_AUDIO_MIXER, @@ -568,12 +564,7 @@ int DomainServer::run() { currentBufferPos = broadcastPacket + numHeaderBytes; startPointer = currentBufferPos; - int numBytesUUID = (nodeType == NODE_TYPE_AUDIO_MIXER || nodeType == NODE_TYPE_AVATAR_MIXER) - ? NUM_BYTES_RFC4122_UUID - : 0; - - unsigned char* nodeTypesOfInterest = packetData + numBytesSenderHeader + numBytesUUID + - sizeof(NODE_TYPE) + numBytesSocket + sizeof(unsigned char); + unsigned char* nodeTypesOfInterest = packetData + packetIndex + sizeof(unsigned char); int numInterestTypes = *(nodeTypesOfInterest - 1); if (numInterestTypes > 0) { @@ -599,7 +590,7 @@ int DomainServer::run() { currentBufferPos += packNodeId(currentBufferPos, checkInNode->getNodeID()); // send the constructed list back to this node - nodeList->getNodeSocket()->send((sockaddr*)&replyDestinationSocket, + nodeList->getNodeSocket()->send((sockaddr*)&senderAddress, broadcastPacket, (currentBufferPos - startPointer) + numHeaderBytes); } diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 0ab4e7ab00..1a0167ee59 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -444,7 +444,8 @@ void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) { // 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 + sizeof(uint16_t) + IP_ADDRESS_BYTES + numBytesNodesOfInterest + sizeof(unsigned char); + NUM_BYTES_RFC4122_UUID + (2 * (sizeof(uint16_t) + IP_ADDRESS_BYTES)) + + numBytesNodesOfInterest + sizeof(unsigned char); _checkInPacket = new unsigned char[numPacketBytes]; unsigned char* packetPosition = _checkInPacket; @@ -453,17 +454,24 @@ void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) { ? PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY : PACKET_TYPE_DOMAIN_LIST_REQUEST; - int numHeaderBytes = populateTypeAndVersion(packetPosition, nodePacketType); - packetPosition += numHeaderBytes; + packetPosition += populateTypeAndVersion(packetPosition, nodePacketType); *(packetPosition++) = _ownerType; - if (assignmentUUID) { - // if we've got an assignment UUID to send add that here - memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID); - packetPosition += NUM_BYTES_RFC4122_UUID; + 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())); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index a1320e84b8..8075099164 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -30,6 +30,11 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_VOXEL_STATS: return 2; + + case PACKET_TYPE_DOMAIN_LIST_REQUEST: + case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY: + return 1; + default: return 0; } From 747175311f1303087167f833c8dd01a357d08d96 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 16:37:24 -0700 Subject: [PATCH 03/21] handle stun response in assigned clients --- assignment-client/src/Agent.cpp | 3 ++- assignment-client/src/audio/AudioMixer.cpp | 5 ++--- domain-server/src/DomainServer.cpp | 2 +- libraries/voxel-server-library/src/VoxelServer.cpp | 6 ++++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9cf479b17..86883d94e5 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -186,7 +186,8 @@ void Agent::run() { qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } - while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) { + while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) + && packetVersionMatch(receivedData)) { if (!firstDomainCheckIn && receivedData[0] == PACKET_TYPE_DOMAIN) { firstDomainCheckIn = true; } diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 2e54988eec..30c59fa6f1 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -399,9 +399,8 @@ void AudioMixer::run() { // give the new audio data to the matching injector node nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes); - } else if (packetData[0] == PACKET_TYPE_PING || packetData[0] == PACKET_TYPE_DOMAIN) { - - // If the packet is a ping, let processNodeData handle it. + } else { + // let processNodeData handle it. nodeList->processNodeData(nodeAddress, packetData, receivedBytes); } } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 9e375e7d87..889e99a748 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -614,7 +614,7 @@ int DomainServer::run() { int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT); int numAssignmentBytes = assignmentToDeploy->packToBuffer(broadcastPacket + numHeaderBytes); - nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress, + nodeList->getNodeSocket()->send((sockaddr*) &senderAddress, broadcastPacket, numHeaderBytes + numAssignmentBytes); } diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index f02069af2e..91c8f5b71a 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -398,8 +398,10 @@ void VoxelServer::run() { nodeData->initializeVoxelSendThread(this); } - } else if (packetData[0] == PACKET_TYPE_PING) { - // If the packet is a ping, let processNodeData handle it. + } else if (packetData[0] == PACKET_TYPE_PING + || packetData[0] == PACKET_TYPE_DOMAIN + || packetData[0] == PACKET_TYPE_STUN_RESPONSE) { + // let processNodeData handle it. NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); } else if (packetData[0] == PACKET_TYPE_DOMAIN) { NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); From e40ab5d13f4b846ed9a1c1a632d3a81e43b3e78e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 16:52:05 -0700 Subject: [PATCH 04/21] add debug of Node's local address --- libraries/shared/src/Node.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 01002a3d61..abdeac5e2c 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -152,10 +152,11 @@ QDebug operator<<(QDebug debug, const Node &node) { char publicAddressBuffer[16] = {'\0'}; unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket()); - //char localAddressBuffer[16] = {'\0'}; - //unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.localSocket); + char localAddressBuffer[16] = {'\0'}; + unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.getLocalSocket()); debug << "#" << node.getNodeID() << node.getTypeName() << node.getType(); debug.nospace() << publicAddressBuffer << ":" << publicAddressPort; + debug.nospace() << " / " << localAddressBuffer << ":" << localAddressPort; return debug.nospace(); } From 330e78920a96a4dcfd6cfa07299e06a758ff659a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 17:06:39 -0700 Subject: [PATCH 05/21] use Qt to query interfaces for correct local address --- libraries/shared/src/UDPSocket.cpp | 52 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 68eb2ad82e..73849847e4 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -22,6 +22,8 @@ #endif #include +#include +#include #include "Logging.h" #include "UDPSocket.h" @@ -88,35 +90,35 @@ void copySocketToEmptySocketPointer(sockaddr** destination, const sockaddr* sour } int getLocalAddress() { - // get this node's local address so we can pass that to DS - struct ifaddrs* ifAddrStruct = NULL; - struct ifaddrs* ifa = NULL; - int family; - int localAddress = 0; - -#ifndef _WIN32 - getifaddrs(&ifAddrStruct); - - for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { - family = ifa->ifa_addr->sa_family; - if (family == AF_INET) { - localAddress = ((sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; + static int localAddress = 0; + + if (localAddress == 0) { + foreach(const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { + if (interface.flags() & QNetworkInterface::IsUp + && interface.flags() & QNetworkInterface::IsRunning + && interface.flags() & ~QNetworkInterface::IsLoopBack) { + // we've decided that this is the active NIC + // enumerate it's addresses to grab the IPv4 address + foreach(const QNetworkAddressEntry &entry, interface.addressEntries()) { + // make sure it's an IPv4 address that isn't the loopback + if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { + qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData()); + + // set our localAddress and break out + localAddress = htonl(entry.ip().toIPv4Address()); + break; + } + } + } + + if (localAddress != 0) { + break; + } } } - freeifaddrs(ifAddrStruct); -#else - // Get the local hostname - char szHostName[255]; - gethostname(szHostName, 255); - struct hostent *host_entry; - host_entry = gethostbyname(szHostName); - char * szLocalIP; - szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); - localAddress = inet_addr(szLocalIP); -#endif - + // return the looked up local address return localAddress; } From 849e5817ecdbbd3905b47d5c70ffdab2d66b73a0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 17:27:16 -0700 Subject: [PATCH 06/21] remove a couple of spaces --- libraries/shared/src/NodeList.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 1a0167ee59..2825a88380 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -117,8 +117,6 @@ void NodeList::setDomainHostname(const QString& domainHostname) { _domainIP.clear(); notifyDomainChanged(); } - - } void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) { From a4be44c2c5174219b0d335e6a034bd8597a6b715 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 17:28:42 -0700 Subject: [PATCH 07/21] remove the injector target --- CMakeLists.txt | 1 - injector/CMakeLists.txt | 22 ---- injector/src/main.cpp | 244 ---------------------------------------- 3 files changed, 267 deletions(-) delete mode 100644 injector/CMakeLists.txt delete mode 100644 injector/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 279f6a6776..7964413d2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(animation-server) add_subdirectory(assignment-client) add_subdirectory(domain-server) add_subdirectory(interface) -add_subdirectory(injector) add_subdirectory(pairing-server) add_subdirectory(space-server) add_subdirectory(voxel-edit) \ No newline at end of file diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt deleted file mode 100644 index ae9ed3d8ad..0000000000 --- a/injector/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(ROOT_DIR ..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") - -set(TARGET_NAME injector) - -include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME} TRUE) - -# set up the external glm library -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - -# link the shared hifi library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/injector/src/main.cpp b/injector/src/main.cpp deleted file mode 100644 index 9caad19e60..0000000000 --- a/injector/src/main.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// -// main.cpp -// Audio Injector -// -// Created by Leonardo Murillo on 3/5/13. -// Copyright (c) 2013 Leonardo Murillo. All rights reserved. -// - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15; - -const int DEFAULT_INJECTOR_VOLUME = 0xFF; - -enum { - INJECTOR_POSITION_X, - INJECTOR_POSITION_Y, - INJECTOR_POSITION_Z, - INJECTOR_YAW -}; - -// Command line parameter defaults -bool shouldLoopAudio = true; -bool hasInjectedAudioOnce = false; -float sleepIntervalMin = 1.00; -float sleepIntervalMax = 2.00; -char *sourceAudioFile = NULL; -const char *allowedParameters = ":sc::a::f::t::r:l"; -float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; -unsigned char volume = DEFAULT_INJECTOR_VOLUME; -float triggerDistance = 0.0f; -float radius = 0.0f; -bool wantsLocalDomain = false; - - -void usage(void) { - std::cout << "High Fidelity - Interface audio injector" << std::endl; - std::cout << " -s Single play mode. If not specified will default to constant loop." << std::endl; - std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; - std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; - std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; - std::cout << " -t FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; - std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl; - std::cout << " -l Local domain mode." << std::endl; -} - -bool processParameters(int parameterCount, char* parameterData[]) { - int p; - while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { - switch (p) { - case 's': - ::shouldLoopAudio = false; - std::cout << "[DEBUG] Single play mode enabled" << std::endl; - break; - case 'f': - ::sourceAudioFile = optarg; - std::cout << "[DEBUG] Opening file: " << sourceAudioFile << std::endl; - break; - case 'c': - { - std::istringstream ss(optarg); - std::string token; - - int i = 0; - while (std::getline(ss, token, ',')) { - ::floatArguments[i] = atof(token.c_str()); - ++i; - if (i == 4) { - break; - } - } - - break; - } - case 'a': - ::volume = atoi(optarg); - std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; - break; - case 't': - ::triggerDistance = atof(optarg); - std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; - break; - case 'r': - ::radius = atof(optarg); - std::cout << "[DEBUG] Injector radius: " << optarg << std::endl; - break; - case 'l': - ::wantsLocalDomain = true; - break; - default: - usage(); - return false; - } - } - return true; -}; - -void createAvatarDataForNode(Node* node) { - if (!node->getLinkedData()) { - node->setLinkedData(new AvatarData(node)); - } -} - -int main(int argc, char* argv[]) { - - // new seed for random audio sleep times - srand(time(0)); - - int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1)); - - if (processParameters(argc, argv)) { - if (::sourceAudioFile == NULL) { - std::cout << "[FATAL] Source audio file not specified" << std::endl; - exit(-1); - } else { - AudioInjector injector(sourceAudioFile); - - // create an NodeList instance to handle communication with other nodes - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT); - - if (::wantsLocalDomain) { - printf("Local Domain MODE!\n"); - nodeList->setDomainIPToLocalhost(); - } - - // start the node list thread that will kill off nodes when they stop talking - nodeList->startSilentNodeRemovalThread(); - - injector.setPosition(glm::vec3(::floatArguments[INJECTOR_POSITION_X], - ::floatArguments[INJECTOR_POSITION_Y], - ::floatArguments[INJECTOR_POSITION_Z])); - injector.setOrientation(glm::quat(glm::vec3(0.0f, ::floatArguments[INJECTOR_YAW], 0.0f))); - injector.setVolume(::volume); - - if (::radius > 0) { - // if we were passed a cube side length, give that to the injector - injector.setRadius(::radius); - } - - // register the callback for node data creation - nodeList->linkedDataCreateCallback = createAvatarDataForNode; - - timeval lastSend = {}; - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO); - unsigned char* broadcastPacket = new unsigned char[numBytesPacketHeader]; - - timeval lastDomainServerCheckIn = {}; - - sockaddr senderAddress; - ssize_t bytesReceived; - unsigned char incomingPacket[MAX_PACKET_SIZE]; - - // the audio injector needs to know about the avatar mixer and the audio mixer - const char INJECTOR_NODES_OF_INTEREST[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER}; - - int bytesNodesOfInterest = (::triggerDistance > 0) - ? sizeof(INJECTOR_NODES_OF_INTEREST) - : sizeof(INJECTOR_NODES_OF_INTEREST) - 1; - - NodeList::getInstance()->setNodeTypesOfInterest(INJECTOR_NODES_OF_INTEREST, bytesNodesOfInterest); - - while (true) { - // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed - if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { - gettimeofday(&lastDomainServerCheckIn, NULL); - NodeList::getInstance()->sendDomainServerCheckIn(); - } - - while (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived) && - packetVersionMatch(incomingPacket)) { - switch (incomingPacket[0]) { - case PACKET_TYPE_BULK_AVATAR_DATA: // this is the positional data for other nodes - // pass that off to the nodeList processBulkNodeData method - nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived); - break; - default: - // have the nodeList handle list of nodes from DS, replies from other nodes, etc. - nodeList->processNodeData(&senderAddress, incomingPacket, bytesReceived); - break; - } - } - - if (::triggerDistance) { - if (!injector.isInjectingAudio()) { - // enumerate the other nodes to decide if one is close enough that we should inject - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - AvatarData* avatarData = (AvatarData*) node->getLinkedData(); - - if (avatarData) { - glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition(); - - if (glm::dot(tempVector, tempVector) <= ::triggerDistance) { - // use the AudioInjectionManager to thread this injector - AudioInjectionManager::threadInjector(&injector); - } - } - } - } - - // find the current avatar mixer - Node* avatarMixer = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); - - // make sure we actually have an avatar mixer with an active socket - if (avatarMixer && avatarMixer->getActiveSocket() != NULL - && (usecTimestampNow() - usecTimestamp(&lastSend) > AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS)) { - - // update the lastSend timeval to the current time - gettimeofday(&lastSend, NULL); - - // use the UDPSocket instance attached to our node list to ask avatar mixer for a list of avatars - nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(), - broadcastPacket, - numBytesPacketHeader); - } - } else { - if (!injector.isInjectingAudio() && (::shouldLoopAudio || !::hasInjectedAudioOnce)) { - // use the AudioInjectionManager to thread this injector - AudioInjectionManager::threadInjector(&injector); - ::hasInjectedAudioOnce = true; - } - } - } - - // stop the node list's threads - nodeList->stopSilentNodeRemovalThread(); - } - } -} - From 7de88898e1b4355ef2b6e59de02716a6c11f6ce7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 17:51:32 -0700 Subject: [PATCH 08/21] activate appropriate socket after receiving ping reply --- domain-server/src/DomainServer.cpp | 13 +--- interface/src/Audio.cpp | 121 ++++++++++++++--------------- libraries/shared/src/Node.cpp | 2 + libraries/shared/src/NodeList.cpp | 42 +++++----- libraries/shared/src/NodeList.h | 2 + 5 files changed, 88 insertions(+), 92 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 889e99a748..3736b77e03 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -484,8 +484,6 @@ int DomainServer::run() { nodePublicAddress.sin_family = AF_INET; nodeLocalAddress.sin_family = AF_INET; - in_addr_t serverLocalAddress = getLocalAddress(); - nodeList->startSilentNodeRemovalThread(); if (!_staticAssignmentFile.exists() || _voxelServerConfig) { @@ -628,20 +626,11 @@ int DomainServer::run() { qDebug() << "Received a create assignment -" << *createAssignment << "\n"; - // check the node public address - // if it matches our local address - // or if it's the loopback address we're on the same box - if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress || - nodePublicAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { - - nodePublicAddress.sin_addr.s_addr = 0; - } - // make sure we have a matching node with the UUID packed with the assignment // if the node has sent no types of interest, assume they want nothing but their own ID back for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() - && socketMatch((sockaddr*) &nodePublicAddress, node->getPublicSocket()) + && socketMatch((sockaddr*) &senderAddress, node->getPublicSocket()) && ((Assignment*) node->getLinkedData())->getUUID() == createAssignment->getUUID()) { // give the create assignment a new UUID diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bea12af25e..b4866432da 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -106,71 +106,70 @@ 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(); - - int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO); - int leadingBytes = numBytesPacketHeader + sizeof(headPosition) + sizeof(headOrientation); - - // we need the amount of bytes in the buffer + 1 for type - // + 12 for 3 floats for position + float for bearing + 1 attenuation byte - unsigned char dataPacket[MAX_PACKET_SIZE]; - - PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio) + if (audioMixer->getActiveSocket()) { + glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); + glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); + + int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO); + int leadingBytes = numBytesPacketHeader + sizeof(headPosition) + sizeof(headOrientation); + + // we need the amount of bytes in the buffer + 1 for type + // + 12 for 3 floats for position + float for bearing + 1 attenuation byte + unsigned char dataPacket[MAX_PACKET_SIZE]; + + PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio) ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO; - - 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]); + + 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]); + } } + + // memcpy the three float positions + memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); + currentPacketPtr += (sizeof(headPosition)); + + // memcpy our orientation + memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); + currentPacketPtr += sizeof(headOrientation); + + // 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); + + interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + + leadingBytes); + } else { + nodeList->pingPublicAndLocalSocketsForInactiveNode(audioMixer); } - - // memcpy the three float positions - memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); - currentPacketPtr += (sizeof(headPosition)); - - // memcpy our orientation - memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); - currentPacketPtr += sizeof(headOrientation); - - // 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((sockaddr*) &audioSocket, - dataPacket, - 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 abdeac5e2c..0cef53182d 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -106,10 +106,12 @@ const char* Node::getTypeName() const { } void Node::activateLocalSocket() { + qDebug() << "Activating local socket for node" << *this << "\n"; _activeSocket = _localSocket; } void Node::activatePublicSocket() { + qDebug() << "Activating public socket for node" << *this << "\n"; _activeSocket = _publicSocket; } diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 2825a88380..03505aba8e 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -143,13 +143,16 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat break; } case PACKET_TYPE_PING: { - char pingPacket[dataBytes]; - memcpy(pingPacket, packetData, dataBytes); - populateTypeAndVersion((unsigned char*) pingPacket, PACKET_TYPE_PING_REPLY); - _nodeSocket.send(senderAddress, pingPacket, dataBytes); + // 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 + handlePingReply(senderAddress); + + // set the ping time for this node for stat collection timePingReply(senderAddress, packetData); break; } @@ -553,6 +556,22 @@ void NodeList::sendAssignment(Assignment& assignment) { _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, ¤tTime, 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(); @@ -569,25 +588,10 @@ Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, c // we didn't have this node, so add them Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId); - if (socketMatch(publicSocket, localSocket)) { - // likely debugging scenario with two nodes on local network - // set the node active right away - newNode->activatePublicSocket(); - } - - if (newNode->getType() == NODE_TYPE_VOXEL_SERVER || - newNode->getType() == NODE_TYPE_AVATAR_MIXER || - newNode->getType() == NODE_TYPE_AUDIO_MIXER) { - // this is currently the cheat we use to talk directly to our test servers on EC2 - // to be removed when we have a proper identification strategy - newNode->activatePublicSocket(); - } - 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 diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 69d6e428a9..ec4cf0978f 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -112,6 +112,8 @@ public: void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); + void pingPublicAndLocalSocketsForInactiveNode(Node* node) const; + Node* nodeWithAddress(sockaddr *senderAddress); Node* nodeWithID(uint16_t nodeID); From 012fccc72e328093047a413a847bc23a53477d55 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 16 Oct 2013 18:01:15 -0700 Subject: [PATCH 09/21] send ping to AvM and VS for socket activation --- interface/src/Application.cpp | 2 +- libraries/shared/src/NodeList.cpp | 35 ++++++++++++++++++------------- libraries/shared/src/NodeList.h | 2 +- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f9424500a7..c40cc2e81e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -500,7 +500,7 @@ void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_ if (nodeTypes[i] == NODE_TYPE_VOXEL_SERVER && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { continue; } - + // Perform the broadcast for one type int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(broadcastData, dataBytes, & nodeTypes[i], 1); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 03505aba8e..7de25d2af1 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -150,7 +150,7 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat } case PACKET_TYPE_PING_REPLY: { // activate the appropriate socket for this node, if not yet updated - handlePingReply(senderAddress); + activateSocketFromPingReply(senderAddress); // set the ping time for this node for stat collection timePingReply(senderAddress, packetData); @@ -625,25 +625,32 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt 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 && memchr(nodeTypes, node->getType(), numNodeTypes)) { - // we know which socket is good for this node, send there - _nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes); - ++n; + 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::handlePingReply(sockaddr *nodeAddress) { +void NodeList::activateSocketFromPingReply(sockaddr *nodeAddress) { for(NodeList::iterator node = begin(); node != end(); node++) { - // 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; + 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; + } } } } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index ec4cf0978f..7a2e8a16c6 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -177,7 +177,7 @@ private: QHostAddress _publicAddress; uint16_t _publicPort; - void handlePingReply(sockaddr *nodeAddress); + void activateSocketFromPingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); std::vector _hooks; From fa146e302d10d1e83850a0fdcceea42f2c2cd9a8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 11:49:41 -0700 Subject: [PATCH 10/21] remove 16-bit node IDs and replace with UUIDs --- assignment-client/src/audio/AudioMixer.cpp | 334 ++++--- .../src/audio/AvatarAudioRingBuffer.h | 4 +- assignment-client/src/avatars/AvatarMixer.cpp | 20 +- assignment-client/src/main.cpp | 2 + domain-server/src/DomainServer.cpp | 47 +- domain-server/src/DomainServer.h | 4 +- interface/src/Application.cpp | 108 +-- interface/src/Application.h | 5 +- interface/src/Audio.cpp | 51 +- interface/src/Audio.h | 11 - interface/src/Menu.cpp | 15 - interface/src/Menu.h | 3 - interface/src/VoxelPacketProcessor.cpp | 4 +- interface/src/VoxelSystem.cpp | 17 +- interface/src/avatar/Avatar.cpp | 12 +- interface/src/avatar/Head.cpp | 11 +- libraries/audio/src/AudioInjector.cpp | 13 +- libraries/audio/src/AudioInjector.h | 3 - .../audio/src/InjectedAudioRingBuffer.cpp | 7 +- libraries/audio/src/InjectedAudioRingBuffer.h | 2 - .../audio/src/PositionalAudioRingBuffer.cpp | 54 +- .../audio/src/PositionalAudioRingBuffer.h | 7 - libraries/avatars/src/AvatarData.cpp | 19 +- libraries/avatars/src/AvatarData.h | 4 +- libraries/shared/NodeList.cpp | 873 ++++++++++++++++++ libraries/shared/src/Assignment.cpp | 1 + libraries/shared/src/Assignment.h | 1 - libraries/shared/src/Node.cpp | 17 +- libraries/shared/src/Node.h | 9 +- libraries/shared/src/NodeList.cpp | 128 +-- libraries/shared/src/NodeList.h | 18 +- libraries/shared/src/UUID.h | 2 + .../src/VoxelNodeData.cpp | 4 +- .../src/VoxelSendThread.cpp | 6 +- .../src/VoxelSendThread.h | 4 +- .../voxel-server-library/src/VoxelServer.cpp | 19 +- libraries/voxels/src/JurisdictionListener.cpp | 6 +- libraries/voxels/src/JurisdictionMap.h | 4 +- libraries/voxels/src/JurisdictionSender.cpp | 10 +- libraries/voxels/src/JurisdictionSender.h | 2 +- .../voxels/src/VoxelEditPacketSender.cpp | 26 +- libraries/voxels/src/VoxelEditPacketSender.h | 10 +- libraries/voxels/src/VoxelNode.cpp | 2 +- libraries/voxels/src/VoxelTree.cpp | 4 +- libraries/voxels/src/VoxelTree.h | 2 +- 45 files changed, 1295 insertions(+), 610 deletions(-) create mode 100644 libraries/shared/NodeList.cpp diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 30c59fa6f1..b324bab245 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #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); diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index cfb6d7717c..a3e39073de 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -12,9 +12,11 @@ #include #include +#include + #include "PositionalAudioRingBuffer.h" -typedef std::map TwoPoleNodeMap; +typedef std::map TwoPoleNodeMap; class AvatarAudioRingBuffer : public PositionalAudioRingBuffer { public: diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 5c7e47a42a..cdbefdf73d 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #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); } } diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 03578c4e8a..7597ea47f5 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -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 diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 3736b77e03..240befe800 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -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, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 540ca67acd..205d9e8f6e 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -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(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c40cc2e81e..c297f771ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -54,7 +54,7 @@ #include #include #include - +#include #include #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; } diff --git a/interface/src/Application.h b/interface/src/Application.h index 595f337bf5..0aae683844 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -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); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index b4866432da..152ce8d74b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -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()); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 7c66c7e375..6dad16f366 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -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 _listenSources; - // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index f9479865c6..f3bae87d4c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -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"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 81d213c026..86e40ee928 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -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"; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index e33f377edc..58c0f850d5 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -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); } } } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 574615d113..278bc51454 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -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 { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9c755a24c1..2e082a7369 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -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(); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 452037f436..b6be6cf1d3 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -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; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e3b137fe4d..d7fd003515 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -10,8 +10,10 @@ #include #include +#include #include #include +#include #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); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 8847ce14b9..be265fe57f 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -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; diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 7e93c7716c..3d94d63579 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -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)); diff --git a/libraries/audio/src/InjectedAudioRingBuffer.h b/libraries/audio/src/InjectedAudioRingBuffer.h index e1df9ac5b9..28284cf404 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.h +++ b/libraries/audio/src/InjectedAudioRingBuffer.h @@ -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__) */ diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 9980b48a3e..21f6ac2dc5 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -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; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index b43cd60660..1cd0751e9b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -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 _listenSources; }; #endif /* defined(__hifi__PositionalAudioRingBuffer__) */ diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 46aad2d86f..e3872ae2b3 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -13,9 +13,10 @@ #include #include #include +#include +#include #include "AvatarData.h" -#include 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; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index f3ccab1504..1914ae0d61 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -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; diff --git a/libraries/shared/NodeList.cpp b/libraries/shared/NodeList.cpp new file mode 100644 index 0000000000..39e3cf9578 --- /dev/null +++ b/libraries/shared/NodeList.cpp @@ -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 +#include +#include +#include + +#include +#include + +#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 +#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, ¤tTime, 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(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); + } +} diff --git a/libraries/shared/src/Assignment.cpp b/libraries/shared/src/Assignment.cpp index 6a7f62c91b..83f1e4087c 100644 --- a/libraries/shared/src/Assignment.cpp +++ b/libraries/shared/src/Assignment.cpp @@ -8,6 +8,7 @@ #include "PacketHeaders.h" #include "SharedUtil.h" +#include "UUID.h" #include diff --git a/libraries/shared/src/Assignment.h b/libraries/shared/src/Assignment.h index cc528e9bd4..749622db46 100644 --- a/libraries/shared/src/Assignment.h +++ b/libraries/shared/src/Assignment.h @@ -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 diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index 0cef53182d..9d9c9e9ae4 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -23,19 +23,9 @@ #include -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(); diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index 2de75bcec1..1a204f569b 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -19,13 +19,14 @@ #endif #include +#include #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; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 7de25d2af1..a448d83b3d 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -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); diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 7a2e8a16c6..ff931dfe8e 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -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; diff --git a/libraries/shared/src/UUID.h b/libraries/shared/src/UUID.h index 985f44ae7b..cacadf5a04 100644 --- a/libraries/shared/src/UUID.h +++ b/libraries/shared/src/UUID.h @@ -11,6 +11,8 @@ #include +const int NUM_BYTES_RFC4122_UUID = 16; + QString uuidStringWithoutCurlyBraces(const QUuid& uuid); #endif /* defined(__hifi__UUID__) */ diff --git a/libraries/voxel-server-library/src/VoxelNodeData.cpp b/libraries/voxel-server-library/src/VoxelNodeData.cpp index 811e3bc63a..1995dcc867 100644 --- a/libraries/voxel-server-library/src/VoxelNodeData.cpp +++ b/libraries/voxel-server-library/src/VoxelNodeData.cpp @@ -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); } diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index ac2c56d2d3..d4cf3b491d 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -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) { diff --git a/libraries/voxel-server-library/src/VoxelSendThread.h b/libraries/voxel-server-library/src/VoxelSendThread.h index 37824abedb..8de3968dcb 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.h +++ b/libraries/voxel-server-library/src/VoxelSendThread.h @@ -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); diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 91c8f5b71a..12a25f035c 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -11,8 +11,9 @@ #include #include -#include -#include +#include +#include +#include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #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); diff --git a/libraries/voxels/src/JurisdictionListener.cpp b/libraries/voxels/src/JurisdictionListener.cpp index ea8bea3a2d..0a14d0809e 100644 --- a/libraries/voxels/src/JurisdictionListener.cpp +++ b/libraries/voxels/src/JurisdictionListener.cpp @@ -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; } } } diff --git a/libraries/voxels/src/JurisdictionMap.h b/libraries/voxels/src/JurisdictionMap.h index a3e96933a9..7b88321d5b 100644 --- a/libraries/voxels/src/JurisdictionMap.h +++ b/libraries/voxels/src/JurisdictionMap.h @@ -12,7 +12,9 @@ #include #include #include + #include +#include 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 NodeToJurisdictionMap; +typedef std::map NodeToJurisdictionMap; #endif /* defined(__hifi__JurisdictionMap__) */ diff --git a/libraries/voxels/src/JurisdictionSender.cpp b/libraries/voxels/src/JurisdictionSender.cpp index df48c27c47..150d04440f 100644 --- a/libraries/voxels/src/JurisdictionSender.cpp +++ b/libraries/voxels/src/JurisdictionSender.cpp @@ -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::iterator nodeIterator = _nodesRequestingJurisdictions.begin(); + for (std::set::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(); diff --git a/libraries/voxels/src/JurisdictionSender.h b/libraries/voxels/src/JurisdictionSender.h index 34f5a9f06f..9678eb15e2 100644 --- a/libraries/voxels/src/JurisdictionSender.h +++ b/libraries/voxels/src/JurisdictionSender.h @@ -35,6 +35,6 @@ protected: private: JurisdictionMap* _jurisdictionMap; - std::set _nodesRequestingJurisdictions; + std::set _nodesRequestingJurisdictions; }; #endif // __shared__JurisdictionSender__ diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 3c435ca0af..a222c903d1 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -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::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) { + for (std::map::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; } diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 97853af74a..7a5713d4c9 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -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 _pendingEditPackets; + std::map _pendingEditPackets; // These are packets that are waiting to be processed because we don't yet know if there are voxel servers int _maxPendingMessages; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index ad83b5a9cf..3f3397fedb 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -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(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3b79722686..6b3623ebe3 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -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); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 318b8fc5eb..2e42269440 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -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), From a5c837b197e333ad869771fd78c686ca49c679bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 11:51:42 -0700 Subject: [PATCH 11/21] fix domain-server check in from assigned clients --- assignment-client/src/audio/AudioMixer.cpp | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 2 +- libraries/voxel-server-library/src/VoxelServer.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index b324bab245..f172ec57a8 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -130,7 +130,7 @@ void AudioMixer::run() { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); - NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData()); + NodeList::getInstance()->sendDomainServerCheckIn(); if (Logging::shouldSendStats() && numStatCollections > 0) { // if we should be sending stats to Logstash send the appropriate average now diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index cdbefdf73d..802df2b2a3 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -120,7 +120,7 @@ void AvatarMixer::run() { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); - NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData()); + NodeList::getInstance()->sendDomainServerCheckIn(); } if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) && diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 12a25f035c..fec946bef9 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -375,7 +375,7 @@ void VoxelServer::run() { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); - NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData()); + NodeList::getInstance()->sendDomainServerCheckIn(); } if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) && From 1c70e09178c6901e8314d5e9fd1111a6b5cc728b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 11:58:52 -0700 Subject: [PATCH 12/21] repairs to audio exchange for new UUID setup --- assignment-client/src/audio/AudioMixer.cpp | 5 +++++ libraries/audio/src/PositionalAudioRingBuffer.cpp | 3 ++- libraries/avatars/src/AvatarData.cpp | 3 --- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index f172ec57a8..c5aa4345fb 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -364,6 +364,11 @@ void AudioMixer::run() { nodeAddress, nodeAddress); + // temp activation of public socket before server ping/reply is setup + if (!avatarNode->getActiveSocket()) { + avatarNode->activatePublicSocket(); + } + nodeList->updateNodeWithData(nodeAddress, packetData, receivedBytes); if (std::isnan(((PositionalAudioRingBuffer *)avatarNode->getLinkedData())->getOrientation().x)) { diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 21f6ac2dc5..4e0c906d3b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "PositionalAudioRingBuffer.h" @@ -27,7 +28,7 @@ PositionalAudioRingBuffer::~PositionalAudioRingBuffer() { int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer); - currentBuffer += sizeof(uint16_t); // the source ID + currentBuffer += NUM_BYTES_RFC4122_UUID; // the source ID currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e3872ae2b3..4fbd5c5c78 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -224,9 +224,6 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* startPosition = sourceBuffer; - // push past the node ID - sourceBuffer += sizeof(uint16_t); - // UUID _uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); sourceBuffer += NUM_BYTES_RFC4122_UUID; From 628a3ba489c5d58c89d2f64f08f0790aaef6398e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 12:10:27 -0700 Subject: [PATCH 13/21] fixes to AvatarMixer for new UUID setup --- assignment-client/src/avatars/AvatarMixer.cpp | 10 +++++----- libraries/avatars/src/AvatarData.cpp | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 802df2b2a3..b515f1400c 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -46,7 +46,7 @@ void attachAvatarDataToNode(Node* newNode) { // 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to // determine which avatars are included in the packet stream // 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful). -void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) { +void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, sockaddr* receiverAddress) { static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE]; static unsigned char avatarDataBuffer[MAX_PACKET_SIZE]; unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0]; @@ -57,7 +57,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) { // send back a packet with other active node data to this node for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && !socketMatch(nodeAddress, node->getActiveSocket())) { + if (node->getLinkedData() && node->getUUID() != receiverUUID) { unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node); int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer; @@ -68,7 +68,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) { } else { packetsSent++; //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket); + nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket); // reset the packet currentBufferPosition = broadcastPacket + numHeaderBytes; @@ -83,7 +83,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) { } packetsSent++; //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength); - nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket); + nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket); } AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { @@ -136,7 +136,7 @@ void AvatarMixer::run() { // parse positional data from an node nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes); case PACKET_TYPE_INJECT_AUDIO: - broadcastAvatarData(nodeList, &nodeAddress); + broadcastAvatarData(nodeList, nodeUUID, &nodeAddress); break; case PACKET_TYPE_AVATAR_URLS: case PACKET_TYPE_AVATAR_FACE_VIDEO: diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4fbd5c5c78..8e6b1b2038 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -224,7 +224,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* startPosition = sourceBuffer; - // UUID + // push past the node session UUID + sourceBuffer += NUM_BYTES_RFC4122_UUID; + + // user UUID _uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID)); sourceBuffer += NUM_BYTES_RFC4122_UUID; From 0ae825d7610835914a629eb92eda2fc746575cf7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 13:01:03 -0700 Subject: [PATCH 14/21] temporary activation of node public socket in VS --- libraries/voxel-server-library/src/VoxelSendThread.cpp | 2 +- libraries/voxel-server-library/src/VoxelServer.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/voxel-server-library/src/VoxelSendThread.cpp b/libraries/voxel-server-library/src/VoxelSendThread.cpp index d4cf3b491d..2cc0277cff 100644 --- a/libraries/voxel-server-library/src/VoxelSendThread.cpp +++ b/libraries/voxel-server-library/src/VoxelSendThread.cpp @@ -83,7 +83,7 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& } else { // just send the voxel packet NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); + nodeData->getPacket(), nodeData->getPacketLength()); } // remember to track our stats nodeData->stats.packetSent(nodeData->getPacketLength()); diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index fec946bef9..1899eec02f 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -393,6 +393,11 @@ void VoxelServer::run() { NODE_TYPE_AGENT, &senderAddress, &senderAddress); + + // temp activation of public socket before server ping/reply is setup + if (!node->getActiveSocket()) { + node->activatePublicSocket(); + } NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength); From 74e66dfd352467c0e4002d0067c85547d306d969 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 13:35:53 -0700 Subject: [PATCH 15/21] push various PACKET_TYPES, repairs to Agent for UUID setup --- assignment-client/src/Agent.cpp | 37 +++++++++++-------- .../audio/src/InjectedAudioRingBuffer.cpp | 4 ++ .../audio/src/PositionalAudioRingBuffer.cpp | 2 +- libraries/shared/src/NodeList.cpp | 10 ++--- libraries/shared/src/PacketHeaders.cpp | 11 +++--- .../voxels/src/VoxelEditPacketSender.cpp | 11 ++++-- 6 files changed, 45 insertions(+), 30 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2215bde60b..3675788616 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -155,35 +155,42 @@ void Agent::run() { NodeList::getInstance()->sendDomainServerCheckIn(); } - if (firstDomainCheckIn) { - // find the audio-mixer in the NodeList so we can inject audio at it - Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); - + // find the audio-mixer in the NodeList so we can inject audio at it + Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + + if (audioMixer && audioMixer->getActiveSocket()) { emit willSendAudioDataCallback(); - if (audioMixer && scriptedAudioInjector.hasSamplesToInject()) { + if (scriptedAudioInjector.hasSamplesToInject()) { int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } - scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getPublicSocket()); + scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket()); // clear out the audio injector so that it doesn't re-send what we just sent scriptedAudioInjector.clear(); } + } else if (audioMixer) { + int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); + if (usecToSleep > 0) { + usleep(usecToSleep); + } - // allow the scripter's call back to setup visual data - emit willSendVisualDataCallback(); - - // release the queue of edit voxel messages. - voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - voxelScripter.getVoxelPacketSender()->process(); - + // don't have an active socket for the audio-mixer, ping it now + NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer); } + // allow the scripter's call back to setup visual data + emit willSendVisualDataCallback(); + + // release the queue of edit voxel messages. + voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); + + // since we're in non-threaded mode, call process so that the packets are sent + voxelScripter.getVoxelPacketSender()->process(); + if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index 3d94d63579..fc5479fa88 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "InjectedAudioRingBuffer.h" @@ -22,6 +23,9 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer() : int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer); + // push past the UUID for this injector + currentBuffer += NUM_BYTES_RFC4122_UUID; + // use parsePositionalData in parent PostionalAudioRingBuffer class to pull common positional data currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 4e0c906d3b..3cb4acbf94 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -28,7 +28,7 @@ PositionalAudioRingBuffer::~PositionalAudioRingBuffer() { int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer); - currentBuffer += NUM_BYTES_RFC4122_UUID; // the source ID + currentBuffer += NUM_BYTES_RFC4122_UUID; // the source UUID currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index a448d83b3d..567bd9b27d 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -589,12 +589,10 @@ void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const { Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket) { 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; - } + for (node = begin(); node != end(); node++) { + if (node->getUUID() == uuid) { + // we already have this node, stop checking + break; } } diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 8075099164..134a811c6b 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -17,24 +17,25 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO: case PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO: - return 1; + return 2; case PACKET_TYPE_HEAD_DATA: - return 9; + return 10; case PACKET_TYPE_AVATAR_URLS: - return 1; + return 2; case PACKET_TYPE_AVATAR_FACE_VIDEO: - return 1; + return 2; case PACKET_TYPE_VOXEL_STATS: return 2; + case PACKET_TYPE_DOMAIN: case PACKET_TYPE_DOMAIN_LIST_REQUEST: case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY: return 1; - + default: return 0; } diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index a222c903d1..99807548b5 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -102,10 +102,15 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch 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 && + if (node->getType() == NODE_TYPE_VOXEL_SERVER && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { - sockaddr* nodeAddress = node->getActiveSocket(); - queuePacketForSending(*nodeAddress, buffer, length); + if (node->getActiveSocket()) { + sockaddr* nodeAddress = node->getActiveSocket(); + queuePacketForSending(*nodeAddress, buffer, length); + } else { + // we don't have an active socket for this node, ping it + nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); + } } } } From d7d8d76b07b899a8598c849f655a2f0f67aa9604 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 13:58:00 -0700 Subject: [PATCH 16/21] fix ping of VS from agent --- .../voxels/src/VoxelEditPacketSender.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 99807548b5..1b987fd2b9 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -89,8 +89,13 @@ bool VoxelEditPacketSender::voxelServersExist() const { 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) { - return true; + if (node->getType() == NODE_TYPE_VOXEL_SERVER) { + if (node->getActiveSocket()) { + return true; + } else { + // we don't have an active socket for this node, ping it + nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); + } } } return false; @@ -102,15 +107,10 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch 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->getType() == NODE_TYPE_VOXEL_SERVER && + if (node->getActiveSocket() && node->getType() == NODE_TYPE_VOXEL_SERVER && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { - if (node->getActiveSocket()) { - sockaddr* nodeAddress = node->getActiveSocket(); - queuePacketForSending(*nodeAddress, buffer, length); - } else { - // we don't have an active socket for this node, ping it - nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); - } + sockaddr* nodeAddress = node->getActiveSocket(); + queuePacketForSending(*nodeAddress, buffer, length); } } } From 8f1135feb74340f511170106ce718697eb6a2724 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 14:35:42 -0700 Subject: [PATCH 17/21] more repairs to Agent and AvatarData for UUID transition --- assignment-client/src/Agent.cpp | 19 ++++++++++------- interface/src/VoxelPacketProcessor.cpp | 1 + libraries/avatars/src/AvatarData.cpp | 21 +------------------ libraries/avatars/src/AvatarData.h | 1 - libraries/shared/src/NodeList.cpp | 2 +- .../voxels/src/VoxelEditPacketSender.cpp | 11 +++++++--- libraries/voxels/src/VoxelEditPacketSender.h | 4 +++- 7 files changed, 25 insertions(+), 34 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 3675788616..a8b085fe0b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -182,14 +182,17 @@ void Agent::run() { NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer); } - // allow the scripter's call back to setup visual data - emit willSendVisualDataCallback(); - - // release the queue of edit voxel messages. - voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); - - // since we're in non-threaded mode, call process so that the packets are sent - voxelScripter.getVoxelPacketSender()->process(); + if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { + // allow the scripter's call back to setup visual data + emit willSendVisualDataCallback(); + + // release the queue of edit voxel messages. + voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); + + // since we're in non-threaded mode, call process so that the packets are sent + voxelScripter.getVoxelPacketSender()->process(); + + } if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 58c0f850d5..7d2c59eeb7 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -50,6 +50,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) { app->_environment.parseData(&senderAddress, packetData, messageLength); } else { + app->_voxels.setDataSourceID(0); app->_voxels.parseData(packetData, messageLength); app->_voxels.setDataSourceID(0); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8e6b1b2038..e9a4034b09 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -54,25 +54,6 @@ AvatarData::~AvatarData() { delete _handData; } -void AvatarData::sendData() { - - // called from Agent visual loop to send data - if (Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER)) { - unsigned char packet[MAX_PACKET_SIZE]; - - unsigned char* endOfPacket = packet; - endOfPacket += populateTypeAndVersion(endOfPacket, PACKET_TYPE_HEAD_DATA); - - QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122(); - memcpy(endOfPacket, rfcUUID.constData(), rfcUUID.size()); - endOfPacket += rfcUUID.size(); - - int numPacketBytes = (endOfPacket - packet) + getBroadcastData(endOfPacket); - - NodeList::getInstance()->getNodeSocket()->send(avatarMixer->getActiveSocket(), packet, numPacketBytes); - } -} - int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { unsigned char* bufferStart = destinationBuffer; @@ -108,7 +89,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // Follow mode info memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); - destinationBuffer += sizeof(NUM_BYTES_RFC4122_UUID); + destinationBuffer += NUM_BYTES_RFC4122_UUID; // Head rotation (NOTE: This needs to become a quaternion to save two bytes) destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1914ae0d61..c621fbbe63 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -126,7 +126,6 @@ public: void setHandData(HandData* handData) { _handData = handData; } public slots: - void sendData(); void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 567bd9b27d..f533ad996c 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -313,7 +313,7 @@ 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 char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io"; const unsigned short STUN_SERVER_PORT = 3478; unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER]; diff --git a/libraries/voxels/src/VoxelEditPacketSender.cpp b/libraries/voxels/src/VoxelEditPacketSender.cpp index 1b987fd2b9..11e4600f6b 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.cpp +++ b/libraries/voxels/src/VoxelEditPacketSender.cpp @@ -107,10 +107,15 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch 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() && node->getType() == NODE_TYPE_VOXEL_SERVER && + if (node->getType() == NODE_TYPE_VOXEL_SERVER && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) { - sockaddr* nodeAddress = node->getActiveSocket(); - queuePacketForSending(*nodeAddress, buffer, length); + if (node->getActiveSocket()) { + sockaddr* nodeAddress = node->getActiveSocket(); + queuePacketForSending(*nodeAddress, buffer, length); + } else { + // we don't have an active socket for this node, ping it + nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node)); + } } } } diff --git a/libraries/voxels/src/VoxelEditPacketSender.h b/libraries/voxels/src/VoxelEditPacketSender.h index 7a5713d4c9..bb54009d1a 100644 --- a/libraries/voxels/src/VoxelEditPacketSender.h +++ b/libraries/voxels/src/VoxelEditPacketSender.h @@ -83,6 +83,8 @@ public: // the default number of pending messages we will store if no voxel servers are available static const int DEFAULT_MAX_PENDING_MESSAGES; + + bool voxelServersExist() const; private: bool _shouldSend; @@ -90,7 +92,7 @@ private: void queuePacketToNodes(unsigned char* buffer, ssize_t length); void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type); void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet - bool voxelServersExist() const; + void processPreServerExistsPackets(); // These are packets which are destined from know servers but haven't been released because they're still too small From 3b4231208af60e4867023e55297ebdc71f5c86f9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 14:41:13 -0700 Subject: [PATCH 18/21] remove firstDomainCheckIn bool that is no longer required --- assignment-client/src/Agent.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index a8b085fe0b..c85eb5e4c1 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -140,8 +140,6 @@ void Agent::run() { int thisFrame = 0; - bool firstDomainCheckIn = false; - while (!_shouldStop) { // if we're not hearing from the domain-server we should stop running @@ -201,10 +199,6 @@ void Agent::run() { while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) && packetVersionMatch(receivedData)) { - if (!firstDomainCheckIn && receivedData[0] == PACKET_TYPE_DOMAIN) { - firstDomainCheckIn = true; - } - NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); } } From 90e189b425b46c738aca7f43371cec59d4dc6b84 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 14:42:07 -0700 Subject: [PATCH 19/21] remove accidentally double saved NodeList.cpp --- libraries/shared/NodeList.cpp | 873 ---------------------------------- 1 file changed, 873 deletions(-) delete mode 100644 libraries/shared/NodeList.cpp diff --git a/libraries/shared/NodeList.cpp b/libraries/shared/NodeList.cpp deleted file mode 100644 index 39e3cf9578..0000000000 --- a/libraries/shared/NodeList.cpp +++ /dev/null @@ -1,873 +0,0 @@ -// -// NodeList.cpp -// hifi -// -// Created by Stephen Birarda on 2/15/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include -#include - -#include -#include - -#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 -#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, ¤tTime, 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(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); - } -} From 4bbb59be72d9d81e33553e325b4e573fc3a7ad3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 14:45:38 -0700 Subject: [PATCH 20/21] fix use of htonl in constant outside function --- libraries/shared/src/NodeList.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index f533ad996c..12ad03e177 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -309,7 +309,7 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo _nodeTypesOfInterest[numNodeTypesOfInterest] = '\0'; } -const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(0x2112A442); +const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442; const int NUM_BYTES_STUN_HEADER = 20; void NodeList::sendSTUNRequest() { @@ -319,6 +319,8 @@ void NodeList::sendSTUNRequest() { unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER]; int packetIndex = 0; + + const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE); // leading zeros + message type const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001); @@ -364,6 +366,8 @@ 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); + const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE); + int attributeStartIndex = NUM_BYTES_STUN_HEADER; if (memcmp(packetData + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH, From 80d2df6a49fb36c3c572b9d8fa9fb370b48677f6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 17 Oct 2013 15:12:34 -0700 Subject: [PATCH 21/21] fix audio ternary indentations --- assignment-client/src/audio/AudioMixer.cpp | 12 ++++++------ interface/src/Audio.cpp | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c5aa4345fb..1b44c2e905 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -278,15 +278,15 @@ void AudioMixer::run() { int16_t* sourceBuffer = otherNodeBuffer->getNextOutput(); int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f) - ? clientSamples - : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + ? clientSamples + : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; int16_t* delayedChannel = (bearingRelativeAngleToSource > 0.0f) - ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL - : clientSamples; + ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL + : clientSamples; int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer() - ? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay - : otherNodeBuffer->getNextOutput() - numSamplesDelay; + ? 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 diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index d0492f3903..0f3b047a3f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -121,8 +121,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o unsigned char dataPacket[MAX_PACKET_SIZE]; PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio) - ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO - : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO; + ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO + : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO; unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, packetType); @@ -245,8 +245,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o if (flangeIndex < 0) { // we need to grab the flange sample from earlier in the buffer flangeFrame = ringBuffer->getNextOutput() != ringBuffer->getBuffer() - ? ringBuffer->getNextOutput() - PACKET_LENGTH_SAMPLES - : ringBuffer->getNextOutput() + RING_BUFFER_LENGTH_SAMPLES - PACKET_LENGTH_SAMPLES; + ? ringBuffer->getNextOutput() - PACKET_LENGTH_SAMPLES + : ringBuffer->getNextOutput() + RING_BUFFER_LENGTH_SAMPLES - PACKET_LENGTH_SAMPLES; flangeIndex = PACKET_LENGTH_SAMPLES_PER_CHANNEL + (s - sampleFlangeDelay); }