diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 0ae67574ed..660ee970a8 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -175,4 +175,5 @@ void AssignmentClient::assignmentCompleted() { // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NodeType::Unassigned); nodeList->reset(); + nodeList->resetNodeInterestSet(); } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 33a54716a6..f9193803e9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -69,8 +69,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : } else if ((argumentIndex = argumentList.indexOf(CUSTOM_AUTH_OPTION)) != -1) { _nodeAuthenticationHostname = argumentList.value(argumentIndex + 1); } - - qDebug() << "the node authentication hostname is" << _nodeAuthenticationHostname; NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort); @@ -254,109 +252,126 @@ void DomainServer::readAvailableDatagrams() { PacketType requestType = packetTypeForPacket(receivedPacket); if (requestType == PacketTypeDomainListRequest) { - // this is an RFD or domain list request packet, and there is a version match - QDataStream packetStream(receivedPacket); - packetStream.skipRawData(numBytesForPacketHeader(receivedPacket)); - QUuid nodeUUID = uuidFromPacketHeader(receivedPacket); - packetStream >> nodeType; - packetStream >> nodePublicAddress >> nodeLocalAddress; - - if (nodePublicAddress.getAddress().isNull()) { - // this node wants to use us its STUN server - // so set the node public address to whatever we perceive the public address to be + if (!_nodeAuthenticationHostname.isEmpty() && + (nodeUUID.isNull() || !nodeList->nodeWithUUID(nodeUUID))) { + // this is a node we do not recognize and we need authentication - ask them to do so + // by providing them the hostname they should authenticate with + QByteArray authenticationRequestPacket = byteArrayWithPopluatedHeader(PacketTypeDomainServerAuthRequest); - // if the sender is on our box then leave its public address to 0 so that - // other users attempt to reach it on the same address they have for the domain-server - if (senderSockAddr.getAddress().isLoopback()) { - nodePublicAddress.setAddress(QHostAddress()); - } else { - nodePublicAddress.setAddress(senderSockAddr.getAddress()); - } - } - - SharedAssignmentPointer matchingStaticAssignment; - - // check if this is a non-statically assigned node, a node that is assigned and checking in for the first time - // or a node that has already checked in and is continuing to report for duty - if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) - || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) - || nodeList->getInstance()->nodeWithUUID(nodeUUID)) { + QDataStream authPacketStream(&authenticationRequestPacket, QIODevice::Append); + authPacketStream << _nodeAuthenticationHostname; - if (nodeUUID.isNull()) { - // this is a check in from an unidentified node - // we need to generate a session UUID for this node - nodeUUID = QUuid::createUuid(); - } + qDebug() << "Asking node at" << senderSockAddr << "to authenticate."; - SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, - nodeType, - nodePublicAddress, - nodeLocalAddress); + // send the authentication request back to the node + nodeList->getNodeSocket().writeDatagram(authenticationRequestPacket, + senderSockAddr.getAddress(), senderSockAddr.getPort()); - // resize our broadcast packet in preparation to set it up again - broadcastPacket.resize(numBroadcastPacketHeaderBytes); + } else { + // this is an RFD or domain list request packet, and there is a match + QDataStream packetStream(receivedPacket); + packetStream.skipRawData(numBytesForPacketHeader(receivedPacket)); - if (matchingStaticAssignment) { - // this was a newly added node with a matching static assignment + packetStream >> nodeType; + packetStream >> nodePublicAddress >> nodeLocalAddress; + + if (nodePublicAddress.getAddress().isNull()) { + // this node wants to use us its STUN server + // so set the node public address to whatever we perceive the public address to be - // remove the matching assignment from the assignment queue so we don't take the next check in - // (if it exists) - if (_hasCompletedRestartHold) { - removeMatchingAssignmentFromQueue(matchingStaticAssignment); + // if the sender is on our box then leave its public address to 0 so that + // other users attempt to reach it on the same address they have for the domain-server + if (senderSockAddr.getAddress().isLoopback()) { + nodePublicAddress.setAddress(QHostAddress()); + } else { + nodePublicAddress.setAddress(senderSockAddr.getAddress()); } } - quint8 numInterestTypes = 0; - packetStream >> numInterestTypes; + SharedAssignmentPointer matchingStaticAssignment; - NodeType_t* nodeTypesOfInterest = reinterpret_cast(receivedPacket.data() - + packetStream.device()->pos()); - - // always send the node their own UUID back - QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); - broadcastDataStream << checkInNode->getUUID(); - - DomainServerNodeData* nodeData = reinterpret_cast(checkInNode->getLinkedData()); - - if (numInterestTypes > 0) { - // if the node has any interest types, send back those nodes as well - foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) { - if (otherNode->getUUID() != nodeUUID && - memchr(nodeTypesOfInterest, otherNode->getType(), numInterestTypes)) { - - // don't send avatar nodes to other avatars, that will come from avatar mixer - broadcastDataStream << *otherNode.data(); - - // pack the secret that these two nodes will use to communicate with each other - QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID()); - if (secretUUID.isNull()) { - // generate a new secret UUID these two nodes can use - secretUUID = QUuid::createUuid(); - - // set that on the current Node's sessionSecretHash - nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID); - - // set it on the other Node's sessionSecretHash - reinterpret_cast(otherNode->getLinkedData()) - ->getSessionSecretHash().insert(nodeUUID, secretUUID); - - } - - broadcastDataStream << secretUUID; + // check if this is a non-statically assigned node, a node that is assigned and checking in for the first time + // or a node that has already checked in and is continuing to report for duty + if (!STATICALLY_ASSIGNED_NODES.contains(nodeType) + || (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType)) + || nodeList->getInstance()->nodeWithUUID(nodeUUID)) { + + if (nodeUUID.isNull()) { + // this is a check in from an unidentified node + // we need to generate a session UUID for this node + nodeUUID = QUuid::createUuid(); + } + + SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID, + nodeType, + nodePublicAddress, + nodeLocalAddress); + + // resize our broadcast packet in preparation to set it up again + broadcastPacket.resize(numBroadcastPacketHeaderBytes); + + if (matchingStaticAssignment) { + // this was a newly added node with a matching static assignment + + // remove the matching assignment from the assignment queue so we don't take the next check in + // (if it exists) + if (_hasCompletedRestartHold) { + removeMatchingAssignmentFromQueue(matchingStaticAssignment); } } + + quint8 numInterestTypes = 0; + packetStream >> numInterestTypes; + + NodeType_t* nodeTypesOfInterest = reinterpret_cast(receivedPacket.data() + + packetStream.device()->pos()); + + // always send the node their own UUID back + QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append); + broadcastDataStream << checkInNode->getUUID(); + + DomainServerNodeData* nodeData = reinterpret_cast(checkInNode->getLinkedData()); + + if (numInterestTypes > 0) { + // if the node has any interest types, send back those nodes as well + foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) { + if (otherNode->getUUID() != nodeUUID && + memchr(nodeTypesOfInterest, otherNode->getType(), numInterestTypes)) { + + // don't send avatar nodes to other avatars, that will come from avatar mixer + broadcastDataStream << *otherNode.data(); + + // pack the secret that these two nodes will use to communicate with each other + QUuid secretUUID = nodeData->getSessionSecretHash().value(otherNode->getUUID()); + if (secretUUID.isNull()) { + // generate a new secret UUID these two nodes can use + secretUUID = QUuid::createUuid(); + + // set that on the current Node's sessionSecretHash + nodeData->getSessionSecretHash().insert(otherNode->getUUID(), secretUUID); + + // set it on the other Node's sessionSecretHash + reinterpret_cast(otherNode->getLinkedData()) + ->getSessionSecretHash().insert(nodeUUID, secretUUID); + + } + + broadcastDataStream << secretUUID; + } + } + } + + // update last receive to now + quint64 timeNow = usecTimestampNow(); + checkInNode->setLastHeardMicrostamp(timeNow); + + // send the constructed list back to this node + nodeList->getNodeSocket().writeDatagram(broadcastPacket, + senderSockAddr.getAddress(), senderSockAddr.getPort()); } - - // update last receive to now - quint64 timeNow = usecTimestampNow(); - checkInNode->setLastHeardMicrostamp(timeNow); - - // send the constructed list back to this node - nodeList->getNodeSocket().writeDatagram(broadcastPacket, - senderSockAddr.getAddress(), senderSockAddr.getPort()); - } + } } else if (requestType == PacketTypeRequestAssignment) { // construct the requested assignment from the packet data diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 62e9d7e7f8..0c0f66e6e9 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -68,11 +68,9 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : { _nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort); qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort(); -} - - -NodeList::~NodeList() { - clear(); + + // clear our NodeList when the domain changes + connect(&_domainInfo, &DomainInfo::hostnameChanged, this, &NodeList::reset); } bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { @@ -87,7 +85,8 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) { } const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainList - << PacketTypeDomainListRequest << PacketTypeStunResponse << PacketTypeDataServerConfirm + << PacketTypeDomainListRequest << PacketTypeDomainServerAuthRequest + << PacketTypeStunResponse << PacketTypeDataServerConfirm << PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend << PacketTypeCreateAssignment << PacketTypeRequestAssignment; @@ -196,6 +195,18 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr break; } + case PacketTypeDomainServerAuthRequest: { + // the domain-server has asked us to auth via a data-server + QDataStream authPacketStream(packet); + authPacketStream.skipRawData(numBytesForPacketHeader(packet)); + + QString authenticationHostname; + authPacketStream >> authenticationHostname; + + qDebug() << "Domain server wants us to auth with" << authenticationHostname; + + break; + } case PacketTypePing: { // send back a reply SharedNodePointer matchingNode = sendingNodeForPacket(packet); @@ -288,10 +299,8 @@ void NodeList::reset() { clear(); _numNoReplyDomainCheckIns = 0; - _nodeTypesOfInterest.clear(); - - // refresh the owner UUID - _sessionUUID = QUuid::createUuid(); + // refresh the owner UUID to the NULL UUID + _sessionUUID = QUuid(); } void NodeList::addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 5c90a869f4..230cda6b54 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -88,11 +88,10 @@ public: int getNumNoReplyDomainCheckIns() const { return _numNoReplyDomainCheckIns; } DomainInfo& getDomainInfo() { return _domainInfo; } - void reset(); - const NodeSet& getNodeInterestSet() const { return _nodeTypesOfInterest; } void addNodeTypeToInterestSet(NodeType_t nodeTypeToAdd); void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes); + void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); } int processDomainServerList(const QByteArray& packet); @@ -121,6 +120,8 @@ public: void loadData(QSettings* settings); void saveData(QSettings* settings); public slots: + void reset(); + void sendDomainServerCheckIn(); void pingInactiveNodes(); void removeSilentNodes(); @@ -130,20 +131,22 @@ signals: void uuidChanged(const QUuid& ownerUUID); void nodeAdded(SharedNodePointer); void nodeKilled(SharedNodePointer); + private: static NodeList* _sharedInstance; NodeList(char ownerType, unsigned short int socketListenPort); - ~NodeList(); NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton void sendSTUNRequest(); void processSTUNResponse(const QByteArray& packet); - qint64 NodeList::writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, - const QUuid& connectionSecret); + qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr, + const QUuid& connectionSecret); NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); + + void clear(); NodeHash _nodeHash; QMutex _nodeHashMutex; @@ -159,10 +162,7 @@ private: unsigned int _stunRequestsSinceSuccess; void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); - void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); - void resetDomainData(char domainField[], const char* domainData); - void domainLookup(); - void clear(); + void timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode); }; #endif /* defined(__hifi__NodeList__) */