add option for domain-server to enforce DTLS

This commit is contained in:
Stephen Birarda 2014-03-31 15:06:58 -07:00
parent da30d21f6e
commit 6c08e2a407
11 changed files with 180 additions and 247 deletions

View file

@ -5,7 +5,7 @@
# Once done this will define
#
# GNUTLS_FOUND - system found GnuTLS
# GNUTLS_INCLUDE_DIRS - the GnuTLS include directory
# GNUTLS_INCLUDE_DIR - the GnuTLS include directory
# GNUTLS_LIBRARY - Link this to use GnuTLS
#
# Created on 3/31/2014 by Stephen Birarda

View file

@ -180,6 +180,18 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
domainServerPort = _argumentList.value(argumentIndex + 1).toUShort();
}
unsigned short domainServerDTLSPort = -1;
if (_isUsingDTLS) {
domainServerDTLSPort = DEFAULT_DOMAIN_SERVER_DTLS_PORT;
const QString CUSTOM_DTLS_PORT_OPTION = "--dtlsPort";
if ((argumentIndex = _argumentList.indexOf(CUSTOM_DTLS_PORT_OPTION)) != -1) {
domainServerDTLSPort = _argumentList.value(argumentIndex + 1).toUShort();
}
}
QSet<Assignment::Type> parsedTypes(QSet<Assignment::Type>() << Assignment::AgentType);
parseCommandLineTypeConfigs(_argumentList, parsedTypes);
@ -191,7 +203,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
populateDefaultStaticAssignmentsExcludingTypes(parsedTypes);
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort);
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort, domainServerDTLSPort);
// create a random UUID for this session for the domain-server
nodeList->setSessionUUID(sessionUUID);
@ -519,10 +531,6 @@ void DomainServer::readAvailableDatagrams() {
NodeList* nodeList = NodeList::getInstance();
HifiSockAddr senderSockAddr;
static QByteArray assignmentPacket = byteArrayWithPopulatedHeader(PacketTypeCreateAssignment);
static int numAssignmentPacketHeaderBytes = assignmentPacket.size();
QByteArray receivedPacket;
while (nodeList->getNodeSocket().hasPendingDatagrams()) {
@ -530,22 +538,42 @@ void DomainServer::readAvailableDatagrams() {
nodeList->getNodeSocket().readDatagram(receivedPacket.data(), receivedPacket.size(),
senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer());
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType requestType = packetTypeForPacket(receivedPacket);
if (!_isUsingDTLS) {
// not using DTLS, process datagram normally
processDatagram(receivedPacket, senderSockAddr);
} else {
// we're using DTLS, so tell the sender to get back to us using DTLS
static QByteArray dtlsRequiredPacket = byteArrayWithPopulatedHeader(PacketTypeDomainServerRequireDTLS);
static int numBytesDTLSHeader = numBytesForPacketHeaderGivenPacketType(PacketTypeDomainServerRequireDTLS);
if (requestType == PacketTypeDomainConnectRequest) {
QDataStream packetStream(receivedPacket);
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
quint8 hasRegistrationToken;
packetStream >> hasRegistrationToken;
// we don't require authentication - add this node to our NodeList
// and send back session UUID right away
addNodeToNodeListAndConfirmConnection(receivedPacket, senderSockAddr);
} else if (requestType == PacketTypeDomainListRequest) {
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
if (dtlsRequiredPacket.size() == numBytesDTLSHeader) {
// pack the port that we accept DTLS traffic on
unsigned short dtlsPort = nodeList->getDTLSSocket().localPort();
dtlsRequiredPacket.replace(numBytesDTLSHeader, sizeof(dtlsPort), reinterpret_cast<const char*>(&dtlsPort));
}
nodeList->getNodeSocket().writeDatagram(dtlsRequiredPacket, senderSockAddr.getAddress(), senderSockAddr.getPort());
}
}
}
void DomainServer::readAvailableDTLSDatagrams() {
}
void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) {
NodeList* nodeList = NodeList::getInstance();
static QByteArray assignmentPacket = byteArrayWithPopulatedHeader(PacketTypeCreateAssignment);
static int numAssignmentPacketHeaderBytes = assignmentPacket.size();
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType requestType = packetTypeForPacket(receivedPacket);
if (requestType == PacketTypeDomainListRequest) {
QUuid nodeUUID = uuidFromPacketHeader(receivedPacket);
if (!nodeUUID.isNull() && nodeList->nodeWithUUID(nodeUUID)) {
NodeType_t throwawayNodeType;
HifiSockAddr nodePublicAddress, nodeLocalAddress;
@ -553,69 +581,68 @@ void DomainServer::readAvailableDatagrams() {
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 {
// new node - add this node to our NodeList
// and send back session UUID right away
addNodeToNodeListAndConfirmConnection(receivedPacket, senderSockAddr);
}
} else if (requestType == PacketTypeRequestAssignment) {
// construct the requested assignment from the packet data
Assignment requestAssignment(receivedPacket);
// Suppress these for Assignment::AgentType to once per 5 seconds
static quint64 lastNoisyMessage = usecTimestampNow();
quint64 timeNow = usecTimestampNow();
const quint64 NOISY_TIME_ELAPSED = 5 * USECS_PER_SECOND;
bool noisyMessage = false;
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
<< "from" << senderSockAddr;
noisyMessage = true;
}
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
if (assignmentToDeploy) {
qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << senderSockAddr;
} else if (requestType == PacketTypeRequestAssignment) {
// give this assignment out, either the type matches or the requestor said they will take any
assignmentPacket.resize(numAssignmentPacketHeaderBytes);
// construct the requested assignment from the packet data
Assignment requestAssignment(receivedPacket);
QDataStream assignmentStream(&assignmentPacket, QIODevice::Append);
// Suppress these for Assignment::AgentType to once per 5 seconds
static quint64 lastNoisyMessage = usecTimestampNow();
quint64 timeNow = usecTimestampNow();
const quint64 NOISY_TIME_ELAPSED = 5 * USECS_PER_SECOND;
bool noisyMessage = false;
assignmentStream << *assignmentToDeploy.data();
nodeList->getNodeSocket().writeDatagram(assignmentPacket,
senderSockAddr.getAddress(), senderSockAddr.getPort());
} else {
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
qDebug() << "Received a request for assignment type" << requestAssignment.getType()
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
<< "from" << senderSockAddr;
noisyMessage = true;
}
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
if (assignmentToDeploy) {
qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << senderSockAddr;
// give this assignment out, either the type matches or the requestor said they will take any
assignmentPacket.resize(numAssignmentPacketHeaderBytes);
QDataStream assignmentStream(&assignmentPacket, QIODevice::Append);
assignmentStream << *assignmentToDeploy.data();
nodeList->getNodeSocket().writeDatagram(assignmentPacket,
senderSockAddr.getAddress(), senderSockAddr.getPort());
} else {
if (requestAssignment.getType() != Assignment::AgentType || (timeNow - lastNoisyMessage) > NOISY_TIME_ELAPSED) {
qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType()
<< "from" << senderSockAddr;
noisyMessage = true;
}
}
if (noisyMessage) {
lastNoisyMessage = timeNow;
}
} else if (requestType == PacketTypeNodeJsonStats) {
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
if (matchingNode) {
reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket);
}
}
if (noisyMessage) {
lastNoisyMessage = timeNow;
}
} else if (requestType == PacketTypeNodeJsonStats) {
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
if (matchingNode) {
reinterpret_cast<DomainServerNodeData*>(matchingNode->getLinkedData())->parseJSONStatsPacket(receivedPacket);
}
}
}
}
void DomainServer::readAvailableDTLSDatagrams() {
}
QJsonObject DomainServer::jsonForSocket(const HifiSockAddr& socket) {
QJsonObject socketJSON;

View file

@ -51,7 +51,8 @@ private:
bool optionallySetupDTLS();
bool readX509KeyAndCertificate();
void requestAuthenticationFromPotentialNode(const HifiSockAddr& senderSockAddr);
void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
void addNodeToNodeListAndConfirmConnection(const QByteArray& packet, const HifiSockAddr& senderSockAddr,
const QJsonObject& authJsonObject = QJsonObject());
int parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,

View file

@ -67,6 +67,7 @@ foreach(EXTERNAL_SOURCE_SUBDIR ${EXTERNAL_SOURCE_SUBDIRS})
endforeach(EXTERNAL_SOURCE_SUBDIR)
find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools)
find_package(GnuTLS REQUIRED)
# grab the ui files in resources/ui
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
@ -187,7 +188,7 @@ include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes"
# include external library headers
# use system flag so warnings are supressed
include_directories(SYSTEM "${FACESHIFT_INCLUDE_DIRS}")
include_directories(SYSTEM "${FACESHIFT_INCLUDE_DIRS}" "${GNUTLS_INCLUDE_DIR}")
target_link_libraries(
${TARGET_NAME}
@ -195,6 +196,7 @@ target_link_libraries(
"${ZLIB_LIBRARIES}"
Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL
Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools
"${GNUTLS_LIBRARY}"
)
if (APPLE)

View file

@ -11,6 +11,7 @@ set(TARGET_NAME shared)
project(${TARGET_NAME})
find_package(Qt5 COMPONENTS Network Widgets Xml)
find_package(GnuTLS REQUIRED)
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
setup_hifi_library(${TARGET_NAME})
@ -32,4 +33,5 @@ if (UNIX AND NOT APPLE)
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
endif (UNIX AND NOT APPLE)
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets)
include_directories("${GNUTLS_INCLUDE_DIR}")
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets "${GNUTLS_LIBRARY}")

View file

@ -8,7 +8,7 @@
#include <QtCore/QJsonObject>
#include "AccountManager.h"
#include "PacketHeaders.h"
#include "DomainInfo.h"
@ -16,22 +16,14 @@ DomainInfo::DomainInfo() :
_uuid(),
_sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)),
_assignmentUUID(),
_connectionSecret(),
_registrationToken(),
_rootAuthenticationURL(),
_publicKey(),
_requiresDTLS(false),
_isConnected(false)
{
// clear appropriate variables after a domain-server logout
connect(&AccountManager::getInstance(), &AccountManager::logoutComplete, this, &DomainInfo::logout);
}
void DomainInfo::clearConnectionInfo() {
_uuid = QUuid();
_connectionSecret = QUuid();
_registrationToken = QByteArray();
_rootAuthenticationURL = QUrl();
_publicKey = QString();
_isConnected = false;
}
@ -39,13 +31,7 @@ void DomainInfo::reset() {
clearConnectionInfo();
_hostname = QString();
_sockAddr.setAddress(QHostAddress::Null);
}
void DomainInfo::parseAuthInformationFromJsonObject(const QJsonObject& jsonObject) {
QJsonObject dataObject = jsonObject["data"].toObject();
_connectionSecret = QUuid(dataObject["connection_secret"].toString());
_registrationToken = QByteArray::fromHex(dataObject["registration_token"].toString().toUtf8());
_publicKey = dataObject["public_key"].toString();
_requiresDTLS = false;
}
void DomainInfo::setSockAddr(const HifiSockAddr& sockAddr) {
@ -114,13 +100,15 @@ void DomainInfo::setIsConnected(bool isConnected) {
}
}
void DomainInfo::logout() {
// clear any information related to auth for this domain, assuming it had requested auth
if (!_rootAuthenticationURL.isEmpty()) {
_rootAuthenticationURL = QUrl();
_connectionSecret = QUuid();
_registrationToken = QByteArray();
_publicKey = QString();
_isConnected = false;
}
}
void DomainInfo::parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket) {
// figure out the port that the DS wants us to use for us to talk to them with DTLS
int numBytesPacketHeader = numBytesForPacketHeader(dtlsRequirementPacket);
unsigned short dtlsPort = 0;
memcpy(&dtlsPort, dtlsRequirementPacket.data() + numBytesPacketHeader, sizeof(dtlsPort));
_sockAddr.setPort(dtlsPort);
_requiresDTLS = true;
qDebug() << "domain-server DTLS port changed to" << dtlsPort << "- DTLS enabled.";
}

View file

@ -18,6 +18,7 @@
const QString DEFAULT_DOMAIN_HOSTNAME = "alpha.highfidelity.io";
const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102;
const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = 40103;
class DomainInfo : public QObject {
Q_OBJECT
@ -26,8 +27,6 @@ public:
void clearConnectionInfo();
void parseAuthInformationFromJsonObject(const QJsonObject& jsonObject);
const QUuid& getUUID() const { return _uuid; }
void setUUID(const QUuid& uuid) { _uuid = uuid; }
@ -45,21 +44,13 @@ public:
const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
const QUuid& getConnectionSecret() const { return _connectionSecret; }
void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; }
const QByteArray& getRegistrationToken() const { return _registrationToken; }
const QUrl& getRootAuthenticationURL() const { return _rootAuthenticationURL; }
void setRootAuthenticationURL(const QUrl& rootAuthenticationURL) { _rootAuthenticationURL = rootAuthenticationURL; }
bool isConnected() const { return _isConnected; }
void setIsConnected(bool isConnected);
void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket);
private slots:
void completedHostnameLookup(const QHostInfo& hostInfo);
void logout();
signals:
void hostnameChanged(const QString& hostname);
void connectedToDomain(const QString& hostname);
@ -70,10 +61,7 @@ private:
QString _hostname;
HifiSockAddr _sockAddr;
QUuid _assignmentUUID;
QUuid _connectionSecret;
QByteArray _registrationToken;
QUrl _rootAuthenticationURL;
QString _publicKey;
bool _requiresDTLS;
bool _isConnected;
};

View file

@ -34,11 +34,11 @@ const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://data-web.highfidelity.io");
NodeList* NodeList::_sharedInstance = NULL;
NodeList* NodeList::createInstance(char ownerType, unsigned short int socketListenPort) {
NodeList* NodeList::createInstance(char ownerType, unsigned short socketListenPort, unsigned short dtlsPort) {
if (!_sharedInstance) {
NodeType::init();
_sharedInstance = new NodeList(ownerType, socketListenPort);
_sharedInstance = new NodeList(ownerType, socketListenPort, dtlsPort);
// register the SharedNodePointer meta-type for signals/slots
qRegisterMetaType<SharedNodePointer>();
@ -58,7 +58,7 @@ NodeList* NodeList::getInstance() {
}
NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned short dtlsListenPort) :
_nodeHash(),
_nodeHashMutex(QMutex::Recursive),
_nodeSocket(this),
@ -74,9 +74,15 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
_numCollectedBytes(0),
_packetStatTimer()
{
_nodeSocket.bind(QHostAddress::AnyIPv4, newSocketListenPort);
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
qDebug() << "NodeList socket is listening on" << _nodeSocket.localPort();
if (dtlsListenPort > 0) {
// we have a specfic DTLS port, bind that socket now
_dtlsSocket.bind(QHostAddress::AnyIPv4, dtlsListenPort);
qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket.localPort();
}
// clear our NodeList when the domain changes
connect(&_domainInfo, &DomainInfo::hostnameChanged, this, &NodeList::reset);
@ -141,7 +147,7 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
}
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
<< PacketTypeDomainServerAuthRequest << PacketTypeDomainConnectRequest
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainList << PacketTypeDomainListRequest
<< PacketTypeStunResponse << PacketTypeDataServerConfirm
<< PacketTypeDataServerGet << PacketTypeDataServerPut << PacketTypeDataServerSend
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment;
@ -158,31 +164,6 @@ bool NodeList::packetVersionAndHashMatch(const QByteArray& packet) {
<< uuidFromPacketHeader(packet);
}
} else {
if (checkType == PacketTypeDomainList) {
if (_domainInfo.getRootAuthenticationURL().isEmpty() && _domainInfo.getUUID().isNull()) {
// if this is a domain-server that doesn't require auth,
// pull the UUID from this packet and set it as our domain-server UUID
_domainInfo.setUUID(uuidFromPacketHeader(packet));
// we also know this domain-server requires no authentication
// so set the account manager root URL to the default one
AccountManager::getInstance().setAuthURL(DEFAULT_NODE_AUTH_URL);
}
if (_domainInfo.getUUID() == uuidFromPacketHeader(packet)) {
if (hashForPacketAndConnectionUUID(packet, _domainInfo.getConnectionSecret()) == hashFromPacketHeader(packet)) {
// this is a packet from the domain-server (PacketTypeDomainServerListRequest)
// and the sender UUID matches the UUID we expect for the domain
return true;
} else {
// this is a packet from the domain-server but there is a hash mismatch
qDebug() << "Packet hash mismatch on" << checkType << "from domain-server at" << _domainInfo.getHostname();
return false;
}
}
}
qDebug() << "Packet of type" << checkType << "received from unknown node with UUID"
<< uuidFromPacketHeader(packet);
}
@ -246,7 +227,7 @@ qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) {
statsPacketStream << statsObject.toVariantMap();
return writeDatagram(statsPacket, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret());
return writeDatagram(statsPacket, _domainInfo.getSockAddr(), QUuid());
}
void NodeList::timePingReply(const QByteArray& packet, const SharedNodePointer& sendingNode) {
@ -290,10 +271,8 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr
processDomainServerList(packet);
break;
}
case PacketTypeDomainServerAuthRequest: {
// the domain-server has asked us to auth via a data-server
processDomainServerAuthRequest(packet);
case PacketTypeDomainServerRequireDTLS: {
_domainInfo.parseDTLSRequirementPacket(packet);
break;
}
case PacketTypePing: {
@ -590,61 +569,44 @@ void NodeList::sendDomainServerCheckIn() {
// send a STUN request to figure it out
sendSTUNRequest();
} else if (!_domainInfo.getIP().isNull()) {
if (_domainInfo.getRootAuthenticationURL().isEmpty()
|| !_sessionUUID.isNull()
|| !_domainInfo.getRegistrationToken().isEmpty() ) {
// construct the DS check in packet
PacketType domainPacketType = _sessionUUID.isNull() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest;
QUuid packetUUID = (domainPacketType == PacketTypeDomainListRequest)
? _sessionUUID : _domainInfo.getAssignmentUUID();
QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID);
QDataStream packetStream(&domainServerPacket, QIODevice::Append);
if (domainPacketType == PacketTypeDomainConnectRequest) {
// we may need a registration token to present to the domain-server
packetStream << (quint8) !_domainInfo.getRegistrationToken().isEmpty();
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
packetStream << _ownerType << _publicSockAddr
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
// copy over the bytes for node types of interest, if required
foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
packetStream << nodeTypeOfInterest;
}
writeDatagram(domainServerPacket, _domainInfo.getSockAddr(), _domainInfo.getConnectionSecret());
const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5;
static unsigned int numDomainCheckins = 0;
// send a STUN request every Nth domain server check in so we update our public socket, if required
if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) {
sendSTUNRequest();
}
if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
// so emit our signal that indicates that
emit limitOfSilentDomainCheckInsReached();
}
// increment the count of un-replied check-ins
_numNoReplyDomainCheckIns++;
} else if (AccountManager::getInstance().hasValidAccessToken()) {
// we have an access token we can use for the authentication server the domain-server requested
// so ask that server to provide us with information to connect to the domain-server
requestAuthForDomainServer();
// construct the DS check in packet
PacketType domainPacketType = _sessionUUID.isNull() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest;
QUuid packetUUID = (domainPacketType == PacketTypeDomainListRequest)
? _sessionUUID : _domainInfo.getAssignmentUUID();
QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID);
QDataStream packetStream(&domainServerPacket, QIODevice::Append);
// pack our data to send to the domain-server
packetStream << _ownerType << _publicSockAddr
<< HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort())
<< (quint8) _nodeTypesOfInterest.size();
// copy over the bytes for node types of interest, if required
foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
packetStream << nodeTypeOfInterest;
}
writeDatagram(domainServerPacket, _domainInfo.getSockAddr(), QUuid());
const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5;
static unsigned int numDomainCheckins = 0;
// send a STUN request every Nth domain server check in so we update our public socket, if required
if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) {
sendSTUNRequest();
}
if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
// we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS
// so emit our signal that indicates that
emit limitOfSilentDomainCheckInsReached();
}
// increment the count of un-replied check-ins
_numNoReplyDomainCheckIns++;
}
}
@ -707,41 +669,6 @@ int NodeList::processDomainServerList(const QByteArray& packet) {
return readNodes;
}
void NodeList::domainServerAuthReply(const QJsonObject& jsonObject) {
_domainInfo.parseAuthInformationFromJsonObject(jsonObject);
}
void NodeList::requestAuthForDomainServer() {
JSONCallbackParameters callbackParams;
callbackParams.jsonCallbackReceiver = this;
callbackParams.jsonCallbackMethod = "domainServerAuthReply";
AccountManager::getInstance().authenticatedRequest("/api/v1/domains/"
+ uuidStringWithoutCurlyBraces(_domainInfo.getUUID()) + "/auth.json",
QNetworkAccessManager::GetOperation,
callbackParams);
}
void NodeList::processDomainServerAuthRequest(const QByteArray& packet) {
QDataStream authPacketStream(packet);
authPacketStream.skipRawData(numBytesForPacketHeader(packet));
_domainInfo.setUUID(uuidFromPacketHeader(packet));
AccountManager& accountManager = AccountManager::getInstance();
// grab the hostname this domain-server wants us to authenticate with
QUrl authenticationRootURL;
authPacketStream >> authenticationRootURL;
accountManager.setAuthURL(authenticationRootURL);
_domainInfo.setRootAuthenticationURL(authenticationRootURL);
if (AccountManager::getInstance().checkAndSignalForAccessToken()) {
// request a domain-server auth
requestAuthForDomainServer();
}
}
void NodeList::sendAssignment(Assignment& assignment) {
PacketType assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand

View file

@ -63,7 +63,7 @@ namespace PingType {
class NodeList : public QObject {
Q_OBJECT
public:
static NodeList* createInstance(char ownerType, unsigned short int socketListenPort = 0);
static NodeList* createInstance(char ownerType, unsigned short socketListenPort = 0, unsigned short dtlsPort = 0);
static NodeList* getInstance();
NodeType_t getOwnerType() const { return _ownerType; }
void setOwnerType(NodeType_t ownerType) { _ownerType = ownerType; }
@ -140,12 +140,10 @@ signals:
void nodeAdded(SharedNodePointer);
void nodeKilled(SharedNodePointer);
void limitOfSilentDomainCheckInsReached();
private slots:
void domainServerAuthReply(const QJsonObject& jsonObject);
private:
static NodeList* _sharedInstance;
NodeList(char ownerType, unsigned short int socketListenPort);
NodeList(char ownerType, unsigned short socketListenPort, unsigned short dtlsListenPort);
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();

View file

@ -52,7 +52,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1;
case PacketTypeDomainList:
case PacketTypeDomainListRequest:
return 1;
return 2;
case PacketTypeCreateAssignment:
case PacketTypeRequestAssignment:
return 1;

View file

@ -57,9 +57,9 @@ enum PacketType {
PacketTypeMetavoxelData,
PacketTypeAvatarIdentity,
PacketTypeAvatarBillboard,
PacketTypeDomainConnectRequest,
PacketTypeDomainServerAuthRequest,
PacketTypeNodeJsonStats
PacketTypeDomainConnectRequest, // RE-USABLE
PacketTypeDomainServerRequireDTLS,
PacketTypeNodeJsonStats,
};
typedef char PacketVersion;