mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-15 21:18:06 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into no-id-swap-redux
This commit is contained in:
commit
52ce26d80d
19 changed files with 897 additions and 775 deletions
|
@ -43,8 +43,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
|||
AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QString assignmentPool,
|
||||
QUuid walletUUID, QString assignmentServerHostname, quint16 assignmentServerPort,
|
||||
quint16 assignmentMonitorPort) :
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||
_localASPortSharedMem(NULL)
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
|
||||
{
|
||||
LogUtils::init();
|
||||
|
||||
|
@ -181,8 +180,7 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
if (_assignmentServerHostname == "localhost") {
|
||||
// we want to check again for the local domain-server port in case the DS has restarted
|
||||
quint16 localAssignmentServerPort;
|
||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, _localASPortSharedMem,
|
||||
localAssignmentServerPort)) {
|
||||
if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) {
|
||||
if (localAssignmentServerPort != _assignmentServerSocket.getPort()) {
|
||||
qDebug() << "Port for local assignment server read from shared memory is"
|
||||
<< localAssignmentServerPort;
|
||||
|
@ -190,7 +188,11 @@ void AssignmentClient::sendAssignmentRequest() {
|
|||
_assignmentServerSocket.setPort(localAssignmentServerPort);
|
||||
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);
|
||||
|
|
|
@ -44,7 +44,6 @@ private:
|
|||
QPointer<ThreadedAssignment> _currentAssignment;
|
||||
QString _assignmentServerHostname;
|
||||
HifiSockAddr _assignmentServerSocket;
|
||||
QSharedMemory* _localASPortSharedMem; // memory shared with domain server
|
||||
QTimer _requestTimer; // timer for requesting and assignment
|
||||
QTimer _statsTimerACM; // timer for sending stats to assignment client monitor
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
22
domain-server/resources/web/css/bootstrap-switch.min.css
vendored
Executable file
22
domain-server/resources/web/css/bootstrap-switch.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -109,6 +109,13 @@ table {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
/* styling for bootstrap-switch toggles */
|
||||
.checkbox-help {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* CSS only spinner for AJAX requests */
|
||||
|
||||
.spinner {
|
||||
margin: 30px auto 0;
|
||||
width: 70px;
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
<link href="/css/bootstrap.min.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/bootstrap-switch.min.css" rel="stylesheet" media="screen">
|
||||
<link href="/stats/css/json.human.css" rel="stylesheet" media="screen">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
|
|
|
@ -99,7 +99,8 @@
|
|||
<script src='/js/underscore-min.js'></script>
|
||||
<script src='/js/underscore-keypath.min.js'></script>
|
||||
<script src='/js/bootbox.min.js'></script>
|
||||
<script src='/js/sweetalert.min.js'></script>
|
||||
<script src='/js/settings.js'></script>
|
||||
<script src='/js/form2js.min.js'></script>
|
||||
<script src='js/bootstrap-switch.min.js'></script>
|
||||
<script src='js/sweetalert.min.js'></script>
|
||||
<script src='js/settings.js'></script>
|
||||
<script src='js/form2js.min.js'></script>
|
||||
<!--#include virtual="page-end.html"-->
|
||||
|
|
22
domain-server/resources/web/settings/js/bootstrap-switch.min.js
vendored
Executable file
22
domain-server/resources/web/settings/js/bootstrap-switch.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -60,10 +60,15 @@ var viewHelpers = {
|
|||
if (setting.label) {
|
||||
form_group += "<label class='" + label_class + "'>" + setting.label + "</label>"
|
||||
}
|
||||
form_group += "<div class='checkbox" + (isLocked ? " disabled" : "") + "'>"
|
||||
form_group += "<label for='" + keypath + "'>"
|
||||
form_group += "<input type='checkbox'" + common_attrs() + (setting_value ? "checked" : "") + (isLocked ? " disabled" : "") + "/>"
|
||||
form_group += " " + setting.help + "</label>";
|
||||
|
||||
form_group += "<div class='toggle-checkbox-container" + (isLocked ? " disabled" : "") + "'>"
|
||||
form_group += "<input type='checkbox'" + common_attrs('toggle-checkbox') + (setting_value ? "checked" : "")
|
||||
form_group += (isLocked ? " disabled" : "") + "/>"
|
||||
|
||||
if (setting.help) {
|
||||
form_group += "<span class='help-block checkbox-help'>" + setting.help + "</span>";
|
||||
}
|
||||
|
||||
form_group += "</div>"
|
||||
} else {
|
||||
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(){
|
||||
// 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(){
|
||||
Settings.showAdvanced = !Settings.showAdvanced
|
||||
|
@ -735,6 +747,9 @@ function reloadSettings() {
|
|||
// call our method to setup the place names table
|
||||
setupPlacesTable();
|
||||
|
||||
// setup any bootstrap switches
|
||||
$('.toggle-checkbox').bootstrapSwitch();
|
||||
|
||||
// add tooltip to locked settings
|
||||
$('label.locked').tooltip({
|
||||
placement: 'right',
|
|
@ -44,13 +44,10 @@ int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
|||
|
||||
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 ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors";
|
||||
const QString EDITORS_ARE_REZZERS_KEYPATH = "security.editors_are_rezzers";
|
||||
|
||||
|
||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_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,
|
||||
QString& reasonReturn) {
|
||||
|
||||
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(),
|
||||
ALLOWED_USERS_SETTINGS_KEYPATH);
|
||||
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
|
||||
bool isRestrictingAccess =
|
||||
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||
|
||||
// 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()
|
||||
|
@ -786,45 +782,50 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (allowedUsers.count() > 0) {
|
||||
if (isRestrictingAccess) {
|
||||
|
||||
QStringList allowedUsers =
|
||||
_settingsManager.valueOrDefaultValueForKeyPath(ALLOWED_USERS_SETTINGS_KEYPATH).toStringList();
|
||||
|
||||
if (allowedUsers.contains(username, Qt::CaseInsensitive)) {
|
||||
if (verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
||||
return true;
|
||||
if (!verifyUsersKey(username, usernameSignature, reasonReturn)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Connect request denied for user" << username << "not in allowed users list.";
|
||||
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
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
|
@ -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
|
||||
const QString RESTRICTED_ACCESS_FLAG = "restricted";
|
||||
|
||||
const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(),
|
||||
ALLOWED_USERS_SETTINGS_KEYPATH);
|
||||
QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
|
||||
domainObject[RESTRICTED_ACCESS_FLAG] = (allowedUsers.size() > 0);
|
||||
domainObject[RESTRICTED_ACCESS_FLAG] =
|
||||
_settingsManager.valueOrDefaultValueForKeyPath(RESTRICTED_ACCESS_SETTINGS_KEYPATH).toBool();
|
||||
|
||||
// add the number of currently connected agent users
|
||||
int numConnectedAuthedUsers = 0;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <QtCore/QFile>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonObject>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUrlQuery>
|
||||
|
@ -42,33 +43,73 @@ DomainServerSettingsManager::DomainServerSettingsManager() :
|
|||
QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH);
|
||||
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) {
|
||||
_configMap.loadMasterAndUserConfig(argumentList);
|
||||
|
||||
// for now we perform a temporary transition from http-username and http-password to http_username and http_password
|
||||
const QVariant* oldUsername = valueForKeyPath(_configMap.getUserConfig(), "security.http-username");
|
||||
const QVariant* oldPassword = valueForKeyPath(_configMap.getUserConfig(), "security.http-password");
|
||||
// What settings version were we before and what are we using now?
|
||||
// Do we need to do any re-mapping?
|
||||
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) {
|
||||
QVariantMap& settingsMap = *reinterpret_cast<QVariantMap*>(_configMap.getUserConfig()["security"].data());
|
||||
if (oldVersion != _descriptionVersion) {
|
||||
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
|
||||
if (oldUsername) {
|
||||
settingsMap["http_username"] = oldUsername->toString();
|
||||
settingsMap.remove("http-username");
|
||||
// we have a version mismatch - for now handle custom behaviour here since there are not many remappings
|
||||
if (oldVersion < 1.0) {
|
||||
// This was prior to the introduction of security.restricted_access
|
||||
// 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) {
|
||||
|
|
|
@ -23,6 +23,9 @@ const QString SETTINGS_PATHS_KEY = "paths";
|
|||
const QString SETTINGS_PATH = "/settings";
|
||||
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 {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -44,6 +47,7 @@ private:
|
|||
QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
|
||||
void persistToFile();
|
||||
|
||||
double _descriptionVersion;
|
||||
QJsonArray _descriptionArray;
|
||||
HifiConfigVariantMap _configMap;
|
||||
};
|
||||
|
|
|
@ -55,46 +55,46 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
static bool firstCall = true;
|
||||
if (firstCall) {
|
||||
NodeType::init();
|
||||
|
||||
|
||||
// register the SharedNodePointer meta-type for signals/slots
|
||||
qRegisterMetaType<SharedNodePointer>();
|
||||
firstCall = false;
|
||||
}
|
||||
|
||||
|
||||
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
|
||||
qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort();
|
||||
|
||||
|
||||
if (dtlsListenPort > 0) {
|
||||
// only create the DTLS socket during constructor if a custom port is passed
|
||||
_dtlsSocket = new QUdpSocket(this);
|
||||
|
||||
|
||||
_dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort);
|
||||
qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
||||
}
|
||||
|
||||
|
||||
const int LARGER_BUFFER_SIZE = 1048576;
|
||||
changeSocketBufferSizes(LARGER_BUFFER_SIZE);
|
||||
|
||||
|
||||
// check for local socket updates every so often
|
||||
const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000;
|
||||
QTimer* localSocketUpdate = new QTimer(this);
|
||||
connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr);
|
||||
localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS);
|
||||
|
||||
|
||||
QTimer* silentNodeTimer = new QTimer(this);
|
||||
connect(silentNodeTimer, &QTimer::timeout, this, &LimitedNodeList::removeSilentNodes);
|
||||
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
|
||||
|
||||
|
||||
// check the local socket right now
|
||||
updateLocalSockAddr();
|
||||
|
||||
|
||||
_packetStatTimer.start();
|
||||
}
|
||||
|
||||
void LimitedNodeList::setSessionUUID(const QUuid& sessionUUID) {
|
||||
QUuid oldUUID = _sessionUUID;
|
||||
_sessionUUID = sessionUUID;
|
||||
|
||||
|
||||
if (sessionUUID != oldUUID) {
|
||||
qCDebug(networking) << "NodeList UUID changed from" << uuidStringWithoutCurlyBraces(oldUUID)
|
||||
<< "to" << uuidStringWithoutCurlyBraces(_sessionUUID);
|
||||
|
@ -120,16 +120,16 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() {
|
|||
if (!_dtlsSocket) {
|
||||
// DTLS socket getter called but no DTLS socket exists, create it now
|
||||
_dtlsSocket = new QUdpSocket(this);
|
||||
|
||||
|
||||
_dtlsSocket->bind(QHostAddress::AnyIPv4, 0, QAbstractSocket::DontShareAddress);
|
||||
|
||||
|
||||
// we're using DTLS and our socket is good to go, so make the required DTLS changes
|
||||
// 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
|
||||
|
||||
|
||||
qCDebug(networking) << "LimitedNodeList DTLS socket is listening on" << _dtlsSocket->localPort();
|
||||
}
|
||||
|
||||
|
||||
return *_dtlsSocket;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
|||
if (i == 0) {
|
||||
bufferOpt = QAbstractSocket::SendBufferSizeSocketOption;
|
||||
bufferTypeString = "send";
|
||||
|
||||
|
||||
} else {
|
||||
bufferOpt = QAbstractSocket::ReceiveBufferSizeSocketOption;
|
||||
bufferTypeString = "receive";
|
||||
|
@ -148,7 +148,7 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
|||
int oldBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
||||
if (oldBufferSize < numBytes) {
|
||||
int newBufferSize = _nodeSocket.socketOption(bufferOpt).toInt();
|
||||
|
||||
|
||||
qCDebug(networking) << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to"
|
||||
<< newBufferSize << "bytes";
|
||||
} else {
|
||||
|
@ -162,13 +162,13 @@ void LimitedNodeList::changeSocketBufferSizes(int numBytes) {
|
|||
bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
||||
PacketType checkType = packetTypeForPacket(packet);
|
||||
int numPacketTypeBytes = numBytesArithmeticCodingFromBuffer(packet.data());
|
||||
|
||||
|
||||
if (packet[numPacketTypeBytes] != versionForPacketType(checkType)
|
||||
&& checkType != PacketTypeStunResponse) {
|
||||
PacketType mismatchType = packetTypeForPacket(packet);
|
||||
|
||||
|
||||
static QMultiMap<QUuid, PacketType> versionDebugSuppressMap;
|
||||
|
||||
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
if (!versionDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||
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.";
|
||||
|
||||
emit packetVersionMismatch();
|
||||
|
||||
|
||||
versionDebugSuppressMap.insert(senderUUID, checkType);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!NON_VERIFIED_PACKETS.contains(checkType)) {
|
||||
// figure out which node this is from
|
||||
SharedNodePointer sendingNode = sendingNodeForPacket(packet);
|
||||
|
@ -192,26 +192,26 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) {
|
|||
return true;
|
||||
} else {
|
||||
static QMultiMap<QUuid, PacketType> hashDebugSuppressMap;
|
||||
|
||||
|
||||
QUuid senderUUID = uuidFromPacketHeader(packet);
|
||||
if (!hashDebugSuppressMap.contains(senderUUID, checkType)) {
|
||||
qCDebug(networking) << "Packet hash mismatch on" << checkType << "- Sender"
|
||||
<< uuidFromPacketHeader(packet);
|
||||
|
||||
|
||||
hashDebugSuppressMap.insert(senderUUID, checkType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
static QString repeatedMessage
|
||||
= 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"
|
||||
<< qPrintable(uuidStringWithoutCurlyBraces(uuidFromPacketHeader(packet)));
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -226,7 +226,7 @@ qint64 LimitedNodeList::readDatagram(QByteArray& incomingPacket, QHostAddress* a
|
|||
} else {
|
||||
emit dataReceived(NodeType::Unassigned, incomingPacket.size());
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -235,14 +235,14 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const HifiSock
|
|||
// stat collection for packets
|
||||
++_numCollectedPackets;
|
||||
_numCollectedBytes += datagram.size();
|
||||
|
||||
|
||||
qint64 bytesWritten = _nodeSocket.writeDatagram(datagram,
|
||||
destinationSockAddr.getAddress(), destinationSockAddr.getPort());
|
||||
|
||||
|
||||
if (bytesWritten < 0) {
|
||||
qCDebug(networking) << "ERROR in writeDatagram:" << _nodeSocket.error() << "-" << _nodeSocket.errorString();
|
||||
}
|
||||
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram,
|
|||
}
|
||||
|
||||
QByteArray datagramCopy = datagram;
|
||||
|
||||
|
||||
// if we're here and the connection secret is null, debug out - this could be a problem
|
||||
if (destinationNode->getConnectionSecret().isNull()) {
|
||||
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
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
PacketSequenceNumber sequenceNumber = getNextSequenceNumberForPacket(destinationNode->getUUID(), packetType);
|
||||
replaceHashAndSequenceNumberInPacket(datagramCopy, destinationNode->getConnectionSecret(),
|
||||
sequenceNumber, packetType);
|
||||
} else {
|
||||
replaceHashInPacket(datagramCopy, destinationNode->getConnectionSecret(), packetType);
|
||||
}
|
||||
|
||||
|
||||
emit dataSent(destinationNode->getType(), datagram.size());
|
||||
auto bytesWritten = writeDatagram(datagramCopy, *destinationSockAddr);
|
||||
// Keep track of per-destination-node bandwidth
|
||||
destinationNode->recordBytesSent(bytesWritten);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
|
||||
// didn't have a destinationNode to send to, return 0
|
||||
return 0;
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PacketType packetType = packetTypeForPacket(datagram);
|
||||
|
||||
// optionally peform sequence number replacement in the header
|
||||
|
@ -328,7 +328,7 @@ qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, cons
|
|||
return writeDatagram(datagram, *destinationSockAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// didn't have a destinationNode to send to, 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) {
|
||||
// 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.
|
||||
// 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 _packetSequenceNumbers[nodeUUID][packetType]++;
|
||||
}
|
||||
|
||||
|
@ -367,21 +367,21 @@ void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const
|
|||
|
||||
int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& matchingNode, const QByteArray &packet) {
|
||||
QMutexLocker locker(&matchingNode->getMutex());
|
||||
|
||||
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
|
||||
|
||||
// if this was a sequence numbered packet we should store the last seq number for
|
||||
// a packet of this type for this node
|
||||
PacketType packetType = packetTypeForPacket(packet);
|
||||
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
|
||||
matchingNode->setLastSequenceNumberForPacketType(sequenceNumberFromHeader(packet, packetType), packetType);
|
||||
}
|
||||
|
||||
|
||||
NodeData* linkedData = matchingNode->getLinkedData();
|
||||
if (!linkedData && linkedDataCreateCallback) {
|
||||
linkedDataCreateCallback(matchingNode.data());
|
||||
}
|
||||
|
||||
|
||||
if (linkedData) {
|
||||
QMutexLocker linkedDataLocker(&linkedData->getMutex());
|
||||
return linkedData->parseData(packet);
|
||||
|
@ -391,42 +391,42 @@ int LimitedNodeList::updateNodeWithDataFromPacket(const SharedNodePointer& match
|
|||
|
||||
int LimitedNodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
||||
SharedNodePointer matchingNode = sendingNodeForPacket(packet);
|
||||
|
||||
|
||||
if (matchingNode) {
|
||||
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
|
||||
return 0;
|
||||
}
|
||||
|
||||
SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||
QReadLocker readLocker(&_nodeMutex);
|
||||
|
||||
|
||||
NodeHash::const_iterator it = _nodeHash.find(nodeUUID);
|
||||
return it == _nodeHash.cend() ? SharedNodePointer() : it->second;
|
||||
}
|
||||
|
||||
SharedNodePointer LimitedNodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||
QUuid nodeUUID = uuidFromPacketHeader(packet);
|
||||
|
||||
|
||||
// return the matching node, or NULL if there is no match
|
||||
return nodeWithUUID(nodeUUID);
|
||||
}
|
||||
|
||||
void LimitedNodeList::eraseAllNodes() {
|
||||
qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list.";
|
||||
|
||||
|
||||
QSet<SharedNodePointer> killedNodes;
|
||||
eachNode([&killedNodes](const SharedNodePointer& node){
|
||||
killedNodes.insert(node);
|
||||
});
|
||||
|
||||
|
||||
// iterate the current nodes, emit that they are dying and remove them from the hash
|
||||
_nodeMutex.lockForWrite();
|
||||
_nodeHash.clear();
|
||||
_nodeMutex.unlock();
|
||||
|
||||
|
||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||
handleNodeKill(killedNode);
|
||||
}
|
||||
|
@ -438,17 +438,17 @@ void LimitedNodeList::reset() {
|
|||
|
||||
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||
_nodeMutex.lockForRead();
|
||||
|
||||
|
||||
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
||||
if (it != _nodeHash.end()) {
|
||||
SharedNodePointer matchingNode = it->second;
|
||||
|
||||
|
||||
_nodeMutex.unlock();
|
||||
|
||||
|
||||
_nodeMutex.lockForWrite();
|
||||
_nodeHash.unsafe_erase(it);
|
||||
_nodeMutex.unlock();
|
||||
|
||||
|
||||
handleNodeKill(matchingNode);
|
||||
} else {
|
||||
_nodeMutex.unlock();
|
||||
|
@ -472,34 +472,34 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||
bool canAdjustLocks, bool canRez) {
|
||||
NodeHash::const_iterator it = _nodeHash.find(uuid);
|
||||
|
||||
|
||||
if (it != _nodeHash.end()) {
|
||||
SharedNodePointer& matchingNode = it->second;
|
||||
|
||||
|
||||
matchingNode->setPublicSocket(publicSocket);
|
||||
matchingNode->setLocalSocket(localSocket);
|
||||
matchingNode->setCanAdjustLocks(canAdjustLocks);
|
||||
matchingNode->setCanRez(canRez);
|
||||
|
||||
|
||||
return matchingNode;
|
||||
} else {
|
||||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, canAdjustLocks, canRez);
|
||||
SharedNodePointer newNodePointer(newNode);
|
||||
|
||||
|
||||
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
|
||||
|
||||
|
||||
qCDebug(networking) << "Added" << *newNode;
|
||||
|
||||
|
||||
emit nodeAdded(newNodePointer);
|
||||
|
||||
|
||||
return newNodePointer;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
|
||||
unsigned n = 0;
|
||||
|
||||
|
||||
eachNode([&](const SharedNodePointer& node){
|
||||
if (destinationNodeTypes.contains(node->getType())) {
|
||||
writeDatagram(packet, node);
|
||||
|
@ -516,35 +516,35 @@ QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVeri
|
|||
|
||||
QByteArray pingPacket = byteArrayWithUUIDPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing,
|
||||
packetUUID);
|
||||
|
||||
|
||||
QDataStream packetStream(&pingPacket, QIODevice::Append);
|
||||
|
||||
|
||||
packetStream << pingType;
|
||||
packetStream << usecTimestampNow();
|
||||
|
||||
|
||||
return pingPacket;
|
||||
}
|
||||
|
||||
QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) {
|
||||
QDataStream pingPacketStream(pingPacket);
|
||||
pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket));
|
||||
|
||||
|
||||
PingType_t typeFromOriginalPing;
|
||||
pingPacketStream >> typeFromOriginalPing;
|
||||
|
||||
|
||||
quint64 timeFromOriginalPing;
|
||||
pingPacketStream >> timeFromOriginalPing;
|
||||
|
||||
|
||||
PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing)
|
||||
? PacketTypePingReply : PacketTypeUnverifiedPingReply;
|
||||
|
||||
|
||||
QUuid packetUUID = packetHeaderID.isNull() ? _sessionUUID : packetHeaderID;
|
||||
|
||||
QByteArray replyPacket = byteArrayWithUUIDPopulatedHeader(replyType, packetUUID);
|
||||
QDataStream packetStream(&replyPacket, QIODevice::Append);
|
||||
|
||||
|
||||
packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow();
|
||||
|
||||
|
||||
return replyPacket;
|
||||
}
|
||||
|
||||
|
@ -566,9 +566,9 @@ void LimitedNodeList::resetPacketStats() {
|
|||
}
|
||||
|
||||
void LimitedNodeList::removeSilentNodes() {
|
||||
|
||||
|
||||
QSet<SharedNodePointer> killedNodes;
|
||||
|
||||
|
||||
eachNodeHashIterator([&](NodeHash::iterator& it){
|
||||
SharedNodePointer node = it->second;
|
||||
node->getMutex().lock();
|
||||
|
@ -582,10 +582,10 @@ void LimitedNodeList::removeSilentNodes() {
|
|||
// we didn't erase this node, push the iterator forwards
|
||||
++it;
|
||||
}
|
||||
|
||||
|
||||
node->getMutex().unlock();
|
||||
});
|
||||
|
||||
|
||||
foreach(const SharedNodePointer& killedNode, killedNodes) {
|
||||
handleNodeKill(killedNode);
|
||||
}
|
||||
|
@ -595,38 +595,38 @@ const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
|||
const int NUM_BYTES_STUN_HEADER = 20;
|
||||
|
||||
void LimitedNodeList::sendSTUNRequest() {
|
||||
|
||||
|
||||
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||
|
||||
|
||||
int packetIndex = 0;
|
||||
|
||||
|
||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||
|
||||
|
||||
// leading zeros + message type
|
||||
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||
|
||||
|
||||
// message length (no additional attributes are included)
|
||||
uint16_t messageLength = 0;
|
||||
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||
packetIndex += sizeof(messageLength);
|
||||
|
||||
|
||||
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
|
||||
// transaction ID (random 12-byte unsigned integer)
|
||||
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||
QUuid randomUUID = QUuid::createUuid();
|
||||
memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES);
|
||||
|
||||
|
||||
_nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket),
|
||||
_stunSockAddr.getAddress(), _stunSockAddr.getPort());
|
||||
}
|
||||
|
||||
void LimitedNodeList::rebindNodeSocket() {
|
||||
quint16 oldPort = _nodeSocket.localPort();
|
||||
|
||||
|
||||
_nodeSocket.close();
|
||||
_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
|
||||
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
||||
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
||||
|
||||
|
||||
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||
|
||||
|
||||
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
||||
|
||||
|
||||
if (memcmp(packet.data() + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
||||
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
||||
|
||||
|
||||
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||
while (attributeStartIndex < packet.size()) {
|
||||
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_FAMILY_ALIGN = 1;
|
||||
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
||||
|
||||
|
||||
uint8_t addressFamily = 0;
|
||||
memcpy(&addressFamily, packet.data() + byteIndex, sizeof(addressFamily));
|
||||
|
||||
|
||||
byteIndex += sizeof(addressFamily);
|
||||
|
||||
|
||||
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
||||
// grab the X-Port
|
||||
uint16_t xorMappedPort = 0;
|
||||
memcpy(&xorMappedPort, packet.data() + byteIndex, sizeof(xorMappedPort));
|
||||
|
||||
|
||||
uint16_t newPublicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
||||
|
||||
|
||||
byteIndex += sizeof(xorMappedPort);
|
||||
|
||||
|
||||
// grab the X-Address
|
||||
uint32_t xorMappedAddress = 0;
|
||||
memcpy(&xorMappedAddress, packet.data() + byteIndex, sizeof(xorMappedAddress));
|
||||
|
||||
|
||||
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||
|
||||
|
||||
QHostAddress newPublicAddress = QHostAddress(stunAddress);
|
||||
|
||||
|
||||
if (newPublicAddress != _publicSockAddr.getAddress() || newPublicPort != _publicSockAddr.getPort()) {
|
||||
_publicSockAddr = HifiSockAddr(newPublicAddress, newPublicPort);
|
||||
|
||||
|
||||
qCDebug(networking, "New public socket received from STUN server is %s:%hu",
|
||||
_publicSockAddr.getAddress().toString().toLocal8Bit().constData(),
|
||||
_publicSockAddr.getPort());
|
||||
|
||||
emit publicSockAddrChanged(_publicSockAddr);
|
||||
|
||||
emit publicSockAddrChanged(_publicSockAddr);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// push forward attributeStartIndex by the length of this attribute
|
||||
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
||||
|
||||
|
||||
uint16_t attributeLength = 0;
|
||||
memcpy(&attributeLength, packet.data() + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE,
|
||||
sizeof(attributeLength));
|
||||
attributeLength = ntohs(attributeLength);
|
||||
|
||||
|
||||
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LimitedNodeList::updateLocalSockAddr() {
|
||||
HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort());
|
||||
if (newSockAddr != _localSockAddr) {
|
||||
|
||||
|
||||
if (_localSockAddr.isNull()) {
|
||||
qCDebug(networking) << "Local socket is" << newSockAddr;
|
||||
} else {
|
||||
qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
|
||||
}
|
||||
|
||||
|
||||
_localSockAddr = newSockAddr;
|
||||
|
||||
|
||||
emit localSockAddrChanged(_localSockAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
||||
QUuid headerID, const QUuid& connectionRequestID) {
|
||||
|
||||
|
||||
if (headerID.isNull()) {
|
||||
headerID = _sessionUUID;
|
||||
}
|
||||
|
||||
|
||||
QByteArray iceRequestByteArray = byteArrayWithUUIDPopulatedHeader(PacketTypeIceServerHeartbeat, headerID);
|
||||
QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append);
|
||||
|
||||
|
||||
iceDataStream << _publicSockAddr << _localSockAddr;
|
||||
|
||||
|
||||
if (!connectionRequestID.isNull()) {
|
||||
iceDataStream << connectionRequestID;
|
||||
|
||||
|
||||
qCDebug(networking) << "Sending packet to ICE server to request connection info for peer with ID"
|
||||
<< uuidStringWithoutCurlyBraces(connectionRequestID);
|
||||
}
|
||||
|
||||
|
||||
writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr);
|
||||
}
|
||||
|
||||
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
|
||||
QSharedMemory* sharedPortMem = new QSharedMemory(key, parent);
|
||||
|
||||
|
||||
// attempt to create the shared memory segment
|
||||
if (sharedPortMem->create(sizeof(localPort)) || sharedPortMem->attach()) {
|
||||
sharedPortMem->lock();
|
||||
memcpy(sharedPortMem->data(), &localPort, sizeof(localPort));
|
||||
sharedPortMem->unlock();
|
||||
|
||||
|
||||
qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key;
|
||||
} else {
|
||||
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,
|
||||
quint16& localPort) {
|
||||
if (!sharedMem) {
|
||||
sharedMem = new QSharedMemory(key, this);
|
||||
|
||||
if (!sharedMem->attach(QSharedMemory::ReadOnly)) {
|
||||
qWarning() << "Could not attach to shared memory at key" << key;
|
||||
}
|
||||
}
|
||||
|
||||
if (sharedMem->isAttached()) {
|
||||
sharedMem->lock();
|
||||
memcpy(&localPort, sharedMem->data(), sizeof(localPort));
|
||||
sharedMem->unlock();
|
||||
bool LimitedNodeList::getLocalServerPortFromSharedMemory(const QString key, quint16& localPort) {
|
||||
QSharedMemory sharedMem(key);
|
||||
if (!sharedMem.attach(QSharedMemory::ReadOnly)) {
|
||||
qWarning() << "Could not attach to shared memory at key" << key;
|
||||
return false;
|
||||
} else {
|
||||
sharedMem.lock();
|
||||
memcpy(&localPort, sharedMem.data(), sizeof(localPort));
|
||||
sharedMem.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace PingType {
|
|||
class LimitedNodeList : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
|
||||
public:
|
||||
const QUuid& getSessionUUID() const { return _sessionUUID; }
|
||||
void setSessionUUID(const QUuid& sessionUUID);
|
||||
|
@ -89,22 +89,22 @@ public:
|
|||
|
||||
bool getThisNodeCanRez() const { return _thisNodeCanRez; }
|
||||
void setThisNodeCanRez(bool canRez);
|
||||
|
||||
|
||||
void rebindNodeSocket();
|
||||
QUdpSocket& getNodeSocket() { return _nodeSocket; }
|
||||
QUdpSocket& getDTLSSocket();
|
||||
|
||||
|
||||
bool packetVersionAndHashMatch(const QByteArray& packet);
|
||||
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType packetType)
|
||||
QByteArray byteArrayWithPopulatedHeader(PacketType packetType)
|
||||
{ return byteArrayWithUUIDPopulatedHeader(packetType, _sessionUUID); }
|
||||
int populatePacketHeader(QByteArray& packet, PacketType packetType)
|
||||
int populatePacketHeader(QByteArray& packet, PacketType packetType)
|
||||
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
||||
int populatePacketHeader(char* packet, PacketType packetType)
|
||||
int populatePacketHeader(char* packet, PacketType packetType)
|
||||
{ return populatePacketHeaderWithUUID(packet, packetType, _sessionUUID); }
|
||||
|
||||
qint64 readDatagram(QByteArray& incomingPacket, QHostAddress* address, quint16 * port);
|
||||
|
||||
|
||||
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||
|
||||
|
@ -120,16 +120,16 @@ public:
|
|||
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
|
||||
|
||||
void (*linkedDataCreateCallback)(Node *);
|
||||
|
||||
|
||||
int size() const { return _nodeHash.size(); }
|
||||
|
||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||
|
||||
|
||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
|
||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||
bool canAdjustLocks, bool canRez);
|
||||
|
||||
|
||||
const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
|
||||
const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
|
||||
|
||||
|
@ -144,21 +144,21 @@ public:
|
|||
|
||||
void getPacketStats(float &packetsPerSecond, float &bytesPerSecond);
|
||||
void resetPacketStats();
|
||||
|
||||
|
||||
QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true,
|
||||
const QUuid& packetHeaderID = QUuid());
|
||||
QByteArray constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID = QUuid());
|
||||
|
||||
|
||||
virtual void sendSTUNRequest();
|
||||
virtual bool processSTUNResponse(const QByteArray& packet);
|
||||
|
||||
|
||||
void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr,
|
||||
QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid());
|
||||
|
||||
|
||||
template<typename NodeLambda>
|
||||
void eachNode(NodeLambda functor) {
|
||||
QReadLocker readLock(&_nodeMutex);
|
||||
|
||||
|
||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||
functor(it->second);
|
||||
}
|
||||
|
@ -178,44 +178,44 @@ public:
|
|||
template<typename BreakableNodeLambda>
|
||||
void eachNodeBreakable(BreakableNodeLambda functor) {
|
||||
QReadLocker readLock(&_nodeMutex);
|
||||
|
||||
|
||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||
if (!functor(it->second)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename PredLambda>
|
||||
SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) {
|
||||
QReadLocker readLock(&_nodeMutex);
|
||||
|
||||
|
||||
for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
|
||||
if (predicate(it->second)) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return SharedNodePointer();
|
||||
}
|
||||
|
||||
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:
|
||||
void reset();
|
||||
void eraseAllNodes();
|
||||
|
||||
|
||||
void removeSilentNodes();
|
||||
|
||||
|
||||
void updateLocalSockAddr();
|
||||
|
||||
|
||||
void killNodeWithUUID(const QUuid& nodeUUID);
|
||||
signals:
|
||||
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
||||
void nodeAdded(SharedNodePointer);
|
||||
void nodeKilled(SharedNodePointer);
|
||||
|
||||
|
||||
void localSockAddrChanged(const HifiSockAddr& localSockAddr);
|
||||
void publicSockAddrChanged(const HifiSockAddr& publicSockAddr);
|
||||
|
||||
|
@ -226,18 +226,18 @@ signals:
|
|||
void dataReceived(const quint8 channel_type, const int bytes);
|
||||
|
||||
void packetVersionMismatch();
|
||||
|
||||
|
||||
protected:
|
||||
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
||||
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
|
||||
|
||||
|
||||
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr);
|
||||
|
||||
PacketSequenceNumber getNextSequenceNumberForPacket(const QUuid& nodeUUID, PacketType packetType);
|
||||
|
||||
|
||||
void changeSocketBufferSizes(int numBytes);
|
||||
|
||||
|
||||
void handleNodeKill(const SharedNodePointer& node);
|
||||
|
||||
QUuid _sessionUUID;
|
||||
|
@ -258,17 +258,17 @@ protected:
|
|||
bool _thisNodeCanRez;
|
||||
|
||||
std::unordered_map<QUuid, PacketTypeSequenceMap, UUIDHasher> _packetSequenceNumbers;
|
||||
|
||||
|
||||
template<typename IteratorLambda>
|
||||
void eachNodeHashIterator(IteratorLambda functor) {
|
||||
QWriteLocker writeLock(&_nodeMutex);
|
||||
NodeHash::iterator it = _nodeHash.begin();
|
||||
|
||||
|
||||
while (it != _nodeHash.end()) {
|
||||
functor(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_LimitedNodeList_h
|
||||
|
|
|
@ -335,12 +335,8 @@ void NodeList::sendDomainServerCheckIn() {
|
|||
if (_domainHandler.getSockAddr().getAddress() == QHostAddress::LocalHost
|
||||
|| _domainHandler.getHostname() == "localhost") {
|
||||
|
||||
static QSharedMemory* localDSPortSharedMem = NULL;
|
||||
|
||||
quint16 domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY,
|
||||
localDSPortSharedMem,
|
||||
domainPort);
|
||||
getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, domainPort);
|
||||
qCDebug(networking) << "Local domain-server port read from shared memory (or default) is" << domainPort;
|
||||
_domainHandler.setPort(domainPort);
|
||||
}
|
||||
|
|
|
@ -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('.');
|
||||
|
||||
QString firstKey = (dotIndex == -1) ? keyPath : keyPath.mid(0, dotIndex);
|
||||
|
||||
if (variantMap.contains(firstKey)) {
|
||||
if (shouldCreateIfMissing || variantMap.contains(firstKey)) {
|
||||
if (dotIndex == -1) {
|
||||
return &variantMap[firstKey];
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,6 @@ private:
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue