mirror of
https://github.com/overte-org/overte.git
synced 2025-06-06 14:20:45 +02:00
tweaks to domain-server authentication flow
This commit is contained in:
parent
217a7862e5
commit
a6c1e3e87f
7 changed files with 253 additions and 191 deletions
|
@ -121,7 +121,7 @@ void AssignmentClient::readPendingDatagrams() {
|
||||||
// switch our nodelist domain IP and port to whoever sent us the assignment
|
// switch our nodelist domain IP and port to whoever sent us the assignment
|
||||||
|
|
||||||
nodeList->getDomainInfo().setSockAddr(senderSockAddr);
|
nodeList->getDomainInfo().setSockAddr(senderSockAddr);
|
||||||
nodeList->setSessionUUID(_currentAssignment->getUUID());
|
nodeList->getDomainInfo().setAssignmentUUID(_currentAssignment->getUUID());
|
||||||
|
|
||||||
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
|
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,6 @@
|
||||||
|
|
||||||
#include "DomainServer.h"
|
#include "DomainServer.h"
|
||||||
|
|
||||||
const int RESTART_HOLD_TIME_MSECS = 5 * 1000;
|
|
||||||
|
|
||||||
const char* VOXEL_SERVER_CONFIG = "voxelServerConfig";
|
|
||||||
const char* PARTICLE_SERVER_CONFIG = "particleServerConfig";
|
|
||||||
const char* METAVOXEL_SERVER_CONFIG = "metavoxelServerConfig";
|
|
||||||
|
|
||||||
const quint16 DOMAIN_SERVER_HTTP_PORT = 8080;
|
const quint16 DOMAIN_SERVER_HTTP_PORT = 8080;
|
||||||
|
|
||||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
@ -40,8 +34,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
_HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
_HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
|
||||||
_staticAssignmentHash(),
|
_staticAssignmentHash(),
|
||||||
_assignmentQueue(),
|
_assignmentQueue(),
|
||||||
_hasCompletedRestartHold(false),
|
_nodeAuthenticationURL(DEFAULT_NODE_AUTH_URL),
|
||||||
_nodeAuthenticationURL(DEFAULT_NODE_AUTH_URL)
|
_redeemedTokenResponses()
|
||||||
{
|
{
|
||||||
_argumentList = arguments();
|
_argumentList = arguments();
|
||||||
int argumentIndex = 0;
|
int argumentIndex = 0;
|
||||||
|
@ -149,8 +143,8 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
|
|
||||||
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readAvailableDatagrams()));
|
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), SLOT(readAvailableDatagrams()));
|
||||||
|
|
||||||
// fire a single shot timer to add static assignments back into the queue after a restart
|
// add whatever static assignments that have been parsed to the queue
|
||||||
QTimer::singleShot(RESTART_HOLD_TIME_MSECS, this, SLOT(addStaticAssignmentsBackToQueueAfterRestart()));
|
addStaticAssignmentsToQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes) {
|
void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes) {
|
||||||
|
@ -292,24 +286,156 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Ass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainServer::requestAuthenticationFromPotentialNode(const HifiSockAddr& senderSockAddr) {
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
QDataStream authPacketStream(&authenticationRequestPacket, QIODevice::Append);
|
||||||
|
authPacketStream << _nodeAuthenticationURL;
|
||||||
|
|
||||||
|
qDebug() << "Asking node at" << senderSockAddr << "to authenticate.";
|
||||||
|
|
||||||
|
// send the authentication request back to the node
|
||||||
|
NodeList::getInstance()->getNodeSocket().writeDatagram(authenticationRequestPacket,
|
||||||
|
senderSockAddr.getAddress(), senderSockAddr.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer
|
||||||
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
|
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
|
||||||
<< NodeType::MetavoxelServer;
|
<< NodeType::MetavoxelServer;
|
||||||
|
|
||||||
|
|
||||||
|
void DomainServer::addNodeToNodeListAndConfirmConnection(const QByteArray& packet, const HifiSockAddr& senderSockAddr,
|
||||||
|
const QJsonObject& authJsonObject) {
|
||||||
|
|
||||||
|
NodeType_t nodeType;
|
||||||
|
HifiSockAddr publicSockAddr, localSockAddr;
|
||||||
|
|
||||||
|
int numPreInterestBytes = parseNodeDataFromByteArray(nodeType, publicSockAddr, localSockAddr, packet, senderSockAddr);
|
||||||
|
|
||||||
|
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||||
|
SharedAssignmentPointer matchingAssignment;
|
||||||
|
|
||||||
|
if (!nodeUUID.isNull() && (matchingAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))) {
|
||||||
|
// this is an assigned node, make sure the UUID sent is for an assignment we're actually trying to give out
|
||||||
|
nodeUUID = uuidFromPacketHeader(packet);
|
||||||
|
|
||||||
|
if (matchingAssignment) {
|
||||||
|
// this was a newly added node with a matching assignment
|
||||||
|
|
||||||
|
// remove the matching assignment from the assignment queue so we don't take the next check in
|
||||||
|
// (if it exists)
|
||||||
|
removeMatchingAssignmentFromQueue(matchingAssignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new session UUID for this node
|
||||||
|
nodeUUID = QUuid::createUuid();
|
||||||
|
|
||||||
|
SharedNodePointer newNode = NodeList::getInstance()->addOrUpdateNode(nodeUUID, nodeType, publicSockAddr, localSockAddr);
|
||||||
|
|
||||||
|
// reply back to the user with a PacketTypeDomainList
|
||||||
|
sendDomainListToNode(newNode, senderSockAddr, nodeInterestListFromPacket(packet, numPreInterestBytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
int DomainServer::parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,
|
||||||
|
HifiSockAddr& localSockAddr, const QByteArray& packet,
|
||||||
|
const HifiSockAddr& senderSockAddr) {
|
||||||
|
QDataStream packetStream(packet);
|
||||||
|
packetStream.skipRawData(numBytesForPacketHeader(packet));
|
||||||
|
|
||||||
|
packetStream >> nodeType;
|
||||||
|
packetStream >> publicSockAddr >> localSockAddr;
|
||||||
|
|
||||||
|
if (publicSockAddr.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 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()) {
|
||||||
|
publicSockAddr.setAddress(QHostAddress());
|
||||||
|
} else {
|
||||||
|
publicSockAddr.setAddress(senderSockAddr.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return packetStream.device()->pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeSet DomainServer::nodeInterestListFromPacket(const QByteArray& packet, int numPreceedingBytes) {
|
||||||
|
QDataStream packetStream(packet);
|
||||||
|
packetStream.skipRawData(numPreceedingBytes);
|
||||||
|
|
||||||
|
quint8 numInterestTypes = 0;
|
||||||
|
packetStream >> numInterestTypes;
|
||||||
|
|
||||||
|
quint8 nodeType;
|
||||||
|
NodeSet nodeInterestSet;
|
||||||
|
|
||||||
|
for (int i = 0; i < numInterestTypes; i++) {
|
||||||
|
packetStream >> nodeType;
|
||||||
|
nodeInterestSet.insert((NodeType_t) nodeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeInterestSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr &senderSockAddr,
|
||||||
|
const NodeSet& nodeInterestList) {
|
||||||
|
|
||||||
|
QByteArray broadcastPacket = byteArrayWithPopluatedHeader(PacketTypeDomainList);
|
||||||
|
|
||||||
|
// always send the node their own UUID back
|
||||||
|
QDataStream broadcastDataStream(&broadcastPacket, QIODevice::Append);
|
||||||
|
broadcastDataStream << node->getUUID();
|
||||||
|
|
||||||
|
DomainServerNodeData* nodeData = reinterpret_cast<DomainServerNodeData*>(node->getLinkedData());
|
||||||
|
|
||||||
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
|
if (nodeInterestList.size() > 0) {
|
||||||
|
// if the node has any interest types, send back those nodes as well
|
||||||
|
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||||
|
if (otherNode->getUUID() != node->getUUID() && nodeInterestList.contains(otherNode->getType())) {
|
||||||
|
|
||||||
|
// 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(node->getUUID(), secretUUID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
broadcastDataStream << secretUUID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void DomainServer::readAvailableDatagrams() {
|
void DomainServer::readAvailableDatagrams() {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
AccountManager& accountManager = AccountManager::getInstance();
|
AccountManager& accountManager = AccountManager::getInstance();
|
||||||
|
|
||||||
HifiSockAddr senderSockAddr, nodePublicAddress, nodeLocalAddress;
|
HifiSockAddr senderSockAddr;
|
||||||
|
|
||||||
static QByteArray broadcastPacket = byteArrayWithPopluatedHeader(PacketTypeDomainList);
|
|
||||||
static int numBroadcastPacketHeaderBytes = broadcastPacket.size();
|
|
||||||
|
|
||||||
static QByteArray assignmentPacket = byteArrayWithPopluatedHeader(PacketTypeCreateAssignment);
|
static QByteArray assignmentPacket = byteArrayWithPopluatedHeader(PacketTypeCreateAssignment);
|
||||||
static int numAssignmentPacketHeaderBytes = assignmentPacket.size();
|
static int numAssignmentPacketHeaderBytes = assignmentPacket.size();
|
||||||
|
|
||||||
QByteArray receivedPacket;
|
QByteArray receivedPacket;
|
||||||
NodeType_t nodeType;
|
|
||||||
|
|
||||||
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
|
||||||
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
receivedPacket.resize(nodeList->getNodeSocket().pendingDatagramSize());
|
||||||
|
@ -318,142 +444,60 @@ void DomainServer::readAvailableDatagrams() {
|
||||||
|
|
||||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||||
PacketType requestType = packetTypeForPacket(receivedPacket);
|
PacketType requestType = packetTypeForPacket(receivedPacket);
|
||||||
if (requestType == PacketTypeDomainListRequest) {
|
|
||||||
|
if (requestType == PacketTypeDomainConnectRequest) {
|
||||||
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
|
||||||
|
|
||||||
if (!_nodeAuthenticationURL.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);
|
|
||||||
|
|
||||||
QDataStream authPacketStream(&authenticationRequestPacket, QIODevice::Append);
|
|
||||||
authPacketStream << _nodeAuthenticationURL;
|
|
||||||
|
|
||||||
qDebug() << "Asking node at" << senderSockAddr << "to authenticate.";
|
|
||||||
|
|
||||||
// send the authentication request back to the node
|
|
||||||
nodeList->getNodeSocket().writeDatagram(authenticationRequestPacket,
|
|
||||||
senderSockAddr.getAddress(), senderSockAddr.getPort());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// this is an RFD or domain list request packet, and there is a match
|
|
||||||
QDataStream packetStream(receivedPacket);
|
|
||||||
packetStream.skipRawData(numBytesForPacketHeader(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 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)) {
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (requestType == PacketTypeDomainConnectRequest) {
|
|
||||||
QDataStream packetStream(receivedPacket);
|
QDataStream packetStream(receivedPacket);
|
||||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||||
|
|
||||||
QByteArray registrationToken;
|
quint8 hasRegistrationToken;
|
||||||
packetStream >> registrationToken;
|
packetStream >> hasRegistrationToken;
|
||||||
|
|
||||||
// make a request against the data-server to get information required to connect to this node
|
if (requiresAuthentication() && !hasRegistrationToken) {
|
||||||
JSONCallbackParameters tokenCallbackParams;
|
// we need authentication and this node did not give us a registration token - tell it to auth
|
||||||
tokenCallbackParams.jsonCallbackReceiver = this;
|
requestAuthenticationFromPotentialNode(senderSockAddr);
|
||||||
tokenCallbackParams.jsonCallbackMethod = "processTokenRedeemResponse";
|
} else if (requiresAuthentication()) {
|
||||||
|
QByteArray registrationToken;
|
||||||
|
packetStream >> registrationToken;
|
||||||
|
|
||||||
|
QString registrationTokenString(registrationToken.toHex());
|
||||||
|
QJsonObject jsonForRedeemedToken = _redeemedTokenResponses.value(registrationTokenString);
|
||||||
|
|
||||||
|
// check if we have redeemed this token and are ready to check the node in
|
||||||
|
if (jsonForRedeemedToken.isEmpty()) {
|
||||||
|
// make a request against the data-server to get information required to connect to this node
|
||||||
|
JSONCallbackParameters tokenCallbackParams;
|
||||||
|
tokenCallbackParams.jsonCallbackReceiver = this;
|
||||||
|
tokenCallbackParams.jsonCallbackMethod = "processTokenRedeemResponse";
|
||||||
|
|
||||||
|
QString redeemURLString = QString("/api/v1/nodes/redeem/%1.json").arg(registrationTokenString);
|
||||||
|
accountManager.authenticatedRequest(redeemURLString, QNetworkAccessManager::GetOperation);
|
||||||
|
} else {
|
||||||
|
// we've redeemed the token for this node and are ready to start communicating with it
|
||||||
|
// add the node to our NodeList
|
||||||
|
addNodeToNodeListAndConfirmConnection(receivedPacket, senderSockAddr, jsonForRedeemedToken);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we don't require authentication - add this node to our NodeList
|
||||||
|
// and send back session UUID right away
|
||||||
|
addNodeToNodeListAndConfirmConnection(receivedPacket, senderSockAddr);
|
||||||
|
}
|
||||||
|
|
||||||
QString redeemURLString = QString("/api/v1/nodes/redeem/%1.json").arg(QString(registrationToken.toHex()));
|
} else if (requestType == PacketTypeDomainListRequest) {
|
||||||
accountManager.authenticatedRequest(redeemURLString, QNetworkAccessManager::GetOperation);
|
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
|
||||||
|
NodeType_t throwawayNodeType;
|
||||||
|
HifiSockAddr nodePublicAddress, nodeLocalAddress;
|
||||||
|
|
||||||
|
int numNodeInfoBytes = parseNodeDataFromByteArray(throwawayNodeType, nodePublicAddress, nodeLocalAddress,
|
||||||
|
receivedPacket, senderSockAddr);
|
||||||
|
|
||||||
|
SharedNodePointer checkInNode = nodeList->updateSocketsForNode(nodeUUID, nodePublicAddress, nodeLocalAddress);
|
||||||
|
|
||||||
|
// update last receive to now
|
||||||
|
quint64 timeNow = usecTimestampNow();
|
||||||
|
checkInNode->setLastHeardMicrostamp(timeNow);
|
||||||
|
|
||||||
|
|
||||||
|
sendDomainListToNode(checkInNode, senderSockAddr, nodeInterestListFromPacket(receivedPacket, numNodeInfoBytes));
|
||||||
|
|
||||||
} else if (requestType == PacketTypeRequestAssignment) {
|
} else if (requestType == PacketTypeRequestAssignment) {
|
||||||
|
|
||||||
|
@ -713,25 +757,16 @@ void DomainServer::nodeKilled(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
|
SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
|
||||||
if (_hasCompletedRestartHold) {
|
QQueue<SharedAssignmentPointer>::iterator i = _assignmentQueue.begin();
|
||||||
// look for a match in the assignment hash
|
|
||||||
|
while (i != _assignmentQueue.end()) {
|
||||||
QQueue<SharedAssignmentPointer>::iterator i = _assignmentQueue.begin();
|
if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) {
|
||||||
|
return _assignmentQueue.takeAt(i - _assignmentQueue.begin());
|
||||||
while (i != _assignmentQueue.end()) {
|
} else {
|
||||||
if (i->data()->getType() == Assignment::typeForNodeType(nodeType) && i->data()->getUUID() == checkInUUID) {
|
++i;
|
||||||
return _assignmentQueue.takeAt(i - _assignmentQueue.begin());
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SharedAssignmentPointer matchingStaticAssignment = _staticAssignmentHash.value(checkInUUID);
|
|
||||||
if (matchingStaticAssignment && matchingStaticAssignment->getType() == nodeType) {
|
|
||||||
return matchingStaticAssignment;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SharedAssignmentPointer();
|
return SharedAssignmentPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,8 +829,7 @@ void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPoint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() {
|
void DomainServer::addStaticAssignmentsToQueue() {
|
||||||
_hasCompletedRestartHold = true;
|
|
||||||
|
|
||||||
// if the domain-server has just restarted,
|
// if the domain-server has just restarted,
|
||||||
// check if there are static assignments that we need to throw into the assignment queue
|
// check if there are static assignments that we need to throw into the assignment queue
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QQueue>
|
#include <QtCore/QQueue>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
@ -26,6 +27,8 @@ class DomainServer : public QCoreApplication, public HTTPRequestHandler {
|
||||||
public:
|
public:
|
||||||
DomainServer(int argc, char* argv[]);
|
DomainServer(int argc, char* argv[]);
|
||||||
|
|
||||||
|
bool requiresAuthentication() const { return !_nodeAuthenticationURL.isEmpty(); }
|
||||||
|
|
||||||
bool handleHTTPRequest(HTTPConnection* connection, const QString& path);
|
bool handleHTTPRequest(HTTPConnection* connection, const QString& path);
|
||||||
|
|
||||||
void exit(int retCode = 0);
|
void exit(int retCode = 0);
|
||||||
|
@ -39,6 +42,15 @@ public slots:
|
||||||
private:
|
private:
|
||||||
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid());
|
||||||
|
|
||||||
|
void requestAuthenticationFromPotentialNode(const HifiSockAddr& senderSockAddr);
|
||||||
|
void addNodeToNodeListAndConfirmConnection(const QByteArray& packet, const HifiSockAddr& senderSockAddr,
|
||||||
|
const QJsonObject& authJsonObject = QJsonObject());
|
||||||
|
int parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,
|
||||||
|
HifiSockAddr& localSockAddr, const QByteArray& packet, const HifiSockAddr& senderSockAddr);
|
||||||
|
NodeSet nodeInterestListFromPacket(const QByteArray& packet, int numPreceedingBytes);
|
||||||
|
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr,
|
||||||
|
const NodeSet& nodeInterestList);
|
||||||
|
|
||||||
void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes);
|
void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes);
|
||||||
void readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes);
|
void readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes);
|
||||||
QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName);
|
QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName);
|
||||||
|
@ -50,6 +62,7 @@ private:
|
||||||
SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment);
|
SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment);
|
||||||
void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment);
|
void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment);
|
||||||
void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
|
void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
|
||||||
|
void addStaticAssignmentsToQueue();
|
||||||
|
|
||||||
QJsonObject jsonForSocket(const HifiSockAddr& socket);
|
QJsonObject jsonForSocket(const HifiSockAddr& socket);
|
||||||
QJsonObject jsonObjectForNode(const SharedNodePointer& node);
|
QJsonObject jsonObjectForNode(const SharedNodePointer& node);
|
||||||
|
@ -59,18 +72,17 @@ private:
|
||||||
QHash<QUuid, SharedAssignmentPointer> _staticAssignmentHash;
|
QHash<QUuid, SharedAssignmentPointer> _staticAssignmentHash;
|
||||||
QQueue<SharedAssignmentPointer> _assignmentQueue;
|
QQueue<SharedAssignmentPointer> _assignmentQueue;
|
||||||
|
|
||||||
bool _hasCompletedRestartHold;
|
|
||||||
|
|
||||||
QUrl _nodeAuthenticationURL;
|
QUrl _nodeAuthenticationURL;
|
||||||
|
|
||||||
QStringList _argumentList;
|
QStringList _argumentList;
|
||||||
|
|
||||||
|
QHash<QString, QJsonObject> _redeemedTokenResponses;
|
||||||
private slots:
|
private slots:
|
||||||
void requestCreationFromDataServer();
|
void requestCreationFromDataServer();
|
||||||
void processCreateResponseFromDataServer(const QJsonObject& jsonObject);
|
void processCreateResponseFromDataServer(const QJsonObject& jsonObject);
|
||||||
void processTokenRedeemResponse(const QJsonObject& jsonObject);
|
void processTokenRedeemResponse(const QJsonObject& jsonObject);
|
||||||
|
|
||||||
void readAvailableDatagrams();
|
void readAvailableDatagrams();
|
||||||
void addStaticAssignmentsBackToQueueAfterRestart();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__DomainServer__) */
|
#endif /* defined(__hifi__DomainServer__) */
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
DomainInfo::DomainInfo() :
|
DomainInfo::DomainInfo() :
|
||||||
_uuid(),
|
_uuid(),
|
||||||
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
|
||||||
|
_assignmentUUID(),
|
||||||
_connectionSecret(),
|
_connectionSecret(),
|
||||||
_registrationToken(),
|
_registrationToken(),
|
||||||
_rootAuthenticationURL(),
|
_rootAuthenticationURL(),
|
||||||
|
@ -25,6 +26,7 @@ void DomainInfo::reset() {
|
||||||
_uuid = QUuid();
|
_uuid = QUuid();
|
||||||
_hostname = QString();
|
_hostname = QString();
|
||||||
_sockAddr.setAddress(QHostAddress::Null);
|
_sockAddr.setAddress(QHostAddress::Null);
|
||||||
|
_assignmentUUID = QUuid();
|
||||||
_connectionSecret = QString();
|
_connectionSecret = QString();
|
||||||
_registrationToken = QByteArray();
|
_registrationToken = QByteArray();
|
||||||
_rootAuthenticationURL = QUrl();
|
_rootAuthenticationURL = QUrl();
|
||||||
|
|
|
@ -40,6 +40,9 @@ public:
|
||||||
|
|
||||||
unsigned short getPort() const { return _sockAddr.getPort(); }
|
unsigned short getPort() const { return _sockAddr.getPort(); }
|
||||||
|
|
||||||
|
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
|
||||||
|
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
|
||||||
|
|
||||||
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
const QUuid& getConnectionSecret() const { return _connectionSecret; }
|
||||||
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
|
||||||
|
|
||||||
|
@ -58,6 +61,7 @@ private:
|
||||||
QUuid _uuid;
|
QUuid _uuid;
|
||||||
QString _hostname;
|
QString _hostname;
|
||||||
HifiSockAddr _sockAddr;
|
HifiSockAddr _sockAddr;
|
||||||
|
QUuid _assignmentUUID;
|
||||||
QUuid _connectionSecret;
|
QUuid _connectionSecret;
|
||||||
QByteArray _registrationToken;
|
QByteArray _registrationToken;
|
||||||
QUrl _rootAuthenticationURL;
|
QUrl _rootAuthenticationURL;
|
||||||
|
|
|
@ -90,7 +90,7 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << PacketTypeDomainList
|
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>() << PacketTypeDomainList
|
||||||
<< PacketTypeDomainListRequest << PacketTypeDomainServerAuthRequest << PacketTypeDomainConnectRequest
|
<< PacketTypeDomainServerAuthRequest << PacketTypeDomainConnectRequest
|
||||||
<< PacketTypeStunResponse << PacketTypeDataServerConfirm
|
<< PacketTypeStunResponse << PacketTypeDataServerConfirm
|
||||||
<< PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend
|
<< PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend
|
||||||
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment;
|
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment;
|
||||||
|
@ -484,16 +484,22 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|| !_domainInfo.getRegistrationToken().isEmpty() ) {
|
|| !_domainInfo.getRegistrationToken().isEmpty() ) {
|
||||||
// construct the DS check in packet
|
// construct the DS check in packet
|
||||||
|
|
||||||
PacketType domainPacketType = _domainInfo.getRegistrationToken().isEmpty()
|
PacketType domainPacketType = _sessionUUID.isNull() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest;
|
||||||
? PacketTypeDomainListRequest : PacketTypeDomainConnectRequest;
|
|
||||||
|
|
||||||
QByteArray domainServerPacket = byteArrayWithPopluatedHeader(domainPacketType);
|
QUuid packetUUID = (domainPacketType == PacketTypeDomainListRequest)
|
||||||
|
? _sessionUUID : _domainInfo.getAssignmentUUID();
|
||||||
|
|
||||||
|
QByteArray domainServerPacket = byteArrayWithPopluatedHeader(domainPacketType, packetUUID);
|
||||||
QDataStream packetStream(&domainServerPacket, QIODevice::Append);
|
QDataStream packetStream(&domainServerPacket, QIODevice::Append);
|
||||||
|
|
||||||
if (domainPacketType == PacketTypeDomainConnectRequest) {
|
if (domainPacketType == PacketTypeDomainConnectRequest) {
|
||||||
// we have a registration token to present to the domain-server
|
// we may need a registration token to present to the domain-server
|
||||||
// send that along in each packet until we get a list back from the domain-server
|
packetStream << (quint8) !_domainInfo.getRegistrationToken().isEmpty();
|
||||||
packetStream << _domainInfo.getRegistrationToken();
|
|
||||||
|
if (!_domainInfo.getRegistrationToken().isEmpty()) {
|
||||||
|
// if we have a registration token send that along in the request
|
||||||
|
packetStream << _domainInfo.getRegistrationToken();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack our data to send to the domain-server
|
// pack our data to send to the domain-server
|
||||||
|
@ -679,9 +685,8 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) {
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) {
|
||||||
_nodeHashMutex.lock();
|
_nodeHashMutex.lock();
|
||||||
|
|
||||||
SharedNodePointer matchingNode = _nodeHash.value(uuid);
|
if (!_nodeHash.contains(uuid)) {
|
||||||
|
|
||||||
if (!matchingNode) {
|
|
||||||
// we didn't have this node, so add them
|
// we didn't have this node, so add them
|
||||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
||||||
SharedNodePointer newNodeSharedPointer(newNode, &QObject::deleteLater);
|
SharedNodePointer newNodeSharedPointer(newNode, &QObject::deleteLater);
|
||||||
|
@ -698,29 +703,32 @@ SharedNodePointer NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
} else {
|
} else {
|
||||||
_nodeHashMutex.unlock();
|
_nodeHashMutex.unlock();
|
||||||
|
|
||||||
|
return updateSocketsForNode(uuid, publicSocket, localSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedNodePointer NodeList::updateSocketsForNode(const QUuid& uuid,
|
||||||
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) {
|
||||||
|
|
||||||
|
SharedNodePointer matchingNode = nodeWithUUID(uuid);
|
||||||
|
|
||||||
|
if (matchingNode) {
|
||||||
|
// perform appropriate updates to this node
|
||||||
QMutexLocker locker(&matchingNode->getMutex());
|
QMutexLocker locker(&matchingNode->getMutex());
|
||||||
|
|
||||||
if (matchingNode->getType() == NodeType::AudioMixer ||
|
|
||||||
matchingNode->getType() == NodeType::VoxelServer ||
|
|
||||||
matchingNode->getType() == NodeType::MetavoxelServer) {
|
|
||||||
// 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
|
|
||||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we need to change this node's public or local sockets
|
// check if we need to change this node's public or local sockets
|
||||||
if (publicSocket != matchingNode->getPublicSocket()) {
|
if (publicSocket != matchingNode->getPublicSocket()) {
|
||||||
matchingNode->setPublicSocket(publicSocket);
|
matchingNode->setPublicSocket(publicSocket);
|
||||||
qDebug() << "Public socket change for node" << *matchingNode;
|
qDebug() << "Public socket change for node" << *matchingNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localSocket != matchingNode->getLocalSocket()) {
|
if (localSocket != matchingNode->getLocalSocket()) {
|
||||||
matchingNode->setLocalSocket(localSocket);
|
matchingNode->setLocalSocket(localSocket);
|
||||||
qDebug() << "Local socket change for node" << *matchingNode;
|
qDebug() << "Local socket change for node" << *matchingNode;
|
||||||
}
|
}
|
||||||
// we had this node already, do nothing for now
|
|
||||||
return matchingNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return matchingNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
unsigned NodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
||||||
|
|
|
@ -106,6 +106,8 @@ public:
|
||||||
|
|
||||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
|
||||||
|
SharedNodePointer updateSocketsForNode(const QUuid& uuid,
|
||||||
|
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
|
||||||
|
|
||||||
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
|
||||||
void processKillNode(const QByteArray& datagram);
|
void processKillNode(const QByteArray& datagram);
|
||||||
|
|
Loading…
Reference in a new issue