Merge branch 'master' of github.com:highfidelity/hifi into no-id-swap-redux

This commit is contained in:
Seth Alves 2015-05-21 09:20:56 -07:00
commit 52ce26d80d
19 changed files with 897 additions and 775 deletions

View file

@ -43,8 +43,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool, AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort, QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
quint16 assignmentMonitorPort) : quint16 assignmentMonitorPort) :
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME), _assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
_localASPortSharedMem(NULL)
{ {
LogUtils::init(); LogUtils::init();
@ -181,8 +180,7 @@ void AssignmentClient::sendAssignmentRequest() {
if (_assignmentServerHostname == "localhost") { if (_assignmentServerHostname == "localhost") {
// we want to check again for the local domain-server port in case the DS has restarted // we want to check again for the local domain-server port in case the DS has restarted
quint16 localAssignmentServerPort; quint16 localAssignmentServerPort;
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem, if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) {
localAssignmentServerPort)) {
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) { if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
qDebug() << "Port for local assignment server read from shared memory is" qDebug() << "Port for local assignment server read from shared memory is"
<< localAssignmentServerPort; << localAssignmentServerPort;
@ -190,7 +188,11 @@ void AssignmentClient::sendAssignmentRequest() {
_assignmentServerSocket.setPort(localAssignmentServerPort); _assignmentServerSocket.setPort(localAssignmentServerPort);
nodeList->setAssignmentServerSocket(_assignmentServerSocket); nodeList->setAssignmentServerSocket(_assignmentServerSocket);
} }
} else {
qDebug() << "Failed to read local assignment server port from shared memory"
<< "- will send assignment request to previous assignment server socket.";
} }
} }
nodeList->sendAssignment(_requestAssignment); nodeList->sendAssignment(_requestAssignment);

View file

@ -44,7 +44,6 @@ private:
QPointer<ThreadedAssignment> _currentAssignment; QPointer<ThreadedAssignment> _currentAssignment;
QString _assignmentServerHostname; QString _assignmentServerHostname;
HifiSockAddr _assignmentServerSocket; HifiSockAddr _assignmentServerSocket;
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
QTimer _requestTimer; // timer for requesting and assignment QTimer _requestTimer; // timer for requesting and assignment
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor QTimer _statsTimerACM; // timer for sending stats to assignment client monitor

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -109,6 +109,13 @@ table {
width: 100%; width: 100%;
} }
/* styling for bootstrap-switch toggles */
.checkbox-help {
margin-top: 10px;
}
/* CSS only spinner for AJAX requests */
.spinner { .spinner {
margin: 30px auto 0; margin: 30px auto 0;
width: 70px; width: 70px;

View file

@ -7,7 +7,9 @@
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen"> <link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/style.css" rel="stylesheet" media="screen"> <link href="/css/style.css" rel="stylesheet" media="screen">
<link href="/css/sweetalert.css" rel="stylesheet" media="screen"> <link href="/css/sweetalert.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-switch.min.css" rel="stylesheet" media="screen">
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen"> <link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
</head> </head>
<body> <body>
<nav class="navbar navbar-default" role="navigation"> <nav class="navbar navbar-default" role="navigation">

View file

@ -99,7 +99,8 @@
<script src='/js/underscore-min.js'></script> <script src='/js/underscore-min.js'></script>
<script src='/js/underscore-keypath.min.js'></script> <script src='/js/underscore-keypath.min.js'></script>
<script src='/js/bootbox.min.js'></script> <script src='/js/bootbox.min.js'></script>
<script src='/js/sweetalert.min.js'></script> <script src='js/bootstrap-switch.min.js'></script>
<script src='/js/settings.js'></script> <script src='js/sweetalert.min.js'></script>
<script src='/js/form2js.min.js'></script> <script src='js/settings.js'></script>
<script src='js/form2js.min.js'></script>
<!--#include virtual="page-end.html"--> <!--#include virtual="page-end.html"-->

File diff suppressed because one or more lines are too long

View file

@ -60,10 +60,15 @@ var viewHelpers = {
if (setting.label) { if (setting.label) {
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>" form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
} }
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
form_group += "<label for='" + keypath + "'>" form_group += "<div class='toggle-checkbox-container" + (isLocked ? " disabled" : "") + "'>"
form_group += "<input type='checkbox'" + common_attrs() + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>" form_group += "<input type='checkbox'" + common_attrs('toggle-checkbox') + (setting_value ? "checked" : "")
form_group += " " + setting.help + "</label>"; form_group += (isLocked ? " disabled" : "") + "/>"
if (setting.help) {
form_group += "<span class='help-block checkbox-help'>" + setting.help + "</span>";
}
form_group += "</div>" form_group += "</div>"
} else { } else {
input_type = _.has(setting, 'type') ? setting.type : "text" input_type = _.has(setting, 'type') ? setting.type : "text"
@ -201,10 +206,17 @@ $(document).ready(function(){
$('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){ $('#' + Settings.FORM_ID).on('change', '.' + Settings.TRIGGER_CHANGE_CLASS , function(){
// this input was changed, add the changed data attribute to it // this input was changed, add the changed data attribute to it
$(this).attr('data-changed', true) $(this).attr('data-changed', true);
badgeSidebarForDifferences($(this)) badgeSidebarForDifferences($(this));
}) });
$('#' + Settings.FORM_ID).on('switchChange.bootstrapSwitch', 'input.toggle-checkbox', function(){
// this checkbox was changed, add the changed data attribute to it
$(this).attr('data-changed', true);
badgeSidebarForDifferences($(this));
});
$('.advanced-toggle').click(function(){ $('.advanced-toggle').click(function(){
Settings.showAdvanced = !Settings.showAdvanced Settings.showAdvanced = !Settings.showAdvanced
@ -735,6 +747,9 @@ function reloadSettings() {
// call our method to setup the place names table // call our method to setup the place names table
setupPlacesTable(); setupPlacesTable();
// setup any bootstrap switches
$('.toggle-checkbox').bootstrapSwitch();
// add tooltip to locked settings // add tooltip to locked settings
$('label.locked').tooltip({ $('label.locked').tooltip({
placement: 'right', placement: 'right',

View file

@ -44,13 +44,10 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923;
const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io";
const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users";
const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity"; const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity";
const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors"; const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors";
const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers"; const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers";
DomainServer::DomainServer(int argc, char* argv[]) : DomainServer::DomainServer(int argc, char* argv[]) :
QCoreApplication(argc, argv), QCoreApplication(argc, 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),
@ -776,9 +773,8 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
const HifiSockAddr& senderSockAddr, const HifiSockAddr& senderSockAddr,
QString& reasonReturn) { QString& reasonReturn) {
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), bool isRestrictingAccess =
ALLOWED_USERS_SETTINGS_KEYPATH); _settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
// we always let in a user who is sending a packet from our local socket or from the localhost address // we always let in a user who is sending a packet from our local socket or from the localhost address
if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress() if (senderSockAddr.getAddress() == DependencyManager::get<LimitedNodeList>()->getLocalSockAddr().getAddress()
@ -786,45 +782,50 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
return true; return true;
} }
if (allowedUsers.count() > 0) { if (isRestrictingAccess) {
QStringList allowedUsers =
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
if (allowedUsers.contains(username, Qt::CaseInsensitive)) { if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
if (verifyUsersKey(username, usernameSignature, reasonReturn)) { if (!verifyUsersKey(username, usernameSignature, reasonReturn)) {
return true; return false;
} }
} else { } else {
qDebug() << "Connect request denied for user" << username << "not in allowed users list."; qDebug() << "Connect request denied for user" << username << "not in allowed users list.";
reasonReturn = "User not on whitelist."; reasonReturn = "User not on whitelist.";
}
return false;
} else {
// we have no allowed user list.
// if this user is in the editors list, exempt them from the max-capacity check return false;
const QVariant* allowedEditorsVariant =
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
if (allowedEditors.contains(username)) {
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
return true;
}
} }
// if we haven't reached max-capacity, let them in.
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
if (maximumUserCapacity > 0) {
unsigned int connectedUsers = countConnectedUsers();
if (connectedUsers >= maximumUserCapacity) {
// too many users, deny the new connection.
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
reasonReturn = "Too many connected users.";
return false;
}
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection.";
}
return true;
} }
// either we aren't restricting users, or this user is in the allowed list
// if this user is in the editors list, exempt them from the max-capacity check
const QVariant* allowedEditorsVariant =
valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_EDITORS_SETTINGS_KEYPATH);
QStringList allowedEditors = allowedEditorsVariant ? allowedEditorsVariant->toStringList() : QStringList();
if (allowedEditors.contains(username)) {
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
return true;
}
}
// if we haven't reached max-capacity, let them in.
const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
if (maximumUserCapacity > 0) {
unsigned int connectedUsers = countConnectedUsers();
if (connectedUsers >= maximumUserCapacity) {
// too many users, deny the new connection.
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection.";
reasonReturn = "Too many connected users.";
return false;
}
qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection.";
}
return true;
} }
void DomainServer::preloadAllowedUserPublicKeys() { void DomainServer::preloadAllowedUserPublicKeys() {
@ -1255,10 +1256,8 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) {
// add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings // add a flag to indicate if this domain uses restricted access - for now that will exclude it from listings
const QString RESTRICTED_ACCESS_FLAG = "restricted"; const QString RESTRICTED_ACCESS_FLAG = "restricted";
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), domainObject[RESTRICTED_ACCESS_FLAG] =
ALLOWED_USERS_SETTINGS_KEYPATH); _settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
domainObject[RESTRICTED_ACCESS_FLAG] = (allowedUsers.size() > 0);
// add the number of currently connected agent users // add the number of currently connected agent users
int numConnectedAuthedUsers = 0; int numConnectedAuthedUsers = 0;

View file

@ -14,6 +14,7 @@
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QJsonArray> #include <QtCore/QJsonArray>
#include <QtCore/QJsonObject> #include <QtCore/QJsonObject>
#include <QtCore/QSettings>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <QtCore/QUrlQuery> #include <QtCore/QUrlQuery>
@ -42,33 +43,73 @@ DomainServerSettingsManager::DomainServerSettingsManager() :
QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH); QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH);
descriptionFile.open(QIODevice::ReadOnly); descriptionFile.open(QIODevice::ReadOnly);
_descriptionArray = QJsonDocument::fromJson(descriptionFile.readAll()).array(); QJsonDocument descriptionDocument = QJsonDocument::fromJson(descriptionFile.readAll());
if (descriptionDocument.isObject()) {
QJsonObject descriptionObject = descriptionDocument.object();
const QString DESCRIPTION_VERSION_KEY = "version";
if (descriptionObject.contains(DESCRIPTION_VERSION_KEY)) {
// read the version from the settings description
_descriptionVersion = descriptionObject[DESCRIPTION_VERSION_KEY].toDouble();
if (descriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
_descriptionArray = descriptionDocument.object()[DESCRIPTION_SETTINGS_KEY].toArray();
return;
}
}
}
qCritical() << "Did not find settings decription in JSON at" << SETTINGS_DESCRIPTION_RELATIVE_PATH
<< "- Unable to continue. domain-server will quit.";
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
} }
void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) { void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) {
_configMap.loadMasterAndUserConfig(argumentList); _configMap.loadMasterAndUserConfig(argumentList);
// for now we perform a temporary transition from http-username and http-password to http_username and http_password // What settings version were we before and what are we using now?
const QVariant* oldUsername = valueForKeyPath(_configMap.getUserConfig(), "security.http-username"); // Do we need to do any re-mapping?
const QVariant* oldPassword = valueForKeyPath(_configMap.getUserConfig(), "security.http-password"); QSettings appSettings;
const QString JSON_SETTINGS_VERSION_KEY = "json-settings/version";
double oldVersion = appSettings.value(JSON_SETTINGS_VERSION_KEY, 0.0).toDouble();
if (oldUsername || oldPassword) { if (oldVersion != _descriptionVersion) {
QVariantMap& settingsMap = *reinterpret_cast<QVariantMap*>(_configMap.getUserConfig()["security"].data()); qDebug() << "Previous domain-server settings version was"
<< QString::number(oldVersion, 'g', 8) << "and the new version is"
<< QString::number(_descriptionVersion, 'g', 8) << "- checking if any re-mapping is required";
// remove old keys, move to new format // we have a version mismatch - for now handle custom behaviour here since there are not many remappings
if (oldUsername) { if (oldVersion < 1.0) {
settingsMap["http_username"] = oldUsername->toString(); // This was prior to the introduction of security.restricted_access
settingsMap.remove("http-username"); // If the user has a list of allowed users then set their value for security.restricted_access to true
QVariant* allowedUsers = valueForKeyPath(_configMap.getMergedConfig(), ALLOWED_USERS_SETTINGS_KEYPATH);
if (allowedUsers
&& allowedUsers->canConvert(QMetaType::QVariantList)
&& reinterpret_cast<QVariantList*>(allowedUsers)->size() > 0) {
qDebug() << "Forcing security.restricted_access to TRUE since there was an"
<< "existing list of allowed users.";
// In the pre-toggle system the user had a list of allowed users, so
// we need to set security.restricted_access to true
QVariant* restrictedAccess = valueForKeyPath(_configMap.getUserConfig(),
RESTRICTED_ACCESS_SETTINGS_KEYPATH,
true);
*restrictedAccess = QVariant(true);
// write the new settings to the json file
persistToFile();
}
} }
if (oldPassword) {
settingsMap["http_password"] = oldPassword->toString();
settingsMap.remove("http-password");
}
// save the updated settings
persistToFile();
} }
// write the current description version to our settings
appSettings.setValue(JSON_SETTINGS_VERSION_KEY, _descriptionVersion);
} }
QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString &keyPath) { QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString &keyPath) {

View file

@ -23,6 +23,9 @@ const QString SETTINGS_PATHS_KEY = "paths";
const QString SETTINGS_PATH = "/settings"; const QString SETTINGS_PATH = "/settings";
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json"; const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users";
const QString RESTRICTED_ACCESS_SETTINGS_KEYPATH = "security.restricted_access";
class DomainServerSettingsManager : public QObject { class DomainServerSettingsManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
@ -44,6 +47,7 @@ private:
QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName); QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
void persistToFile(); void persistToFile();
double _descriptionVersion;
QJsonArray _descriptionArray; QJsonArray _descriptionArray;
HifiConfigVariantMap _configMap; HifiConfigVariantMap _configMap;
}; };

View file

@ -55,46 +55,46 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
static bool firstCall = true; static bool firstCall = true;
if (firstCall) { if (firstCall) {
NodeType::init(); NodeType::init();
// register the SharedNodePointer meta-type for signals/slots // register the SharedNodePointer meta-type for signals/slots
qRegisterMetaType<SharedNodePointer>(); qRegisterMetaType<SharedNodePointer>();
firstCall = false; firstCall = false;
} }
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort); _nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort(); qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort();
if (dtlsListenPort > 0) { if (dtlsListenPort > 0) {
// only create the DTLS socket during constructor if a custom port is passed // only create the DTLS socket during constructor if a custom port is passed
_dtlsSocket = new QUdpSocket(this); _dtlsSocket = new QUdpSocket(this);
_dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort); _dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort);
qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();
} }
const int LARGER_BUFFER_SIZE = 1048576; const int LARGER_BUFFER_SIZE = 1048576;
changeSocketBufferSizes(LARGER_BUFFER_SIZE); changeSocketBufferSizes(LARGER_BUFFER_SIZE);
// check for local socket updates every so often // check for local socket updates every so often
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
QTimer* localSocketUpdate = new QTimer(this); QTimer* localSocketUpdate = new QTimer(this);
connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr); connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr);
localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS); localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS);
QTimer* silentNodeTimer = new QTimer(this); QTimer* silentNodeTimer = new QTimer(this);
connect(silentNodeTimer, &QTimer::timeout, this, &LimitedNodeList::removeSilentNodes); connect(silentNodeTimer, &QTimer::timeout, this, &LimitedNodeList::removeSilentNodes);
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
// check the local socket right now // check the local socket right now
updateLocalSockAddr(); updateLocalSockAddr();
_packetStatTimer.start(); _packetStatTimer.start();
} }
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) { void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
QUuid oldUUID = _sessionUUID; QUuid oldUUID = _sessionUUID;
_sessionUUID = sessionUUID; _sessionUUID = sessionUUID;
if (sessionUUID != oldUUID) { if (sessionUUID != oldUUID) {
qCDebug(networking) << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID) qCDebug(networking) << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID)
<< "to" << uuidStringWithoutCurlyBraces(_sessionUUID); << "to" << uuidStringWithoutCurlyBraces(_sessionUUID);
@ -120,16 +120,16 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() {
if (!_dtlsSocket) { if (!_dtlsSocket) {
// DTLS socket getter called but no DTLS socket exists, create it now // DTLS socket getter called but no DTLS socket exists, create it now
_dtlsSocket = new QUdpSocket(this); _dtlsSocket = new QUdpSocket(this);
_dtlsSocket->bind(QHostAddress::AnyIPv4, 0, QAbstractSocket::DontShareAddress); _dtlsSocket->bind(QHostAddress::AnyIPv4, 0, QAbstractSocket::DontShareAddress);
// we're using DTLS and our socket is good to go, so make the required DTLS changes // we're using DTLS and our socket is good to go, so make the required DTLS changes
// DTLS requires that IP_DONTFRAG be set // DTLS requires that IP_DONTFRAG be set
// This is not accessible on some platforms (OS X) so we need to make sure DTLS still works without it // This is not accessible on some platforms (OS X) so we need to make sure DTLS still works without it
qCDebug(networking) << "LimitedNodeList DTLS socket is listening on" << _dtlsSocket->localPort(); qCDebug(networking) << "LimitedNodeList DTLS socket is listening on" << _dtlsSocket->localPort();
} }
return *_dtlsSocket; return *_dtlsSocket;
} }
@ -140,7 +140,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
if (i == 0) { if (i == 0) {
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption; bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
bufferTypeString = "send"; bufferTypeString = "send";
} else { } else {
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption; bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
bufferTypeString = "receive"; bufferTypeString = "receive";
@ -148,7 +148,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt(); int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
if (oldBufferSize < numBytes) { if (oldBufferSize < numBytes) {
int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt(); int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
<< newBufferSize << "bytes"; << newBufferSize << "bytes";
} else { } else {
@ -162,13 +162,13 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
PacketType checkType = packetTypeForPacket(packet); PacketType checkType = packetTypeForPacket(packet);
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data()); int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
if (packet[numPacketTypeBytes] != versionForPacketType(checkType) if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
&& checkType != PacketTypeStunResponse) { && checkType != PacketTypeStunResponse) {
PacketType mismatchType = packetTypeForPacket(packet); PacketType mismatchType = packetTypeForPacket(packet);
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap; static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
QUuid senderUUID = uuidFromPacketHeader(packet); QUuid senderUUID = uuidFromPacketHeader(packet);
if (!versionDebugSuppressMap.contains(senderUUID, checkType)) { if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender" qCDebug(networking) << "Packet version mismatch on" << packetTypeForPacket(packet) << "- Sender"
@ -176,13 +176,13 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
<< qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected."; << qPrintable(QString::number(versionForPacketType(mismatchType))) << "expected.";
emit packetVersionMismatch(); emit packetVersionMismatch();
versionDebugSuppressMap.insert(senderUUID, checkType); versionDebugSuppressMap.insert(senderUUID, checkType);
} }
return false; return false;
} }
if (!NON_VERIFIED_PACKETS.contains(checkType)) { if (!NON_VERIFIED_PACKETS.contains(checkType)) {
// figure out which node this is from // figure out which node this is from
SharedNodePointer sendingNode = sendingNodeForPacket(packet); SharedNodePointer sendingNode = sendingNodeForPacket(packet);
@ -192,26 +192,26 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
return true; return true;
} else { } else {
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap; static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
QUuid senderUUID = uuidFromPacketHeader(packet); QUuid senderUUID = uuidFromPacketHeader(packet);
if (!hashDebugSuppressMap.contains(senderUUID, checkType)) { if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender" qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
<< uuidFromPacketHeader(packet); << uuidFromPacketHeader(packet);
hashDebugSuppressMap.insert(senderUUID, checkType); hashDebugSuppressMap.insert(senderUUID, checkType);
} }
} }
} else { } else {
static QString repeatedMessage static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID"); = LogHandler::getInstance().addRepeatedMessageRegex("Packet of type \\d+ received from unknown node with UUID");
qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID" qCDebug(networking) << "Packet of type" << checkType << "received from unknown node with UUID"
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet))); << qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
} }
} else { } else {
return true; return true;
} }
return false; return false;
} }
@ -226,7 +226,7 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a
} else { } else {
emit dataReceived(NodeType::Unassigned, incomingPacket.size()); emit dataReceived(NodeType::Unassigned, incomingPacket.size());
} }
return result; return result;
} }
@ -235,14 +235,14 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock
// stat collection for packets // stat collection for packets
++_numCollectedPackets; ++_numCollectedPackets;
_numCollectedBytes += datagram.size(); _numCollectedBytes += datagram.size();
qint64 bytesWritten = _nodeSocket.writeDatagram(datagram, qint64 bytesWritten = _nodeSocket.writeDatagram(datagram,
destinationSockAddr.getAddress(), destinationSockAddr.getPort()); destinationSockAddr.getAddress(), destinationSockAddr.getPort());
if (bytesWritten < 0) { if (bytesWritten < 0) {
qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString(); qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString();
} }
return bytesWritten; return bytesWritten;
} }
@ -269,7 +269,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
} }
QByteArray datagramCopy = datagram; QByteArray datagramCopy = datagram;
// if we're here and the connection secret is null, debug out - this could be a problem // if we're here and the connection secret is null, debug out - this could be a problem
if (destinationNode->getConnectionSecret().isNull()) { if (destinationNode->getConnectionSecret().isNull()) {
qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for" qDebug() << "LimitedNodeList::writeDatagram called for verified datagram with null connection secret for"
@ -278,21 +278,21 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
} }
// perform replacement of hash and optionally also sequence number in the header // perform replacement of hash and optionally also sequence number in the header
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType); PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(), replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(),
sequenceNumber, packetType); sequenceNumber, packetType);
} else { } else {
replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType); replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType);
} }
emit dataSent(destinationNode->getType(), datagram.size()); emit dataSent(destinationNode->getType(), datagram.size());
auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr); auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr);
// Keep track of per-destination-node bandwidth // Keep track of per-destination-node bandwidth
destinationNode->recordBytesSent(bytesWritten); destinationNode->recordBytesSent(bytesWritten);
return bytesWritten; return bytesWritten;
} }
// didn't have a destinationNode to send to, return 0 // didn't have a destinationNode to send to, return 0
return 0; return 0;
} }
@ -311,7 +311,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
return 0; return 0;
} }
} }
PacketType packetType = packetTypeForPacket(datagram); PacketType packetType = packetTypeForPacket(datagram);
// optionally peform sequence number replacement in the header // optionally peform sequence number replacement in the header
@ -328,7 +328,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
return writeDatagram(datagram, *destinationSockAddr); return writeDatagram(datagram, *destinationSockAddr);
} }
} }
// didn't have a destinationNode to send to, return 0 // didn't have a destinationNode to send to, return 0
return 0; return 0;
} }
@ -348,11 +348,11 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, c
} }
PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) { PacketSequenceNumber LimitedNodeList::getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType) {
// Thanks to std::map and std::unordered_map this line either default constructs the // Thanks to std::map and std::unordered_map this line either default constructs the
// PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value. // PacketTypeSequenceMap and the PacketSequenceNumber or returns the existing value.
// We use the postfix increment so that the stored value is incremented and the next // We use the postfix increment so that the stored value is incremented and the next
// return gives the correct value. // return gives the correct value.
return _packetSequenceNumbers[nodeUUID][packetType]++; return _packetSequenceNumbers[nodeUUID][packetType]++;
} }
@ -367,21 +367,21 @@ void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) { int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
QMutexLocker locker(&matchingNode->getMutex()); QMutexLocker locker(&matchingNode->getMutex());
matchingNode->setLastHeardMicrostamp(usecTimestampNow()); matchingNode->setLastHeardMicrostamp(usecTimestampNow());
// if this was a sequence numbered packet we should store the last seq number for // if this was a sequence numbered packet we should store the last seq number for
// a packet of this type for this node // a packet of this type for this node
PacketType packetType = packetTypeForPacket(packet); PacketType packetType = packetTypeForPacket(packet);
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) { if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType); matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
} }
NodeData* linkedData = matchingNode->getLinkedData(); NodeData* linkedData = matchingNode->getLinkedData();
if (!linkedData && linkedDataCreateCallback) { if (!linkedData && linkedDataCreateCallback) {
linkedDataCreateCallback(matchingNode.data()); linkedDataCreateCallback(matchingNode.data());
} }
if (linkedData) { if (linkedData) {
QMutexLocker linkedDataLocker(&linkedData->getMutex()); QMutexLocker linkedDataLocker(&linkedData->getMutex());
return linkedData->parseData(packet); return linkedData->parseData(packet);
@ -391,42 +391,42 @@ int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& match
int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) { int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
SharedNodePointer matchingNode = sendingNodeForPacket(packet); SharedNodePointer matchingNode = sendingNodeForPacket(packet);
if (matchingNode) { if (matchingNode) {
return updateNodeWithDataFromPacket(matchingNode, packet); return updateNodeWithDataFromPacket(matchingNode, packet);
} }
// we weren't able to match the sender address to the address we have for this node, unlock and don't parse // we weren't able to match the sender address to the address we have for this node, unlock and don't parse
return 0; return 0;
} }
SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) { SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
QReadLocker readLocker(&_nodeMutex); QReadLocker readLocker(&_nodeMutex);
NodeHash::const_iterator it = _nodeHash.find(nodeUUID); NodeHash::const_iterator it = _nodeHash.find(nodeUUID);
return it == _nodeHash.cend() ? SharedNodePointer() : it->second; return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
} }
SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) { SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) {
QUuid nodeUUID = uuidFromPacketHeader(packet); QUuid nodeUUID = uuidFromPacketHeader(packet);
// return the matching node, or NULL if there is no match // return the matching node, or NULL if there is no match
return nodeWithUUID(nodeUUID); return nodeWithUUID(nodeUUID);
} }
void LimitedNodeList::eraseAllNodes() { void LimitedNodeList::eraseAllNodes() {
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list."; qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
QSet<SharedNodePointer> killedNodes; QSet<SharedNodePointer> killedNodes;
eachNode([&killedNodes](const SharedNodePointer& node){ eachNode([&killedNodes](const SharedNodePointer& node){
killedNodes.insert(node); killedNodes.insert(node);
}); });
// iterate the current nodes, emit that they are dying and remove them from the hash // iterate the current nodes, emit that they are dying and remove them from the hash
_nodeMutex.lockForWrite(); _nodeMutex.lockForWrite();
_nodeHash.clear(); _nodeHash.clear();
_nodeMutex.unlock(); _nodeMutex.unlock();
foreach(const SharedNodePointer& killedNode, killedNodes) { foreach(const SharedNodePointer& killedNode, killedNodes) {
handleNodeKill(killedNode); handleNodeKill(killedNode);
} }
@ -438,17 +438,17 @@ void LimitedNodeList::reset() {
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
_nodeMutex.lockForRead(); _nodeMutex.lockForRead();
NodeHash::iterator it = _nodeHash.find(nodeUUID); NodeHash::iterator it = _nodeHash.find(nodeUUID);
if (it != _nodeHash.end()) { if (it != _nodeHash.end()) {
SharedNodePointer matchingNode = it->second; SharedNodePointer matchingNode = it->second;
_nodeMutex.unlock(); _nodeMutex.unlock();
_nodeMutex.lockForWrite(); _nodeMutex.lockForWrite();
_nodeHash.unsafe_erase(it); _nodeHash.unsafe_erase(it);
_nodeMutex.unlock(); _nodeMutex.unlock();
handleNodeKill(matchingNode); handleNodeKill(matchingNode);
} else { } else {
_nodeMutex.unlock(); _nodeMutex.unlock();
@ -472,34 +472,34 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
bool canAdjustLocks, bool canRez) { bool canAdjustLocks, bool canRez) {
NodeHash::const_iterator it = _nodeHash.find(uuid); NodeHash::const_iterator it = _nodeHash.find(uuid);
if (it != _nodeHash.end()) { if (it != _nodeHash.end()) {
SharedNodePointer& matchingNode = it->second; SharedNodePointer& matchingNode = it->second;
matchingNode->setPublicSocket(publicSocket); matchingNode->setPublicSocket(publicSocket);
matchingNode->setLocalSocket(localSocket); matchingNode->setLocalSocket(localSocket);
matchingNode->setCanAdjustLocks(canAdjustLocks); matchingNode->setCanAdjustLocks(canAdjustLocks);
matchingNode->setCanRez(canRez); matchingNode->setCanRez(canRez);
return matchingNode; return matchingNode;
} else { } else {
// 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, canAdjustLocks, canRez); Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez);
SharedNodePointer newNodePointer(newNode); SharedNodePointer newNodePointer(newNode);
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); _nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
qCDebug(networking) << "Added" << *newNode; qCDebug(networking) << "Added" << *newNode;
emit nodeAdded(newNodePointer); emit nodeAdded(newNodePointer);
return newNodePointer; return newNodePointer;
} }
} }
unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) { unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
unsigned n = 0; unsigned n = 0;
eachNode([&](const SharedNodePointer& node){ eachNode([&](const SharedNodePointer& node){
if (destinationNodeTypes.contains(node->getType())) { if (destinationNodeTypes.contains(node->getType())) {
writeDatagram(packet, node); writeDatagram(packet, node);
@ -516,35 +516,35 @@ QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVeri
QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing, QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing,
packetUUID); packetUUID);
QDataStream packetStream(&pingPacket, QIODevice::Append); QDataStream packetStream(&pingPacket, QIODevice::Append);
packetStream << pingType; packetStream << pingType;
packetStream << usecTimestampNow(); packetStream << usecTimestampNow();
return pingPacket; return pingPacket;
} }
QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) { QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) {
QDataStream pingPacketStream(pingPacket); QDataStream pingPacketStream(pingPacket);
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
PingType_t typeFromOriginalPing; PingType_t typeFromOriginalPing;
pingPacketStream >> typeFromOriginalPing; pingPacketStream >> typeFromOriginalPing;
quint64 timeFromOriginalPing; quint64 timeFromOriginalPing;
pingPacketStream >> timeFromOriginalPing; pingPacketStream >> timeFromOriginalPing;
PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing) PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing)
? PacketTypePingReply : PacketTypeUnverifiedPingReply; ? PacketTypePingReply : PacketTypeUnverifiedPingReply;
QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID; QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID;
QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID); QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID);
QDataStream packetStream(&replyPacket, QIODevice::Append); QDataStream packetStream(&replyPacket, QIODevice::Append);
packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
return replyPacket; return replyPacket;
} }
@ -566,9 +566,9 @@ void LimitedNodeList::resetPacketStats() {
} }
void LimitedNodeList::removeSilentNodes() { void LimitedNodeList::removeSilentNodes() {
QSet<SharedNodePointer> killedNodes; QSet<SharedNodePointer> killedNodes;
eachNodeHashIterator([&](NodeHash::iterator& it){ eachNodeHashIterator([&](NodeHash::iterator& it){
SharedNodePointer node = it->second; SharedNodePointer node = it->second;
node->getMutex().lock(); node->getMutex().lock();
@ -582,10 +582,10 @@ void LimitedNodeList::removeSilentNodes() {
// we didn't erase this node, push the iterator forwards // we didn't erase this node, push the iterator forwards
++it; ++it;
} }
node->getMutex().unlock(); node->getMutex().unlock();
}); });
foreach(const SharedNodePointer& killedNode, killedNodes) { foreach(const SharedNodePointer& killedNode, killedNodes) {
handleNodeKill(killedNode); handleNodeKill(killedNode);
} }
@ -595,38 +595,38 @@ const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
const int NUM_BYTES_STUN_HEADER = 20; const int NUM_BYTES_STUN_HEADER = 20;
void LimitedNodeList::sendSTUNRequest() { void LimitedNodeList::sendSTUNRequest() {
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER]; unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
int packetIndex = 0; int packetIndex = 0;
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE); const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
// leading zeros + message type // leading zeros + message type
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001); const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE)); memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
packetIndex += sizeof(REQUEST_MESSAGE_TYPE); packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
// message length (no additional attributes are included) // message length (no additional attributes are included)
uint16_t messageLength = 0; uint16_t messageLength = 0;
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength)); memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
packetIndex += sizeof(messageLength); packetIndex += sizeof(messageLength);
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)); memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER); packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
// transaction ID (random 12-byte unsigned integer) // transaction ID (random 12-byte unsigned integer)
const uint NUM_TRANSACTION_ID_BYTES = 12; const uint NUM_TRANSACTION_ID_BYTES = 12;
QUuid randomUUID = QUuid::createUuid(); QUuid randomUUID = QUuid::createUuid();
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES); memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
_stunSockAddr.getAddress(), _stunSockAddr.getPort()); _stunSockAddr.getAddress(), _stunSockAddr.getPort());
} }
void LimitedNodeList::rebindNodeSocket() { void LimitedNodeList::rebindNodeSocket() {
quint16 oldPort = _nodeSocket.localPort(); quint16 oldPort = _nodeSocket.localPort();
_nodeSocket.close(); _nodeSocket.close();
_nodeSocket.bind(QHostAddress::AnyIPv4, oldPort); _nodeSocket.bind(QHostAddress::AnyIPv4, oldPort);
} }
@ -636,125 +636,125 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) {
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS // and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4; const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020); const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE); const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
int attributeStartIndex = NUM_BYTES_STUN_HEADER; int attributeStartIndex = NUM_BYTES_STUN_HEADER;
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH, if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) { sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE // enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
while (attributeStartIndex < packet.size()) { while (attributeStartIndex < packet.size()) {
if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) { if (memcmp(packet.data() + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4; const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
const int NUM_BYTES_FAMILY_ALIGN = 1; const int NUM_BYTES_FAMILY_ALIGN = 1;
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8; const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN; int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
uint8_t addressFamily = 0; uint8_t addressFamily = 0;
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily)); memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
byteIndex += sizeof(addressFamily); byteIndex += sizeof(addressFamily);
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) { if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
// grab the X-Port // grab the X-Port
uint16_t xorMappedPort = 0; uint16_t xorMappedPort = 0;
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort)); memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16); uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
byteIndex += sizeof(xorMappedPort); byteIndex += sizeof(xorMappedPort);
// grab the X-Address // grab the X-Address
uint32_t xorMappedAddress = 0; uint32_t xorMappedAddress = 0;
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress)); memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER); uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
QHostAddress newPublicAddress = QHostAddress(stunAddress); QHostAddress newPublicAddress = QHostAddress(stunAddress);
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) { if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort); _publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
qCDebug(networking, "New public socket received from STUN server is %s:%hu", qCDebug(networking, "New public socket received from STUN server is %s:%hu",
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(), _publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
_publicSockAddr.getPort()); _publicSockAddr.getPort());
emit publicSockAddrChanged(_publicSockAddr); emit publicSockAddrChanged(_publicSockAddr);
} }
return true; return true;
} }
} else { } else {
// push forward attributeStartIndex by the length of this attribute // push forward attributeStartIndex by the length of this attribute
const int NUM_BYTES_ATTRIBUTE_TYPE = 2; const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
uint16_t attributeLength = 0; uint16_t attributeLength = 0;
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE, memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
sizeof(attributeLength)); sizeof(attributeLength));
attributeLength = ntohs(attributeLength); attributeLength = ntohs(attributeLength);
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength; attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
} }
} }
} }
return false; return false;
} }
void LimitedNodeList::updateLocalSockAddr() { void LimitedNodeList::updateLocalSockAddr() {
HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort()); HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort());
if (newSockAddr != _localSockAddr) { if (newSockAddr != _localSockAddr) {
if (_localSockAddr.isNull()) { if (_localSockAddr.isNull()) {
qCDebug(networking) << "Local socket is" << newSockAddr; qCDebug(networking) << "Local socket is" << newSockAddr;
} else { } else {
qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr; qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
} }
_localSockAddr = newSockAddr; _localSockAddr = newSockAddr;
emit localSockAddrChanged(_localSockAddr); emit localSockAddrChanged(_localSockAddr);
} }
} }
void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
QUuid headerID, const QUuid& connectionRequestID) { QUuid headerID, const QUuid& connectionRequestID) {
if (headerID.isNull()) { if (headerID.isNull()) {
headerID = _sessionUUID; headerID = _sessionUUID;
} }
QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
iceDataStream << _publicSockAddr << _localSockAddr; iceDataStream << _publicSockAddr << _localSockAddr;
if (!connectionRequestID.isNull()) { if (!connectionRequestID.isNull()) {
iceDataStream << connectionRequestID; iceDataStream << connectionRequestID;
qCDebug(networking) << "Sending packet to ICE server to request connection info for peer with ID" qCDebug(networking) << "Sending packet to ICE server to request connection info for peer with ID"
<< uuidStringWithoutCurlyBraces(connectionRequestID); << uuidStringWithoutCurlyBraces(connectionRequestID);
} }
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr); writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
} }
void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort) { void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort) {
// save our local port to shared memory so that assignment client children know how to talk to this parent // save our local port to shared memory so that assignment client children know how to talk to this parent
QSharedMemory* sharedPortMem = new QSharedMemory(key, parent); QSharedMemory* sharedPortMem = new QSharedMemory(key, parent);
// attempt to create the shared memory segment // attempt to create the shared memory segment
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) { if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
sharedPortMem->lock(); sharedPortMem->lock();
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort)); memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
sharedPortMem->unlock(); sharedPortMem->unlock();
qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key; qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key;
} else { } else {
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children."; qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
@ -762,22 +762,15 @@ void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* p
} }
bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, quint16& localPort) {
quint16& localPort) { QSharedMemory sharedMem(key);
if (!sharedMem) { if (!sharedMem.attach(QSharedMemory::ReadOnly)) {
sharedMem = new QSharedMemory(key, this); qWarning() << "Could not attach to shared memory at key" << key;
return false;
if (!sharedMem->attach(QSharedMemory::ReadOnly)) { } else {
qWarning() << "Could not attach to shared memory at key" << key; sharedMem.lock();
} memcpy(&localPort, sharedMem.data(), sizeof(localPort));
} sharedMem.unlock();
if (sharedMem->isAttached()) {
sharedMem->lock();
memcpy(&localPort, sharedMem->data(), sizeof(localPort));
sharedMem->unlock();
return true; return true;
} }
return false;
} }

View file

@ -79,7 +79,7 @@ namespace PingType {
class LimitedNodeList : public QObject, public Dependency { class LimitedNodeList : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
public: public:
const QUuid& getSessionUUID() const { return _sessionUUID; } const QUuid& getSessionUUID() const { return _sessionUUID; }
void setSessionUUID(const QUuid& sessionUUID); void setSessionUUID(const QUuid& sessionUUID);
@ -89,22 +89,22 @@ public:
bool getThisNodeCanRez() const { return _thisNodeCanRez; } bool getThisNodeCanRez() const { return _thisNodeCanRez; }
void setThisNodeCanRez(bool canRez); void setThisNodeCanRez(bool canRez);
void rebindNodeSocket(); void rebindNodeSocket();
QUdpSocket& getNodeSocket() { return _nodeSocket; } QUdpSocket& getNodeSocket() { return _nodeSocket; }
QUdpSocket& getDTLSSocket(); QUdpSocket& getDTLSSocket();
bool packetVersionAndHashMatch(const QByteArray& packet); bool packetVersionAndHashMatch(const QByteArray& packet);
QByteArray byteArrayWithPopulatedHeader(PacketType packetType) QByteArray byteArrayWithPopulatedHeader(PacketType packetType)
{ return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); } { return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); }
int populatePacketHeader(QByteArray& packet, PacketType packetType) int populatePacketHeader(QByteArray& packet, PacketType packetType)
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); } { return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
int populatePacketHeader(char* packet, PacketType packetType) int populatePacketHeader(char* packet, PacketType packetType)
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); } { return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port); qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode, qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr = HifiSockAddr()); const HifiSockAddr& overridenSockAddr = HifiSockAddr());
@ -120,16 +120,16 @@ public:
const HifiSockAddr& overridenSockAddr = HifiSockAddr()); const HifiSockAddr& overridenSockAddr = HifiSockAddr());
void (*linkedDataCreateCallback)(Node *); void (*linkedDataCreateCallback)(Node *);
int size() const { return _nodeHash.size(); } int size() const { return _nodeHash.size(); }
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID); SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
SharedNodePointer sendingNodeForPacket(const QByteArray& packet); SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType, SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
bool canAdjustLocks, bool canRez); bool canAdjustLocks, bool canRez);
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
@ -144,21 +144,21 @@ public:
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
void resetPacketStats(); void resetPacketStats();
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true, QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true,
const QUuid& packetHeaderID = QUuid()); const QUuid& packetHeaderID = QUuid());
QByteArray constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID = QUuid()); QByteArray constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID = QUuid());
virtual void sendSTUNRequest(); virtual void sendSTUNRequest();
virtual bool processSTUNResponse(const QByteArray& packet); virtual bool processSTUNResponse(const QByteArray& packet);
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid()); QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid());
template<typename NodeLambda> template<typename NodeLambda>
void eachNode(NodeLambda functor) { void eachNode(NodeLambda functor) {
QReadLocker readLock(&_nodeMutex); QReadLocker readLock(&_nodeMutex);
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
functor(it->second); functor(it->second);
} }
@ -178,44 +178,44 @@ public:
template<typename BreakableNodeLambda> template<typename BreakableNodeLambda>
void eachNodeBreakable(BreakableNodeLambda functor) { void eachNodeBreakable(BreakableNodeLambda functor) {
QReadLocker readLock(&_nodeMutex); QReadLocker readLock(&_nodeMutex);
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
if (!functor(it->second)) { if (!functor(it->second)) {
break; break;
} }
} }
} }
template<typename PredLambda> template<typename PredLambda>
SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) { SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) {
QReadLocker readLock(&_nodeMutex); QReadLocker readLock(&_nodeMutex);
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) { for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
if (predicate(it->second)) { if (predicate(it->second)) {
return it->second; return it->second;
} }
} }
return SharedNodePointer(); return SharedNodePointer();
} }
void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort); void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort);
bool getLocalServerPortFromSharedMemory(const QString key, QSharedMemory*& sharedMem, quint16& localPort); bool getLocalServerPortFromSharedMemory(const QString key, quint16& localPort);
public slots: public slots:
void reset(); void reset();
void eraseAllNodes(); void eraseAllNodes();
void removeSilentNodes(); void removeSilentNodes();
void updateLocalSockAddr(); void updateLocalSockAddr();
void killNodeWithUUID(const QUuid& nodeUUID); void killNodeWithUUID(const QUuid& nodeUUID);
signals: signals:
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
void nodeAdded(SharedNodePointer); void nodeAdded(SharedNodePointer);
void nodeKilled(SharedNodePointer); void nodeKilled(SharedNodePointer);
void localSockAddrChanged(const HifiSockAddr& localSockAddr); void localSockAddrChanged(const HifiSockAddr& localSockAddr);
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
@ -226,18 +226,18 @@ signals:
void dataReceived(const quint8 channel_type, const int bytes); void dataReceived(const quint8 channel_type, const int bytes);
void packetVersionMismatch(); void packetVersionMismatch();
protected: protected:
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr); qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr);
PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType); PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType);
void changeSocketBufferSizes(int numBytes); void changeSocketBufferSizes(int numBytes);
void handleNodeKill(const SharedNodePointer& node); void handleNodeKill(const SharedNodePointer& node);
QUuid _sessionUUID; QUuid _sessionUUID;
@ -258,17 +258,17 @@ protected:
bool _thisNodeCanRez; bool _thisNodeCanRez;
std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers; std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers;
template<typename IteratorLambda> template<typename IteratorLambda>
void eachNodeHashIterator(IteratorLambda functor) { void eachNodeHashIterator(IteratorLambda functor) {
QWriteLocker writeLock(&_nodeMutex); QWriteLocker writeLock(&_nodeMutex);
NodeHash::iterator it = _nodeHash.begin(); NodeHash::iterator it = _nodeHash.begin();
while (it != _nodeHash.end()) { while (it != _nodeHash.end()) {
functor(it); functor(it);
} }
} }
}; };
#endif // hifi_LimitedNodeList_h #endif // hifi_LimitedNodeList_h

View file

@ -335,12 +335,8 @@ void NodeList::sendDomainServerCheckIn() {
if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost
|| _domainHandler.getHostname() == "localhost") { || _domainHandler.getHostname() == "localhost") {
static QSharedMemory* localDSPortSharedMem = NULL;
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT; quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, domainPort);
localDSPortSharedMem,
domainPort);
qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort; qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort;
_domainHandler.setPort(domainPort); _domainHandler.setPort(domainPort);
} }

View file

@ -159,16 +159,17 @@ void HifiConfigVariantMap::addMissingValuesToExistingMap(QVariantMap& existingMa
} }
} }
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath) { QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool shouldCreateIfMissing) {
int dotIndex = keyPath.indexOf('.'); int dotIndex = keyPath.indexOf('.');
QString firstKey = (dotIndex == -1) ? keyPath : keyPath.mid(0, dotIndex); QString firstKey = (dotIndex == -1) ? keyPath : keyPath.mid(0, dotIndex);
if (variantMap.contains(firstKey)) { if (shouldCreateIfMissing || variantMap.contains(firstKey)) {
if (dotIndex == -1) { if (dotIndex == -1) {
return &variantMap[firstKey]; return &variantMap[firstKey];
} else if (variantMap[firstKey].canConvert(QMetaType::QVariantMap)) { } else if (variantMap[firstKey].canConvert(QMetaType::QVariantMap)) {
return valueForKeyPath(*static_cast<QVariantMap*>(variantMap[firstKey].data()), keyPath.mid(dotIndex + 1)); return valueForKeyPath(*static_cast<QVariantMap*>(variantMap[firstKey].data()), keyPath.mid(dotIndex + 1),
shouldCreateIfMissing);
} }
} }

View file

@ -37,6 +37,6 @@ private:
void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap); void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap);
}; };
QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath); QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath, bool shouldCreateIfMissing = false);
#endif // hifi_HifiConfigVariantMap_h #endif // hifi_HifiConfigVariantMap_h