diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b8c4629b90..22ed01fd00 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -901,7 +901,7 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha if (canWriteToAssetServer) { - qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(message->getSourceID()); + qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << message->getSourceID(); auto task = new UploadAssetTask(message, senderNode, _filesDirectory, _filesizeLimit); _transferTaskPool.start(task); diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 8af4eec934..34eb138697 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -117,12 +117,13 @@ void AudioMixer::queueAudioPacket(QSharedPointer message, Share void AudioMixer::queueReplicatedAudioPacket(QSharedPointer message) { // make sure we have a replicated node for the original sender of the packet auto nodeList = DependencyManager::get(); - - QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + + // Node ID is now part of user data, since replicated audio packets are non-sourced. + QUuid nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto replicatedNode = nodeList->addOrUpdateNode(nodeID, NodeType::Agent, message->getSenderSockAddr(), message->getSenderSockAddr(), - true, true); + Node::NULL_LOCAL_ID, true, true); replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); // construct a "fake" audio received message from the byte array and packet list information @@ -136,7 +137,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess auto replicatedMessage = QSharedPointer::create(audioData, rewrittenType, versionForPacketType(rewrittenType), - message->getSenderSockAddr(), nodeID); + message->getSenderSockAddr(), Node::NULL_LOCAL_ID); getOrCreateClientData(replicatedNode.data())->queuePacket(replicatedMessage, replicatedNode); } diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 929941c05c..29340f6474 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -74,7 +74,7 @@ SharedNodePointer addOrUpdateReplicatedNode(const QUuid& nodeID, const HifiSockA auto replicatedNode = DependencyManager::get()->addOrUpdateNode(nodeID, NodeType::Agent, senderSockAddr, senderSockAddr, - true, true); + Node::NULL_LOCAL_ID, true, true); replicatedNode->setLastHeardMicrostamp(usecTimestampNow()); @@ -112,8 +112,8 @@ void AvatarMixer::handleReplicatedPacket(QSharedPointer message void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer message) { while (message->getBytesLeftToRead()) { // first, grab the node ID for this replicated avatar + // Node ID is now part of user data, since ReplicatedBulkAvatarPacket is non-sourced. auto nodeID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - // make sure we have an upstream replicated node that matches auto replicatedNode = addOrUpdateReplicatedNode(nodeID, message->getSenderSockAddr()); @@ -127,7 +127,7 @@ void AvatarMixer::handleReplicatedBulkAvatarPacket(QSharedPointer::create(avatarByteArray, PacketType::AvatarData, versionForPacketType(PacketType::AvatarData), - message->getSenderSockAddr(), nodeID); + message->getSenderSockAddr(), Node::NULL_LOCAL_ID); // queue up the replicated avatar data with the client data for the replicated node auto start = usecTimestampNow(); diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 9f24036e92..d78f0aaeb3 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ using SharedAssignmentPointer = QSharedPointer; DomainGatekeeper::DomainGatekeeper(DomainServer* server) : _server(server) { - + initLocalIDManagement(); } void DomainGatekeeper::addPendingAssignedNode(const QUuid& nodeUUID, const QUuid& assignmentUUID, @@ -529,8 +530,10 @@ SharedNodePointer DomainGatekeeper::addVerifiedNodeFromConnectRequest(const Node auto limitedNodeList = DependencyManager::get(); + Node::LocalID newLocalID = findOrCreateLocalID(nodeID); SharedNodePointer newNode = limitedNodeList->addOrUpdateNode(nodeID, nodeConnection.nodeType, - nodeConnection.publicSockAddr, nodeConnection.localSockAddr); + nodeConnection.publicSockAddr, nodeConnection.localSockAddr, + newLocalID); // So that we can send messages to this node at will - we need to activate the correct socket on this node now newNode->activateMatchingOrNewSymmetricSocket(discoveredSocket); @@ -1020,3 +1023,31 @@ void DomainGatekeeper::refreshGroupsCache() { _server->_settingsManager.debugDumpGroupsState(); #endif } + +void DomainGatekeeper::initLocalIDManagement() { + std::uniform_int_distribution sixteenBitRand; + std::random_device randomDevice; + std::default_random_engine engine { randomDevice() }; + _currentLocalID = sixteenBitRand(engine); + // Ensure increment is odd. + _idIncrement = sixteenBitRand(engine) | 1; +} + +Node::LocalID DomainGatekeeper::findOrCreateLocalID(const QUuid& uuid) { + auto existingLocalIDIt = _uuidToLocalID.find(uuid); + if (existingLocalIDIt != _uuidToLocalID.end()) { + return existingLocalIDIt->second; + } + + assert(_localIDs.size() < std::numeric_limits::max() - 2); + + Node::LocalID newLocalID; + do { + newLocalID = _currentLocalID; + _currentLocalID += _idIncrement; + } while (newLocalID == Node::NULL_LOCAL_ID || _localIDs.find(newLocalID) != _localIDs.end()); + + _uuidToLocalID.emplace(uuid, newLocalID); + _localIDs.insert(newLocalID); + return newLocalID; +} diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 09db075e07..8402e58559 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -15,6 +15,7 @@ #define hifi_DomainGatekeeper_h #include +#include #include #include @@ -41,6 +42,8 @@ public: void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); } + Node::LocalID findOrCreateLocalID(const QUuid& uuid); + static void sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr); public slots: void processConnectRequestPacket(QSharedPointer message); @@ -120,6 +123,16 @@ private: void getGroupMemberships(const QString& username); // void getIsGroupMember(const QString& username, const QUuid groupID); void getDomainOwnerFriendsList(); + + // Local ID management. + void initLocalIDManagement(); + using UUIDToLocalID = std::unordered_map ; + using LocalIDs = std::unordered_set; + LocalIDs _localIDs; + UUIDToLocalID _uuidToLocalID; + + Node::LocalID _currentLocalID; + Node::LocalID _idIncrement; }; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b054b5cf8e..ac157979bb 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -593,8 +593,8 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) { if (!PacketTypeEnum::getNonSourcedPackets().contains(headerType)) { // this is a sourced packet - first check if we have a node that matches - QUuid sourceID = NLPacket::sourceIDInHeader(packet); - SharedNodePointer sourceNode = nodeList->nodeWithUUID(sourceID); + Node::LocalID localSourceID = NLPacket::sourceIDInHeader(packet); + SharedNodePointer sourceNode = nodeList->nodeWithLocalID(localSourceID); if (sourceNode) { // unverified DS packets (due to a lack of connection secret between DS + node) @@ -612,14 +612,12 @@ bool DomainServer::isPacketVerified(const udt::Packet& packet) { return nodeList->isPacketVerifiedWithSource(packet, sourceNode.data()); } else { HIFI_FDEBUG("Packet of type" << headerType - << "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceID)); - + << "received from unmatched IP for UUID" << uuidStringWithoutCurlyBraces(sourceNode->getUUID())); return false; } } else { HIFI_FDEBUG("Packet of type" << headerType - << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceID)); - + << "received from unknown node with UUID" << uuidStringWithoutCurlyBraces(sourceNode->getUUID())); return false; } } @@ -683,6 +681,10 @@ void DomainServer::setupNodeListAndAssignments() { } } + // Create our own short session ID. + Node::LocalID serverSessionLocalID = _gatekeeper.findOrCreateLocalID(nodeList->getSessionUUID()); + nodeList->setSessionLocalID(serverSessionLocalID); + if (isMetaverseDomain) { // see if we think we're a temp domain (we have an API key) or a full domain const auto& temporaryDomainKey = DependencyManager::get()->getTemporaryDomainKey(getID()); @@ -1112,7 +1114,8 @@ void DomainServer::handleConnectedNode(SharedNodePointer newNode) { } void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr) { - const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NUM_BYTES_RFC4122_UUID + 2; + const int NUM_DOMAIN_LIST_EXTENDED_HEADER_BYTES = NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + + NUM_BYTES_RFC4122_UUID + NLPacket::NUM_BYTES_LOCALID + 4; // setup the extended header for the domain list packets // this data is at the beginning of each of the domain list packets @@ -1122,7 +1125,9 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif auto limitedNodeList = DependencyManager::get(); extendedHeaderStream << limitedNodeList->getSessionUUID(); + extendedHeaderStream << limitedNodeList->getSessionLocalID(); extendedHeaderStream << node->getUUID(); + extendedHeaderStream << node->getLocalID(); extendedHeaderStream << node->getPermissions(); auto domainListPackets = NLPacketList::create(PacketType::DomainList, extendedHeader); @@ -2841,7 +2846,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) // manually add the replication node to our node list auto node = nodeList->addOrUpdateNode(QUuid::createUuid(), replicationServer.nodeType, replicationServer.sockAddr, replicationServer.sockAddr, - false, direction == Upstream); + Node::NULL_LOCAL_ID, false, direction == Upstream); node->setIsForcedNeverSilent(true); qDebug() << "Adding" << (direction == Upstream ? "upstream" : "downstream") @@ -3141,13 +3146,12 @@ void DomainServer::processNodeDisconnectRequestPacket(QSharedPointer(); - const QUuid& nodeUUID = message->getSourceID(); - - qDebug() << "Received a disconnect request from node with UUID" << nodeUUID; + auto localID = message->getSourceID(); + qDebug() << "Received a disconnect request from node with local ID" << localID; // we want to check what type this node was before going to kill it so that we can avoid sending the RemovedNode // packet to nodes that don't care about this type - auto nodeToKill = limitedNodeList->nodeWithUUID(nodeUUID); + auto nodeToKill = limitedNodeList->nodeWithLocalID(localID); if (nodeToKill) { handleKillNode(nodeToKill); @@ -3415,7 +3419,7 @@ void DomainServer::handleDomainContentReplacementFromURLRequest(QSharedPointer message) { - auto node = DependencyManager::get()->nodeWithUUID(message->getSourceID()); + auto node = DependencyManager::get()->nodeWithLocalID(message->getSourceID()); if (node->getCanReplaceContent()) { handleOctreeFileReplacement(message->readAll()); } diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 122b58c057..0c2883a9a4 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -71,7 +71,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag if (message->getVersion() != versionForPacketType(message->getType())) { static QMultiMap versionDebugSuppressMap; - const QUuid& senderUUID = message->getSourceID(); + const QUuid& senderUUID = sendingNode->getUUID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { qDebug() << "Was stats packet? " << wasStatsPacket; diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 72acc7fcf6..172ec9411a 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -120,8 +120,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // parse sequence number and track it quint16 sequence; message.readPrimitive(&sequence); - SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, - message.getSourceID()); + SequenceNumberStats::ArrivalInfo arrivalInfo = + _incomingSequenceNumberStats.sequenceNumberReceived(sequence, message.getSourceID()); QString codecInPacket = message.readString(); packetReceivedUpdateTimingStats(); @@ -186,7 +186,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { _mismatchedAudioCodecCount = 0; // inform others of the mismatch - auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); + auto sendingNode = DependencyManager::get()->nodeWithLocalID(message.getSourceID()); if (sendingNode) { emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent"; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 7137b8084d..2d4712209d 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -45,6 +45,9 @@ public: const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid); + Node::LocalID getLocalID() const { return _localID; } + void setLocalID(Node::LocalID localID) { _localID = localID; } + QString getHostname() const { return _domainURL.host(); } const QHostAddress& getIP() const { return _sockAddr.getAddress(); } @@ -185,6 +188,7 @@ private: void hardReset(); QUuid _uuid; + Node::LocalID _localID; QUrl _domainURL; HifiSockAddr _sockAddr; QUuid _assignmentUUID; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index d7eb472d65..aaf1b58a0a 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -132,6 +132,16 @@ void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) { } } +Node::LocalID LimitedNodeList::getSessionLocalID() const { + QReadLocker readLock { &_sessionUUIDLock }; + return _sessionLocalID; +} + +void LimitedNodeList::setSessionLocalID(Node::LocalID sessionLocalID) { + QWriteLocker lock { &_sessionUUIDLock }; + _sessionLocalID = sessionLocalID; +} + void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) { NodePermissions originalPermissions = _permissions; @@ -230,13 +240,16 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) { senderString = QString("%1:%2").arg(senderSockAddr.getAddress().toString()).arg(senderSockAddr.getPort()); } } else { - sourceID = NLPacket::sourceIDInHeader(packet); + SharedNodePointer sourceNode = nodeWithLocalID(NLPacket::sourceIDInHeader(packet)); + if (sourceNode) { + sourceID = sourceNode->getUUID(); - hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType); + hasBeenOutput = sourcedVersionDebugSuppressMap.contains(sourceID, headerType); - if (!hasBeenOutput) { - sourcedVersionDebugSuppressMap.insert(sourceID, headerType); - senderString = uuidStringWithoutCurlyBraces(sourceID.toString()); + if (!hasBeenOutput) { + sourcedVersionDebugSuppressMap.insert(sourceID, headerType); + senderString = uuidStringWithoutCurlyBraces(sourceID.toString()); + } } } @@ -289,17 +302,20 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe return true; } } else { - QUuid sourceID = NLPacket::sourceIDInHeader(packet); - + NLPacket::LocalID sourceLocalID = Node::NULL_LOCAL_ID; // check if we were passed a sourceNode hint or if we need to look it up if (!sourceNode) { // figure out which node this is from - SharedNodePointer matchingNode = nodeWithUUID(sourceID); + sourceLocalID = NLPacket::sourceIDInHeader(packet); + + SharedNodePointer matchingNode = nodeWithLocalID(sourceLocalID); sourceNode = matchingNode.data(); } + + QUuid sourceID = sourceNode ? sourceNode->getUUID() : QUuid(); if (!sourceNode && - sourceID == getDomainUUID() && + sourceLocalID == getDomainLocalID() && packet.getSenderSockAddr() == getDomainSockAddr() && PacketTypeEnum::getDomainSourcedPackets().contains(headerType)) { // This is a packet sourced by the domain server @@ -357,7 +373,7 @@ void LimitedNodeList::collectPacketStats(const NLPacket& packet) { void LimitedNodeList::fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth) { if (!PacketTypeEnum::getNonSourcedPackets().contains(packet.getType())) { - packet.writeSourceID(getSessionUUID()); + packet.writeSourceID(getSessionLocalID()); } if (hmacAuth @@ -541,6 +557,13 @@ SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) { return it == _nodeHash.cend() ? SharedNodePointer() : it->second; } +SharedNodePointer LimitedNodeList::nodeWithLocalID(Node::LocalID localID) const { + QReadLocker readLocker(&_nodeMutex); + + LocalIDMapping::const_iterator idIter = _localIDMap.find(localID); + return idIter == _localIDMap.cend() ? nullptr : idIter->second; +} + void LimitedNodeList::eraseAllNodes() { QSet killedNodes; @@ -549,6 +572,8 @@ void LimitedNodeList::eraseAllNodes() { // and then remove them from the hash QWriteLocker writeLocker(&_nodeMutex); + _localIDMap.clear(); + if (_nodeHash.size() > 0) { qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList."; @@ -624,7 +649,7 @@ void LimitedNodeList::handleNodeKill(const SharedNodePointer& node, ConnectionID SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - bool isReplicated, bool isUpstream, + Node::LocalID localID, bool isReplicated, bool isUpstream, const QUuid& connectionSecret, const NodePermissions& permissions) { QReadLocker readLocker(&_nodeMutex); NodeHash::const_iterator it = _nodeHash.find(uuid); @@ -638,6 +663,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t matchingNode->setConnectionSecret(connectionSecret); matchingNode->setIsReplicated(isReplicated); matchingNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); + matchingNode->setLocalID(localID); return matchingNode; } else { @@ -652,6 +678,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t newNode->setIsUpstream(isUpstream || NodeType::isUpstream(nodeType)); newNode->setConnectionSecret(connectionSecret); newNode->setPermissions(permissions); + newNode->setLocalID(localID); // move the newly constructed node to the LNL thread newNode->moveToThread(thread()); @@ -677,6 +704,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t auto oldSoloNode = previousSoloIt->second; + _localIDMap.unsafe_erase(oldSoloNode->getLocalID()); _nodeHash.unsafe_erase(previousSoloIt); handleNodeKill(oldSoloNode); @@ -692,6 +720,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t #else _nodeHash.emplace(newNode->getUUID(), newNodePointer); #endif + _localIDMap.emplace(localID, newNodePointer); readLocker.unlock(); qCDebug(networking) << "Added" << *newNode; @@ -819,6 +848,7 @@ void LimitedNodeList::removeSilentNodes() { if (!node->isForcedNeverSilent() && (usecTimestampNow() - node->getLastHeardMicrostamp()) > (NODE_SILENCE_THRESHOLD_MSECS * USECS_PER_MSEC)) { // call the NodeHash erase to get rid of this node + _localIDMap.unsafe_erase(node->getLocalID()); it = _nodeHash.unsafe_erase(it); killedNodes.insert(node); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index d4517bdcec..05374bbfbb 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -110,6 +110,8 @@ public: Q_ENUM(ConnectionStep); QUuid getSessionUUID() const; void setSessionUUID(const QUuid& sessionUUID); + Node::LocalID getSessionLocalID() const; + void setSessionLocalID(Node::LocalID localID); void setPermissions(const NodePermissions& newPermissions); bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); } @@ -130,6 +132,7 @@ public: virtual bool isDomainServer() const { return true; } virtual QUuid getDomainUUID() const { assert(false); return QUuid(); } + virtual Node::LocalID getDomainLocalID() const { assert(false); return Node::NULL_LOCAL_ID; } virtual HifiSockAddr getDomainSockAddr() const { assert(false); return HifiSockAddr(); } // use sendUnreliablePacket to send an unreliable packet (that you do not need to move) @@ -157,11 +160,12 @@ public: size_t size() const { QReadLocker readLock(&_nodeMutex); return _nodeHash.size(); } SharedNodePointer nodeWithUUID(const QUuid& nodeUUID); + SharedNodePointer nodeWithLocalID(Node::LocalID localID) const; SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, - bool isReplicated = false, bool isUpstream = false, - const QUuid& connectionSecret = QUuid(), + Node::LocalID localID = Node::NULL_LOCAL_ID, bool isReplicated = false, + bool isUpstream = false, const QUuid& connectionSecret = QUuid(), const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS); static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort); @@ -430,6 +434,9 @@ private slots: private: mutable QReadWriteLock _sessionUUIDLock; QUuid _sessionUUID; + using LocalIDMapping = tbb::concurrent_unordered_map; + LocalIDMapping _localIDMap; + Node::LocalID _sessionLocalID { 0 }; }; #endif // hifi_LimitedNodeList_h diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 93274843a6..3355e1cd6b 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -16,7 +16,7 @@ int NLPacket::localHeaderSize(PacketType type) { bool nonSourced = PacketTypeEnum::getNonSourcedPackets().contains(type); bool nonVerified = PacketTypeEnum::getNonVerifiedPackets().contains(type); - qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_RFC4122_UUID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH); + qint64 optionalSize = (nonSourced ? 0 : NUM_BYTES_LOCALID) + ((nonSourced || nonVerified) ? 0 : NUM_BYTES_MD5_HASH); return sizeof(PacketType) + sizeof(PacketVersion) + optionalSize; } int NLPacket::totalHeaderSize(PacketType type, bool isPartOfMessage) { @@ -141,19 +141,22 @@ PacketVersion NLPacket::versionInHeader(const udt::Packet& packet) { return *reinterpret_cast(packet.getData() + headerOffset + sizeof(PacketType)); } -QUuid NLPacket::sourceIDInHeader(const udt::Packet& packet) { +NLPacket::LocalID NLPacket::sourceIDInHeader(const udt::Packet& packet) { int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion); - return QUuid::fromRfc4122(QByteArray::fromRawData(packet.getData() + offset, NUM_BYTES_RFC4122_UUID)); + return *reinterpret_cast(packet.getData() + offset); } QByteArray NLPacket::verificationHashInHeader(const udt::Packet& packet) { - int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; + int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + + sizeof(PacketVersion) + NUM_BYTES_LOCALID; return QByteArray(packet.getData() + offset, NUM_BYTES_MD5_HASH); } QByteArray NLPacket::hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash) { int offset = Packet::totalHeaderSize(packet.isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) - + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + + NUM_BYTES_LOCALID + NUM_BYTES_MD5_HASH; + + // add the packet payload and the connection UUID hash.addData(packet.getData() + offset, packet.getDataSize() - offset); auto hashResult { hash.result() }; return QByteArray((const char*) hashResult.data(), (int) hashResult.size()); @@ -199,11 +202,12 @@ void NLPacket::readSourceID() { } } -void NLPacket::writeSourceID(const QUuid& sourceID) const { +void NLPacket::writeSourceID(LocalID sourceID) const { Q_ASSERT(!PacketTypeEnum::getNonSourcedPackets().contains(_type)); auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion); - memcpy(_packet.get() + offset, sourceID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + + memcpy(_packet.get() + offset, &sourceID, sizeof(sourceID)); _sourceID = sourceID; } @@ -213,7 +217,7 @@ void NLPacket::writeVerificationHash(HMACAuth& hmacAuth) const { !PacketTypeEnum::getNonVerifiedPackets().contains(_type)); auto offset = Packet::totalHeaderSize(isPartOfMessage()) + sizeof(PacketType) + sizeof(PacketVersion) - + NUM_BYTES_RFC4122_UUID; + + NUM_BYTES_LOCALID; QByteArray verificationHash = hashForPacketAndHMAC(*this, hmacAuth); diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index 302598f77c..4103f2068e 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -24,31 +24,29 @@ class NLPacket : public udt::Packet { Q_OBJECT public: // - // | BYTE | BYTE | BYTE | BYTE | + // NLPacket format: // + // | BYTE | BYTE | BYTE | BYTE | // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Packet Type | Version | | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + // | Packet Type | Version | Local Node ID - sourced only | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | | - // | Node UUID - 16 bytes | - // | (ONLY FOR SOURCED PACKETS) | - // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | + // | MD5 Verification - 16 bytes | + // | (ONLY FOR VERIFIED PACKETS) | // | | - // | MD5 Verification - 16 bytes | - // | (ONLY FOR VERIFIED PACKETS) | - // | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | - // NLPacket Header Format + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + using LocalID = NetworkLocalID; + static const LocalID NULL_LOCAL_ID = 0; + + static const int NUM_BYTES_LOCALID = sizeof(LocalID); // this is used by the Octree classes - must be known at compile time static const int MAX_PACKET_HEADER_SIZE = sizeof(udt::Packet::SequenceNumberAndBitField) + sizeof(udt::Packet::MessageNumberAndBitField) + - sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID + NUM_BYTES_MD5_HASH; + sizeof(PacketType) + sizeof(PacketVersion) + NUM_BYTES_LOCALID + NUM_BYTES_MD5_HASH; static std::unique_ptr create(PacketType type, qint64 size = -1, bool isReliable = false, bool isPartOfMessage = false, PacketVersion version = 0); @@ -71,7 +69,7 @@ public: static PacketType typeInHeader(const udt::Packet& packet); static PacketVersion versionInHeader(const udt::Packet& packet); - static QUuid sourceIDInHeader(const udt::Packet& packet); + static LocalID sourceIDInHeader(const udt::Packet& packet); static QByteArray verificationHashInHeader(const udt::Packet& packet); static QByteArray hashForPacketAndHMAC(const udt::Packet& packet, HMACAuth& hash); @@ -81,9 +79,9 @@ public: PacketVersion getVersion() const { return _version; } void setVersion(PacketVersion version); - const QUuid& getSourceID() const { return _sourceID; } + LocalID getSourceID() const { return _sourceID; } - void writeSourceID(const QUuid& sourceID) const; + void writeSourceID(LocalID sourceID) const; void writeVerificationHash(HMACAuth& hmacAuth) const; protected: @@ -108,7 +106,7 @@ protected: PacketType _type; PacketVersion _version; - mutable QUuid _sourceID; + mutable LocalID _sourceID; }; #endif // hifi_NLPacket_h diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index 910d39f71b..9c50033ca7 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -22,7 +22,7 @@ public: bool isReliable = false, bool isOrdered = false); PacketVersion getVersion() const { return _packetVersion; } - const QUuid& getSourceID() const { return _sourceID; } + NLPacket::LocalID getSourceID() const { return _sourceID; } qint64 getMaxSegmentSize() const override { return NLPacket::maxPayloadSize(_packetType, _isOrdered); } @@ -37,7 +37,7 @@ private: PacketVersion _packetVersion; - QUuid _sourceID; + NLPacket::LocalID _sourceID; }; Q_DECLARE_METATYPE(QSharedPointer) diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index b52c54c468..6d384ba558 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -23,6 +23,7 @@ #include #include "NodeType.h" +const NetworkPeer::LocalID NetworkPeer::NULL_LOCAL_ID; NetworkPeer::NetworkPeer(QObject* parent) : QObject(parent), diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 9842768b37..462daa1ed2 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -18,6 +18,7 @@ #include #include +#include "UUID.h" #include "HifiSockAddr.h" const QString ICE_SERVER_HOSTNAME = "localhost"; @@ -39,6 +40,12 @@ public: const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } + using LocalID = NetworkLocalID; + static const LocalID NULL_LOCAL_ID = 0; + + LocalID getLocalID() const { return _localID; } + void setLocalID(LocalID localID) { _localID = localID; } + void softReset(); void reset(); @@ -99,6 +106,7 @@ protected: void setActiveSocket(HifiSockAddr* discoveredSocket); QUuid _uuid; + LocalID _localID { 0 }; HifiSockAddr _publicSocket; HifiSockAddr _localSocket; diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 132d27d311..7979b36e30 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -169,6 +169,7 @@ QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._localSocket; out << node._permissions; out << node._isReplicated; + out << node._localID; return out; } @@ -179,6 +180,7 @@ QDataStream& operator>>(QDataStream& in, Node& node) { in >> node._localSocket; in >> node._permissions; in >> node._isReplicated; + in >> node._localID; return in; } @@ -189,7 +191,7 @@ QDebug operator<<(QDebug debug, const Node& node) { } else { debug.nospace() << " (" << node.getType() << ")"; } - debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " "; + debug << " " << node.getUUID().toString().toLocal8Bit().constData() << "(" << node.getLocalID() << ") "; debug.nospace() << node.getPublicSocket() << "/" << node.getLocalSocket(); return debug.nospace(); } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index fdb503eee5..cfe81a58af 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -624,13 +624,21 @@ void NodeList::processDomainServerList(QSharedPointer message) return; } - // pull our owner UUID from the packet, it's always the first thing + Node::LocalID domainLocalID; + packetStream >> domainLocalID; + + // pull our owner (ie. session) UUID from the packet, it's always the first thing + // The short (16 bit) ID comes next. QUuid newUUID; + Node::LocalID newLocalID; packetStream >> newUUID; + packetStream >> newLocalID; + setSessionLocalID(newLocalID); setSessionUUID(newUUID); // if this was the first domain-server list from this domain, we've now connected if (!_domainHandler.isConnected()) { + _domainHandler.setLocalID(newLocalID); _domainHandler.setUUID(domainUUID); _domainHandler.setIsConnected(true); @@ -668,12 +676,14 @@ void NodeList::processDomainServerRemovedNode(QSharedPointer me void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { // setup variables to read into from QDataStream qint8 nodeType; - QUuid nodeUUID, connectionUUID; + QUuid nodeUUID, connectionSecretUUID; HifiSockAddr nodePublicSocket, nodeLocalSocket; NodePermissions permissions; bool isReplicated; + Node::LocalID sessionLocalID; - packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions >> isReplicated; + packetStream >> nodeType >> nodeUUID >> nodePublicSocket >> nodeLocalSocket >> permissions + >> isReplicated >> sessionLocalID; // if the public socket address is 0 then it's reachable at the same IP // as the domain server @@ -681,10 +691,10 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { nodePublicSocket.setAddress(_domainHandler.getIP()); } - packetStream >> connectionUUID; + packetStream >> connectionSecretUUID; - SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, - nodeLocalSocket, isReplicated, false, connectionUUID, permissions); + SharedNodePointer node = addOrUpdateNode(nodeUUID, nodeType, nodePublicSocket, nodeLocalSocket, + sessionLocalID, isReplicated, false, connectionSecretUUID, permissions); // nodes that are downstream or upstream of our own type are kept alive when we hear about them from the domain server // and always have their public socket as their active socket diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 7e3a7c2bd7..9595c5da84 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -94,6 +94,7 @@ public: virtual bool isDomainServer() const override { return false; } virtual QUuid getDomainUUID() const override { return _domainHandler.getUUID(); } + virtual Node::LocalID getDomainLocalID() const override { return _domainHandler.getLocalID(); } virtual HifiSockAddr getDomainSockAddr() const override { return _domainHandler.getSockAddr(); } public slots: diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 27b57ef26c..fe2a273d61 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -261,10 +261,9 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei SharedNodePointer matchingNode; - if (!receivedMessage->getSourceID().isNull()) { - matchingNode = nodeList->nodeWithUUID(receivedMessage->getSourceID()); + if (receivedMessage->getSourceID() != Node::NULL_LOCAL_ID) { + matchingNode = nodeList->nodeWithLocalID(receivedMessage->getSourceID()); } - QMutexLocker packetListenerLocker(&_packetListenerLock); auto it = _messageListenerMap.find(receivedMessage->getType()); diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 00b16908ce..e1a036b041 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -43,7 +43,7 @@ ReceivedMessage::ReceivedMessage(NLPacket& packet) } ReceivedMessage::ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion, - const HifiSockAddr& senderSockAddr, QUuid sourceID) : + const HifiSockAddr& senderSockAddr, NLPacket::LocalID sourceID) : _data(byteArray), _headData(_data.mid(0, HEAD_DATA_SIZE)), _numPackets(1), diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index ae51e7592a..af87ef75af 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -25,7 +25,7 @@ public: ReceivedMessage(const NLPacketList& packetList); ReceivedMessage(NLPacket& packet); ReceivedMessage(QByteArray byteArray, PacketType packetType, PacketVersion packetVersion, - const HifiSockAddr& senderSockAddr, QUuid sourceID = QUuid()); + const HifiSockAddr& senderSockAddr, NLPacket::LocalID sourceID = NLPacket::NULL_LOCAL_ID); QByteArray getMessage() const { return _data; } const char* getRawMessage() const { return _data.constData(); } @@ -40,7 +40,7 @@ public: bool failed() const { return _failed; } bool isComplete() const { return _isComplete; } - const QUuid& getSourceID() const { return _sourceID; } + NLPacket::LocalID getSourceID() const { return _sourceID; } const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } qint64 getPosition() const { return _position; } @@ -93,7 +93,7 @@ private: std::atomic _position { 0 }; std::atomic _numPackets { 0 }; - QUuid _sourceID; + NLPacket::LocalID _sourceID { NLPacket::NULL_LOCAL_ID }; PacketType _packetType; PacketVersion _packetVersion; HifiSockAddr _senderSockAddr; diff --git a/libraries/networking/src/SequenceNumberStats.cpp b/libraries/networking/src/SequenceNumberStats.cpp index 7f1ee39554..e11fcf22d4 100644 --- a/libraries/networking/src/SequenceNumberStats.cpp +++ b/libraries/networking/src/SequenceNumberStats.cpp @@ -25,7 +25,7 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectO : _lastReceivedSequence(0), _missingSet(), _stats(), - _lastSenderUUID(), + _lastSenderID(NULL_LOCAL_ID), _statsHistory(statsHistoryLength), _lastUnreasonableSequence(0), _consecutiveUnreasonableOnTime(0) @@ -35,7 +35,7 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, bool canDetectO void SequenceNumberStats::reset() { _missingSet.clear(); _stats = PacketStreamStats(); - _lastSenderUUID = QUuid(); + _lastSenderID = NULL_LOCAL_ID; _statsHistory.clear(); _lastUnreasonableSequence = 0; _consecutiveUnreasonableOnTime = 0; @@ -43,18 +43,18 @@ void SequenceNumberStats::reset() { static const int UINT16_RANGE = std::numeric_limits::max() + 1; -SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(quint16 incoming, QUuid senderUUID, const bool wantExtraDebugging) { +SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(quint16 incoming, NetworkLocalID senderID, const bool wantExtraDebugging) { SequenceNumberStats::ArrivalInfo arrivalInfo; // if the sender node has changed, reset all stats - if (senderUUID != _lastSenderUUID) { + if (senderID != _lastSenderID) { if (_stats._received > 0) { qCDebug(networking) << "sequence number stats was reset due to new sender node"; - qCDebug(networking) << "previous:" << _lastSenderUUID << "current:" << senderUUID; + qCDebug(networking) << "previous:" << _lastSenderID << "current:" << senderID; reset(); } - _lastSenderUUID = senderUUID; + _lastSenderID = senderID; } // determine our expected sequence number... handle rollover appropriately diff --git a/libraries/networking/src/SequenceNumberStats.h b/libraries/networking/src/SequenceNumberStats.h index 46149d4307..8705f960b7 100644 --- a/libraries/networking/src/SequenceNumberStats.h +++ b/libraries/networking/src/SequenceNumberStats.h @@ -14,7 +14,7 @@ #include "SharedUtil.h" #include "RingBufferHistory.h" -#include +#include "UUID.h" const int MAX_REASONABLE_SEQUENCE_GAP = 1000; @@ -73,7 +73,7 @@ public: SequenceNumberStats(int statsHistoryLength = 0, bool canDetectOutOfSync = true); void reset(); - ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false); + ArrivalInfo sequenceNumberReceived(quint16 incoming, NetworkLocalID senderID = NULL_LOCAL_ID, const bool wantExtraDebugging = false); void pruneMissingSet(const bool wantExtraDebugging = false); void pushStatsToHistory() { _statsHistory.insert(_stats); } @@ -100,7 +100,8 @@ private: PacketStreamStats _stats; - QUuid _lastSenderUUID; + NetworkLocalID _lastSenderID; + static const NetworkLocalID NULL_LOCAL_ID = (NetworkLocalID) 0; RingBufferHistory _statsHistory; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 765f01db0e..db466a0403 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -91,7 +91,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::Ping: return static_cast(PingVersion::IncludeConnectionID); default: - return 18; + return 19; } } diff --git a/libraries/octree/src/OctreeProcessor.cpp b/libraries/octree/src/OctreeProcessor.cpp index 0808e817ed..43019c7acc 100644 --- a/libraries/octree/src/OctreeProcessor.cpp +++ b/libraries/octree/src/OctreeProcessor.cpp @@ -96,7 +96,7 @@ void OctreeProcessor::processDatagram(ReceivedMessage& message, SharedNodePointe quint64 totalUncompress = 0; quint64 totalReadBitsteam = 0; - const QUuid& sourceUUID = message.getSourceID(); + const QUuid& sourceUUID = sourceNode->getUUID(); int subsection = 1; diff --git a/libraries/shared/src/UUID.h b/libraries/shared/src/UUID.h index 7e7048486f..55ac0866ee 100644 --- a/libraries/shared/src/UUID.h +++ b/libraries/shared/src/UUID.h @@ -15,6 +15,7 @@ #include const int NUM_BYTES_RFC4122_UUID = 16; +using NetworkLocalID = quint16; QString uuidStringWithoutCurlyBraces(const QUuid& uuid);