hook up domain request for node to authenticate

This commit is contained in:
Stephen Birarda 2014-02-18 10:54:45 -08:00
parent 4c135dd3a7
commit 7c69028dc5
4 changed files with 134 additions and 109 deletions

View file

@ -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();
}

View file

@ -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<NodeType_t*>(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<DomainServerNodeData*>(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<DomainServerNodeData*>(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<NodeType_t*>(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<DomainServerNodeData*>(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<DomainServerNodeData*>(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

View file

@ -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<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << 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) {

View file

@ -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__) */