From 3969c8bfe0588657a944b3a81d66720b8911c15c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 30 Sep 2014 12:23:04 -0700 Subject: [PATCH 01/44] don't allow a username and password for domain auth, require access token --- domain-server/src/DomainServer.cpp | 81 ++++++------ domain-server/src/DomainServer.h | 4 +- libraries/networking/src/AccountManager.cpp | 115 +++++++++++------- libraries/networking/src/AccountManager.h | 4 + .../networking/src/DataServerAccountInfo.h | 1 + libraries/networking/src/OAuthAccessToken.cpp | 2 +- libraries/networking/src/OAuthAccessToken.h | 2 +- 7 files changed, 123 insertions(+), 86 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index eccd52dfc1..1ca549cbad 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -64,7 +64,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : qRegisterMetaType("DomainServerWebSessionData"); qRegisterMetaTypeStreamOperators("DomainServerWebSessionData"); - + if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth() && optionallySetupAssignmentPayment()) { // we either read a certificate and private key or were not passed one // and completed login or did not need to @@ -75,7 +75,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : loadExistingSessionsFromSettings(); // check if we have the flag that enables dynamic IP - setupDynamicIPAddressUpdating(); + setupDynamicSocketUpdating(); } } @@ -151,6 +151,17 @@ bool DomainServer::optionallySetupOAuth() { const QVariantMap& settingsMap = _settingsManager.getSettingsMap(); _oauthProviderURL = QUrl(settingsMap.value(OAUTH_PROVIDER_URL_OPTION).toString()); + + // if we don't have an oauth provider URL then we default to the default node auth url + if (_oauthProviderURL.isEmpty()) { + _oauthProviderURL = DEFAULT_NODE_AUTH_URL; + } + + // setup our account manager with that _oauthProviderURL + AccountManager& accountManager = AccountManager::getInstance(); + accountManager.disableSettingsFilePersistence(); + accountManager.setAuthURL(_oauthProviderURL); + _oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString(); _oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV); _hostname = settingsMap.value(REDIRECT_HOSTNAME_OPTION).toString(); @@ -225,41 +236,37 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { addStaticAssignmentsToQueue(); } -const QString HIFI_USERNAME_ENV_KEY = "DOMAIN_SERVER_USERNAME"; -const QString HIFI_PASSWORD_ENV_KEY = "DOMAIN_SERVER_PASSWORD"; - -bool DomainServer::hasOAuthProviderAndAuthInformation() { +bool DomainServer::didSetupAccountManagerWithAccessToken() { + AccountManager& accountManager = AccountManager::getInstance(); + + if (accountManager.hasValidAccessToken()) { + // we already gave the account manager a valid access token + return true; + } if (!_oauthProviderURL.isEmpty()) { + // check for an access-token in our settings, can optionally be overidden by env value + const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token"; + const QString ENV_ACCESS_TOKEN_KEY = "DOMAIN_SERVER_ACCESS_TOKEN"; - static bool hasAttemptedAuthWithOAuthProvider = false; + QString accessToken = QProcessEnvironment::systemEnvironment().value(ENV_ACCESS_TOKEN_KEY); - if (!hasAttemptedAuthWithOAuthProvider) { - AccountManager& accountManager = AccountManager::getInstance(); - accountManager.setAuthURL(_oauthProviderURL); + if (accessToken.isEmpty()) { + const QVariant* accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH); - if (!accountManager.hasValidAccessToken()) { - // we don't have a valid access token so we need to get one - // check if we have a username and password set via env - QString username = QProcessEnvironment::systemEnvironment().value(HIFI_USERNAME_ENV_KEY); - QString password = QProcessEnvironment::systemEnvironment().value(HIFI_PASSWORD_ENV_KEY); - - if (!username.isEmpty() && !password.isEmpty()) { - - accountManager.requestAccessToken(username, password); - - // connect to loginFailed signal from AccountManager so we can quit if that is the case - connect(&accountManager, &AccountManager::loginFailed, this, &DomainServer::loginFailed); - } else { - qDebug() << "Missing access-token or username and password combination. domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); - return false; - } + if (accessTokenVariant->canConvert(QMetaType::QString)) { + accessToken = accessTokenVariant->toString(); + } else { + qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present." + << "Set an access token via the web interface, in your user or master config" + << "at keypath metaverse.access_token or in your ENV at key DOMAIN_SERVER_ACCESS_TOKEN"; + return false; } - - hasAttemptedAuthWithOAuthProvider = true; } + // give this access token to the AccountManager + accountManager.setAccessTokenForCurrentAuthURL(accessToken); + return true; } else { @@ -277,7 +284,7 @@ bool DomainServer::optionallySetupAssignmentPayment() { if (settingsMap.contains(PAY_FOR_ASSIGNMENTS_OPTION) && settingsMap.value(PAY_FOR_ASSIGNMENTS_OPTION).toBool() && - hasOAuthProviderAndAuthInformation()) { + didSetupAccountManagerWithAccessToken()) { qDebug() << "Assignments will be paid for via" << qPrintable(_oauthProviderURL.toString()); @@ -299,20 +306,20 @@ bool DomainServer::optionallySetupAssignmentPayment() { return true; } -void DomainServer::setupDynamicIPAddressUpdating() { - const QString ENABLE_DYNAMIC_IP_UPDATING_OPTION = "update-ip"; +void DomainServer::setupDynamicSocketUpdating() { + const QString ENABLE_DYNAMIC_SOCKET_UPDATING_KEY_PATH = "metaverse.update_sockets"; - const QVariantMap& settingsMap = _settingsManager.getSettingsMap(); + const QVariant* updateSocketValue = valueForKeyPath(_settingsManager.getSettingsMap(), + ENABLE_DYNAMIC_SOCKET_UPDATING_KEY_PATH); - if (settingsMap.contains(ENABLE_DYNAMIC_IP_UPDATING_OPTION) && - settingsMap.value(ENABLE_DYNAMIC_IP_UPDATING_OPTION).toBool() && - hasOAuthProviderAndAuthInformation()) { + if (updateSocketValue && updateSocketValue->canConvert(QMetaType::Bool) && updateSocketValue->toBool() + && didSetupAccountManagerWithAccessToken()) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); const QUuid& domainID = nodeList->getSessionUUID(); if (!domainID.isNull()) { - qDebug() << "domain-server IP address will be updated for domain with ID" + qDebug() << "domain-server socket will be updated for domain with ID" << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 44b8a15901..183ce67639 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -68,9 +68,9 @@ private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); - bool hasOAuthProviderAndAuthInformation(); + bool didSetupAccountManagerWithAccessToken(); bool optionallySetupAssignmentPayment(); - void setupDynamicIPAddressUpdating(); + void setupDynamicSocketUpdating(); void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 88e4bad7b2..d8de09e2cb 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -52,7 +52,8 @@ JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, co AccountManager::AccountManager() : _authURL(), _pendingCallbackMap(), - _accountInfo() + _accountInfo(), + _shouldPersistToSettingsFile(false) { qRegisterMetaType("OAuthAccessToken"); qRegisterMetaTypeStreamOperators("OAuthAccessToken"); @@ -76,14 +77,18 @@ void AccountManager::logout() { emit balanceChanged(0); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); - - QSettings settings; - settings.beginGroup(ACCOUNTS_GROUP); - - QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE)); - settings.remove(keyURLString); - - qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file"; + + if (_shouldPersistToSettingsFile) { + QSettings settings; + settings.beginGroup(ACCOUNTS_GROUP); + + QString keyURLString(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE)); + settings.remove(keyURLString); + + qDebug() << "Removed account info for" << _authURL << "from in-memory accounts and .ini file"; + } else { + qDebug() << "Cleared data server account info in account manager."; + } emit logoutComplete(); // the username has changed to blank @@ -109,28 +114,29 @@ void AccountManager::setAuthURL(const QUrl& authURL) { if (_authURL != authURL) { _authURL = authURL; - qDebug() << "URL for node authentication has been changed to" << qPrintable(_authURL.toString()); - qDebug() << "Re-setting authentication flow."; - - // check if there are existing access tokens to load from settings - QSettings settings; - settings.beginGroup(ACCOUNTS_GROUP); - - foreach(const QString& key, settings.allKeys()) { - // take a key copy to perform the double slash replacement - QString keyCopy(key); - QUrl keyURL(keyCopy.replace("slashslash", "//")); - - if (keyURL == _authURL) { - // pull out the stored access token and store it in memory - _accountInfo = settings.value(key).value(); - qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString()); - - // profile info isn't guaranteed to be saved too - if (_accountInfo.hasProfile()) { - emit profileChanged(); - } else { - requestProfile(); + qDebug() << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString()); + + if (_shouldPersistToSettingsFile) { + // check if there are existing access tokens to load from settings + QSettings settings; + settings.beginGroup(ACCOUNTS_GROUP); + + foreach(const QString& key, settings.allKeys()) { + // take a key copy to perform the double slash replacement + QString keyCopy(key); + QUrl keyURL(keyCopy.replace("slashslash", "//")); + + if (keyURL == _authURL) { + // pull out the stored access token and store it in memory + _accountInfo = settings.value(key).value(); + qDebug() << "Found a data-server access token for" << qPrintable(keyURL.toString()); + + // profile info isn't guaranteed to be saved too + if (_accountInfo.hasProfile()) { + emit profileChanged(); + } else { + requestProfile(); + } } } } @@ -307,8 +313,9 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) { } bool AccountManager::hasValidAccessToken() { - + if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) { + if (VERBOSE_HTTP_REQUEST_DEBUGGING) { qDebug() << "An access token is required for requests to" << qPrintable(_authURL.toString()); } @@ -330,6 +337,19 @@ bool AccountManager::checkAndSignalForAccessToken() { return hasToken; } +void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) { + // clear our current DataServerAccountInfo + _accountInfo = DataServerAccountInfo(); + + // start the new account info with a new OAuthAccessToken + OAuthAccessToken newOAuthToken; + newOAuthToken.token = accessToken; + + qDebug() << "Setting new account manager access token to" << accessToken; + + _accountInfo.setAccessToken(newOAuthToken); +} + void AccountManager::requestAccessToken(const QString& login, const QString& password) { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); @@ -380,12 +400,14 @@ void AccountManager::requestAccessTokenFinished() { _accountInfo.setAccessTokenFromJSON(rootObject); emit loginComplete(rootURL); - - // store this access token into the local settings - QSettings localSettings; - localSettings.beginGroup(ACCOUNTS_GROUP); - localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE), - QVariant::fromValue(_accountInfo)); + + if (_shouldPersistToSettingsFile) { + // store this access token into the local settings + QSettings localSettings; + localSettings.beginGroup(ACCOUNTS_GROUP); + localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE), + QVariant::fromValue(_accountInfo)); + } requestProfile(); } @@ -429,13 +451,16 @@ void AccountManager::requestProfileFinished() { // the username has changed to whatever came back emit usernameChanged(_accountInfo.getUsername()); - // store the whole profile into the local settings - QUrl rootURL = profileReply->url(); - rootURL.setPath(""); - QSettings localSettings; - localSettings.beginGroup(ACCOUNTS_GROUP); - localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE), - QVariant::fromValue(_accountInfo)); + if (_shouldPersistToSettingsFile) { + // store the whole profile into the local settings + QUrl rootURL = profileReply->url(); + rootURL.setPath(""); + QSettings localSettings; + localSettings.beginGroup(ACCOUNTS_GROUP); + localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE), + QVariant::fromValue(_accountInfo)); + } + } else { // TODO: error handling qDebug() << "Error in response for profile"; diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index edccab0b75..46c71dd476 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -59,10 +59,13 @@ public: const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); bool hasAuthEndpoint() { return !_authURL.isEmpty(); } + + void disableSettingsFilePersistence() { _shouldPersistToSettingsFile = false; } bool isLoggedIn() { return !_authURL.isEmpty() && hasValidAccessToken(); } bool hasValidAccessToken(); Q_INVOKABLE bool checkAndSignalForAccessToken(); + void setAccessTokenForCurrentAuthURL(const QString& accessToken); void requestAccessToken(const QString& login, const QString& password); void requestProfile(); @@ -107,6 +110,7 @@ private: QMap _pendingCallbackMap; DataServerAccountInfo _accountInfo; + bool _shouldPersistToSettingsFile; }; #endif // hifi_AccountManager_h diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index dd9540718e..91675594ad 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -27,6 +27,7 @@ public: DataServerAccountInfo& operator=(const DataServerAccountInfo& otherInfo); const OAuthAccessToken& getAccessToken() const { return _accessToken; } + void setAccessToken(const OAuthAccessToken& accessToken) { _accessToken = accessToken; } void setAccessTokenFromJSON(const QJsonObject& jsonObject); const QString& getUsername() const { return _username; } diff --git a/libraries/networking/src/OAuthAccessToken.cpp b/libraries/networking/src/OAuthAccessToken.cpp index 365b07a935..b8ec58099f 100644 --- a/libraries/networking/src/OAuthAccessToken.cpp +++ b/libraries/networking/src/OAuthAccessToken.cpp @@ -16,7 +16,7 @@ OAuthAccessToken::OAuthAccessToken() : token(), refreshToken(), - expiryTimestamp(0), + expiryTimestamp(-1), tokenType() { diff --git a/libraries/networking/src/OAuthAccessToken.h b/libraries/networking/src/OAuthAccessToken.h index 167bb824da..fcd0f22e39 100644 --- a/libraries/networking/src/OAuthAccessToken.h +++ b/libraries/networking/src/OAuthAccessToken.h @@ -26,7 +26,7 @@ public: QByteArray authorizationHeaderValue() const { return QString("Bearer %1").arg(token).toUtf8(); } - bool isExpired() const { return expiryTimestamp <= QDateTime::currentMSecsSinceEpoch(); } + bool isExpired() const { return expiryTimestamp != -1 && expiryTimestamp <= QDateTime::currentMSecsSinceEpoch(); } QString token; QString refreshToken; From a0487e0a57aabacdc27a526242155c340af54921 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 10:42:14 -0700 Subject: [PATCH 02/44] send public and local sockets to data-server in new format --- domain-server/src/DomainServer.cpp | 48 +++++++++++++++++++----------- domain-server/src/DomainServer.h | 7 +++-- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 1ca549cbad..4d7ab8b121 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -157,7 +157,6 @@ bool DomainServer::optionallySetupOAuth() { _oauthProviderURL = DEFAULT_NODE_AUTH_URL; } - // setup our account manager with that _oauthProviderURL AccountManager& accountManager = AccountManager::getInstance(); accountManager.disableSettingsFilePersistence(); accountManager.setAuthURL(_oauthProviderURL); @@ -326,21 +325,14 @@ void DomainServer::setupDynamicSocketUpdating() { // setup our timer to check our IP via stun every 30 seconds QTimer* dynamicIPTimer = new QTimer(this); - connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentIPAddressViaSTUN); + connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); // send public socket changes to the data server so nodes can find us at our new IP - connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewPublicSocketToDataServer); + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewSocketsToDataServer); - if (!AccountManager::getInstance().hasValidAccessToken()) { - // we don't have an access token to talk to data-web yet, so - // check our IP address as soon as we get an AccountManager access token - connect(&AccountManager::getInstance(), &AccountManager::loginComplete, - this, &DomainServer::requestCurrentIPAddressViaSTUN); - } else { - // access token good to go, attempt to update our IP now - requestCurrentIPAddressViaSTUN(); - } + // attempt to update our sockets now + requestCurrentPublicSocketViaSTUN(); } else { qDebug() << "Cannot enable dynamic domain-server IP address updating without a domain ID." @@ -914,18 +906,40 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) { } } -void DomainServer::requestCurrentIPAddressViaSTUN() { +void DomainServer::requestCurrentPublicSocketViaSTUN() { LimitedNodeList::getInstance()->sendSTUNRequest(); } -void DomainServer::sendNewPublicSocketToDataServer(const HifiSockAddr& newPublicSockAddr) { +QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) { + const QString SOCKET_NETWORK_ADDRESS_KEY = "network_address"; + const QString SOCKET_PORT_KEY = "port"; + + QJsonObject socketObject; + socketObject[SOCKET_NETWORK_ADDRESS_KEY] = socket.getAddress().toString(); + socketObject[SOCKET_PORT_KEY] = socket.getPort(); + + return socketObject; +} + +void DomainServer::sendNewSocketsToDataServer(const HifiSockAddr& newPublicSockAddr) { const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID(); - // setup the domain object to send to the data server - const QString DOMAIN_JSON_OBJECT = "{\"domain\":{\"network_address\":\"%1\"}}"; + // we're not mointoring for local socket changes yet + // the first time this is called grab whatever it is and assume it'll stay the same + static HifiSockAddr localSockAddr = HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), + LimitedNodeList::getInstance()->getNodeSocket().localPort()); - QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(newPublicSockAddr.getAddress().toString()); + // setup the domain object to send to the data server + const QString PUBLIC_SOCKET_ATTRIBUTES_KEY = "public_socket_attributes"; + const QString LOCAL_SOCKET_ATTRIBUTES_KEY = "local_socket_attributes"; + + QJsonObject domainObject; + domainObject[PUBLIC_SOCKET_ATTRIBUTES_KEY] = jsonForDomainSocketUpdate(newPublicSockAddr); + domainObject[LOCAL_SOCKET_ATTRIBUTES_KEY] = jsonForDomainSocketUpdate(localSockAddr); + + const QString DOMAIN_JSON_OBJECT = "{\"domain\":%1}"; + QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(QString(QJsonDocument(domainObject).toJson())); AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), QNetworkAccessManager::PutOperation, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 183ce67639..b09602e2e6 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -62,8 +62,8 @@ private slots: void setupPendingAssignmentCredits(); void sendPendingTransactionsToServer(); - void requestCurrentIPAddressViaSTUN(); - void sendNewPublicSocketToDataServer(const HifiSockAddr& newPublicSockAddr); + void requestCurrentPublicSocketViaSTUN(); + void sendNewSocketsToDataServer(const HifiSockAddr& newPublicSockAddr); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); @@ -130,7 +130,10 @@ private: QSet _webAuthenticationStateSet; QHash _cookieSessionHash; + HifiSockAddr _localSockAddr; + DomainServerSettingsManager _settingsManager; }; + #endif // hifi_DomainServer_h From d3cef7e592b89aaca69290d761728398180500ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 11:57:24 -0700 Subject: [PATCH 03/44] add select for automatic networking to describe settings --- .../resources/describe-settings.json | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 364743110d..fbcbcd41a8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -12,7 +12,28 @@ "name": "id", "label": "Domain ID", "help": "This is your High Fidelity domain ID. If you do not want your domain to be registered in the High Fidelity metaverse you can leave this blank." - } + }, + { + "name": "automatic_networking", + "label": "Automatic Networking", + "help": "This defines how other nodes in the High Fidelity metaverse will be able to reach your domain-server.
If you don't want to deal with any network settings, use full automatic networking.", + "default": "full", + "type": "select", + "options": [ + { + "value": "full", + "label": "Full: update both the IP address and port to reach my server" + }, + { + "value": "ip", + "label": "IP Only: update just my IP address, I will open the port manually" + }, + { + "value": "none", + "label": "None: use the network information I have entered for this domain at data.highfidelity.io" + } + ] + } ] }, { From 2eec6c1401e82615b18e4e2d7627d4c6ff6987c7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 12:00:10 -0700 Subject: [PATCH 04/44] changes to settings.js to allow for select inputs --- domain-server/resources/web/js/settings.js | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 17365a27a1..4c5c118fef 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -33,9 +33,24 @@ var viewHelpers = { input_type = _.has(setting, 'type') ? setting.type : "text" form_group += ""; - form_group += "" + + if (setting.type === 'select') { + form_group += "" + + form_group += "" + } else { + form_group += "" + } + form_group += "" + setting.help + "" } @@ -90,6 +105,11 @@ $(document).ready(function(){ $('#settings-form').on('click', '#choose-domain-btn', function(){ chooseFromHighFidelityDomains($(this)) }) + + $('#settings-form').on('change', 'select', function(){ + console.log("Changed" + $(this)) + $("input[name='" + $(this).attr('data-hidden-input') + "']").val($(this).val()).change() + }) var panelsSource = $('#panels-template').html() Settings.panelsTemplate = _.template(panelsSource) From d5b0904d7ab814be6ec264df04d2a1642ca85d47 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 12:08:19 -0700 Subject: [PATCH 05/44] handle new automatic networking option in domain-server --- domain-server/src/DomainServer.cpp | 69 ++++++++++++++++++------------ 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 4d7ab8b121..155de22af8 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -306,40 +306,53 @@ bool DomainServer::optionallySetupAssignmentPayment() { } void DomainServer::setupDynamicSocketUpdating() { - const QString ENABLE_DYNAMIC_SOCKET_UPDATING_KEY_PATH = "metaverse.update_sockets"; + const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; - const QVariant* updateSocketValue = valueForKeyPath(_settingsManager.getSettingsMap(), - ENABLE_DYNAMIC_SOCKET_UPDATING_KEY_PATH); + const QVariant* automaticNetworkVariant = valueForKeyPath(_settingsManager.getSettingsMap(), + METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH); - if (updateSocketValue && updateSocketValue->canConvert(QMetaType::Bool) && updateSocketValue->toBool() - && didSetupAccountManagerWithAccessToken()) { + const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; + const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; + + if (automaticNetworkVariant) { - LimitedNodeList* nodeList = LimitedNodeList::getInstance(); - const QUuid& domainID = nodeList->getSessionUUID(); - - if (!domainID.isNull()) { - qDebug() << "domain-server socket will be updated for domain with ID" - << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); + QString automaticNetworkValue = automaticNetworkVariant->toString(); + if ((automaticNetworkValue == FULL_AUTOMATIC_NETWORKING_VALUE + || automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE)) { - const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; + if (!didSetupAccountManagerWithAccessToken()) { + qDebug() << "Cannot enable domain-server automatic networking without an access token."; + qDebug() << "Please add an access token to your config file or via the web interface."; + + return; + } - // setup our timer to check our IP via stun every 30 seconds - QTimer* dynamicIPTimer = new QTimer(this); - connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); - dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); + LimitedNodeList* nodeList = LimitedNodeList::getInstance(); + const QUuid& domainID = nodeList->getSessionUUID(); - // send public socket changes to the data server so nodes can find us at our new IP - connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewSocketsToDataServer); - - // attempt to update our sockets now - requestCurrentPublicSocketViaSTUN(); - - } else { - qDebug() << "Cannot enable dynamic domain-server IP address updating without a domain ID." - << "Please add an id to your config.json or pass it with the command line argument --id."; - qDebug() << "Failed dynamic IP address update setup. domain-server will now quit."; - - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + if (!domainID.isNull()) { + qDebug() << "domain-server" << automaticNetworkValue << "automatic networking enabled for ID" + << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); + + const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; + + // setup our timer to check our IP via stun every 30 seconds + QTimer* dynamicIPTimer = new QTimer(this); + connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); + dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); + + // send public socket changes to the data server so nodes can find us at our new IP + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewSocketsToDataServer); + + // attempt to update our sockets now + requestCurrentPublicSocketViaSTUN(); + + } else { + qDebug() << "Cannot enable domain-server automatic networking without a domain ID." + << "Please add an ID to your config file or via the web interface."; + + return; + } } } } From 3292808342c10598c994a6dd3ce9a8b6d87b9789 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 16:19:10 -0700 Subject: [PATCH 06/44] update domain network address updating for IP auto networking --- domain-server/src/DomainServer.cpp | 93 ++++++++----------- domain-server/src/DomainServer.h | 4 +- .../src/DomainServerSettingsManager.cpp | 36 ++++++- .../src/DomainServerSettingsManager.h | 1 + 4 files changed, 74 insertions(+), 60 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 155de22af8..130bb101dc 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -75,7 +75,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : loadExistingSessionsFromSettings(); // check if we have the flag that enables dynamic IP - setupDynamicSocketUpdating(); + setupAutomaticNetworking(); } } @@ -305,54 +305,48 @@ bool DomainServer::optionallySetupAssignmentPayment() { return true; } -void DomainServer::setupDynamicSocketUpdating() { +void DomainServer::setupAutomaticNetworking() { const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; - const QVariant* automaticNetworkVariant = valueForKeyPath(_settingsManager.getSettingsMap(), - METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH); - const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; - if (automaticNetworkVariant) { + QString automaticNetworkValue = + _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); + + if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { + if (!didSetupAccountManagerWithAccessToken()) { + qDebug() << "Cannot enable domain-server automatic networking without an access token."; + qDebug() << "Please add an access token to your config file or via the web interface."; + + return; + } - QString automaticNetworkValue = automaticNetworkVariant->toString(); - if ((automaticNetworkValue == FULL_AUTOMATIC_NETWORKING_VALUE - || automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE)) { + LimitedNodeList* nodeList = LimitedNodeList::getInstance(); + const QUuid& domainID = nodeList->getSessionUUID(); + + if (!domainID.isNull()) { + qDebug() << "domain-server" << automaticNetworkValue << "automatic networking enabled for ID" + << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); - if (!didSetupAccountManagerWithAccessToken()) { - qDebug() << "Cannot enable domain-server automatic networking without an access token."; - qDebug() << "Please add an access token to your config file or via the web interface."; - - return; - } + const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; - LimitedNodeList* nodeList = LimitedNodeList::getInstance(); - const QUuid& domainID = nodeList->getSessionUUID(); + // setup our timer to check our IP via stun every 30 seconds + QTimer* dynamicIPTimer = new QTimer(this); + connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); + dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); - if (!domainID.isNull()) { - qDebug() << "domain-server" << automaticNetworkValue << "automatic networking enabled for ID" - << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); - - const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; - - // setup our timer to check our IP via stun every 30 seconds - QTimer* dynamicIPTimer = new QTimer(this); - connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); - dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); - - // send public socket changes to the data server so nodes can find us at our new IP - connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendNewSocketsToDataServer); - - // attempt to update our sockets now - requestCurrentPublicSocketViaSTUN(); - - } else { - qDebug() << "Cannot enable domain-server automatic networking without a domain ID." - << "Please add an ID to your config file or via the web interface."; - - return; - } + // send public socket changes to the data server so nodes can find us at our new IP + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate); + + // attempt to update our sockets now + requestCurrentPublicSocketViaSTUN(); + + } else { + qDebug() << "Cannot enable domain-server automatic networking without a domain ID." + << "Please add an ID to your config file or via the web interface."; + + return; } } } @@ -934,25 +928,16 @@ QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) { return socketObject; } -void DomainServer::sendNewSocketsToDataServer(const HifiSockAddr& newPublicSockAddr) { +void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) { const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID(); - // we're not mointoring for local socket changes yet - // the first time this is called grab whatever it is and assume it'll stay the same - static HifiSockAddr localSockAddr = HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), - LimitedNodeList::getInstance()->getNodeSocket().localPort()); - // setup the domain object to send to the data server - const QString PUBLIC_SOCKET_ATTRIBUTES_KEY = "public_socket_attributes"; - const QString LOCAL_SOCKET_ATTRIBUTES_KEY = "local_socket_attributes"; + const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address"; + const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking"; - QJsonObject domainObject; - domainObject[PUBLIC_SOCKET_ATTRIBUTES_KEY] = jsonForDomainSocketUpdate(newPublicSockAddr); - domainObject[LOCAL_SOCKET_ATTRIBUTES_KEY] = jsonForDomainSocketUpdate(localSockAddr); - - const QString DOMAIN_JSON_OBJECT = "{\"domain\":%1}"; - QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(QString(QJsonDocument(domainObject).toJson())); + const QString DOMAIN_JSON_OBJECT = "{\"domain\": { \"network_address\": \"%1\", \"automatic_networking\": \"ip\" }"; + QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(newPublicSockAddr.getAddress().toString()); AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), QNetworkAccessManager::PutOperation, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index b09602e2e6..44b215006b 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -63,14 +63,14 @@ private slots: void sendPendingTransactionsToServer(); void requestCurrentPublicSocketViaSTUN(); - void sendNewSocketsToDataServer(const HifiSockAddr& newPublicSockAddr); + void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); bool didSetupAccountManagerWithAccessToken(); bool optionallySetupAssignmentPayment(); - void setupDynamicSocketUpdating(); + void setupAutomaticNetworking(); void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index b5d7df65cf..8d866a318c 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -26,6 +26,10 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings.json"; +const QString DESCRIPTION_SETTINGS_KEY = "settings"; +const QString SETTING_DEFAULT_KEY = "default"; +const QString DESCRIPTION_NAME_KEY = "name"; + DomainServerSettingsManager::DomainServerSettingsManager() : _descriptionArray(), _configMap() @@ -63,6 +67,34 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList } } +QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString &keyPath) { + const QVariant* foundValue = valueForKeyPath(_configMap.getMergedConfig(), keyPath); + + if (foundValue) { + return *foundValue; + } else { + int dotIndex = keyPath.indexOf('.'); + + QString groupKey = keyPath.mid(0, dotIndex); + QString settingKey = keyPath.mid(dotIndex); + + foreach(const QVariant& group, _descriptionArray.toVariantList()) { + QVariantMap groupMap = group.toMap(); + + if (groupMap[DESCRIPTION_NAME_KEY].toString() == groupKey) { + foreach(const QVariant& setting, groupMap[DESCRIPTION_SETTINGS_KEY].toList()) { + QVariantMap settingMap = setting.toMap(); + if (settingMap[DESCRIPTION_NAME_KEY].toString() == settingKey) { + return settingMap[SETTING_DEFAULT_KEY]; + } + } + } + } + } + + return *foundValue; +} + const QString SETTINGS_PATH = "/settings.json"; bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) { @@ -127,10 +159,6 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection return false; } -const QString DESCRIPTION_SETTINGS_KEY = "settings"; -const QString SETTING_DEFAULT_KEY = "default"; -const QString DESCRIPTION_NAME_KEY = "name"; - QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& typeValue, bool isAuthenticated) { QJsonObject responseObject; diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index b60cb32dfd..c2e8a7d90d 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -26,6 +26,7 @@ public: bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url); void setupConfigMap(const QStringList& argumentList); + QVariant valueOrDefaultValueForKeyPath(const QString& keyPath); QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } private: From d6572c3e2ee88ab8c9acd4132287f4ee917dde9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 16:38:44 -0700 Subject: [PATCH 07/44] handle automatic networking changes with data-server --- .../resources/describe-settings.json | 2 +- domain-server/src/DomainServer.cpp | 40 ++++++++++++++----- domain-server/src/DomainServer.h | 2 + 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index e1d478753c..303ca7805b 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -29,7 +29,7 @@ "label": "IP Only: update just my IP address, I will open the port manually" }, { - "value": "none", + "value": "disabled", "label": "None: use the network information I have entered for this domain at data.highfidelity.io" } ] diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d6069cac64..3be232dd67 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -74,7 +74,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : loadExistingSessionsFromSettings(); - // check if we have the flag that enables dynamic IP + // setup automatic networking settings with data server setupAutomaticNetworking(); } } @@ -310,22 +310,24 @@ bool DomainServer::optionallySetupAssignmentPayment() { return true; } +const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; +const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; +const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; + void DomainServer::setupAutomaticNetworking() { const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; - const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; - const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; + if (!didSetupAccountManagerWithAccessToken()) { + qDebug() << "Cannot setup domain-server automatic networking without an access token."; + qDebug() << "Please add an access token to your config file or via the web interface."; + + return; + } QString automaticNetworkValue = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { - if (!didSetupAccountManagerWithAccessToken()) { - qDebug() << "Cannot enable domain-server automatic networking without an access token."; - qDebug() << "Please add an access token to your config file or via the web interface."; - - return; - } LimitedNodeList* nodeList = LimitedNodeList::getInstance(); const QUuid& domainID = nodeList->getSessionUUID(); @@ -353,6 +355,8 @@ void DomainServer::setupAutomaticNetworking() { return; } + } else { + updateNetworkingInfoWithDataServer(automaticNetworkValue); } } @@ -933,7 +937,13 @@ QJsonObject jsonForDomainSocketUpdate(const HifiSockAddr& socket) { return socketObject; } +const QString DOMAIN_UPDATE_AUTOMATIC_NETWORKING_KEY = "automatic_networking"; + void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) { + updateNetworkingInfoWithDataServer(IP_ONLY_AUTOMATIC_NETWORKING_VALUE, newPublicSockAddr.getAddress().toString()); +} + +void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress) { const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; const QUuid& domainID = LimitedNodeList::getInstance()->getSessionUUID(); @@ -941,8 +951,16 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) const QString PUBLIC_NETWORK_ADDRESS_KEY = "network_address"; const QString AUTOMATIC_NETWORKING_KEY = "automatic_networking"; - const QString DOMAIN_JSON_OBJECT = "{\"domain\": { \"network_address\": \"%1\", \"automatic_networking\": \"ip\" }"; - QString domainUpdateJSON = DOMAIN_JSON_OBJECT.arg(newPublicSockAddr.getAddress().toString()); + QJsonObject domainObject; + if (!networkAddress.isEmpty()) { + domainObject[PUBLIC_NETWORK_ADDRESS_KEY] = networkAddress; + } + + qDebug() << "Updating automatic networking setting in domain-server to" << newSetting; + + domainObject[AUTOMATIC_NETWORKING_KEY] = newSetting; + + QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), QNetworkAccessManager::PutOperation, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 44b215006b..d6846fc610 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -70,7 +70,9 @@ private: bool optionallyReadX509KeyAndCertificate(); bool didSetupAccountManagerWithAccessToken(); bool optionallySetupAssignmentPayment(); + void setupAutomaticNetworking(); + void updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress = QString()); void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); From ae90b381727ac8c378044eb2ebce3fe1be9e3512 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 1 Oct 2014 17:19:34 -0700 Subject: [PATCH 08/44] add the ice server --- CMakeLists.txt | 1 + ice-server/CMakeLists.txt | 9 +++++++++ ice-server/src/IceServer.cpp | 18 ++++++++++++++++++ ice-server/src/IceServer.h | 22 ++++++++++++++++++++++ ice-server/src/main.cpp | 27 +++++++++++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 ice-server/CMakeLists.txt create mode 100644 ice-server/src/IceServer.cpp create mode 100644 ice-server/src/IceServer.h create mode 100644 ice-server/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c0bfb0892..62cdc925f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ endforeach() # targets on all platforms add_subdirectory(assignment-client) add_subdirectory(domain-server) +add_subdirectory(ice-server) add_subdirectory(interface) add_subdirectory(tests) add_subdirectory(tools) diff --git a/ice-server/CMakeLists.txt b/ice-server/CMakeLists.txt new file mode 100644 index 0000000000..c81ba16248 --- /dev/null +++ b/ice-server/CMakeLists.txt @@ -0,0 +1,9 @@ +set(TARGET_NAME ice-server) + +# setup the project and link required Qt modules +setup_hifi_project(Network) + +# link the shared hifi libraries +link_hifi_libraries(networking shared) + +link_shared_dependencies() \ No newline at end of file diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp new file mode 100644 index 0000000000..6543c41c31 --- /dev/null +++ b/ice-server/src/IceServer.cpp @@ -0,0 +1,18 @@ +// +// IceServer.cpp +// ice-server/src +// +// Created by Stephen Birarda on 2014-10-01. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "IceServer.h" + +IceServer::IceServer(int argc, char* argv[]) : + QCoreApplication(argc, argv) +{ + +} diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h new file mode 100644 index 0000000000..7d56737ca1 --- /dev/null +++ b/ice-server/src/IceServer.h @@ -0,0 +1,22 @@ +// +// IceServer.h +// ice-server/src +// +// Created by Stephen Birarda on 2014-10-01. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_IceServer_h +#define hifi_IceServer_h + +#include + +class IceServer : public QCoreApplication { +public: + IceServer(int argc, char* argv[]); +}; + +#endif // hifi_IceServer_h \ No newline at end of file diff --git a/ice-server/src/main.cpp b/ice-server/src/main.cpp new file mode 100644 index 0000000000..21c8b563b1 --- /dev/null +++ b/ice-server/src/main.cpp @@ -0,0 +1,27 @@ +// +// main.cpp +// ice-server/src +// +// Created by Stephen Birarda on 10/01/12. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include + +#include "IceServer.h" + +int main(int argc, char* argv[]) { +#ifndef WIN32 + setvbuf(stdout, NULL, _IOLBF, 0); +#endif + + qInstallMessageHandler(Logging::verboseMessageHandler); + + IceServer iceServer(argc, argv); + return iceServer.exec(); +} \ No newline at end of file From e0a721209a18a77325e53bd638e79eb56f07fb9c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 09:55:00 -0700 Subject: [PATCH 09/44] add a Node superclass to handle P2P connection --- libraries/networking/src/NetworkPeer.cpp | 66 ++++++++++++++++++++++++ libraries/networking/src/NetworkPeer.h | 46 +++++++++++++++++ libraries/networking/src/Node.cpp | 48 +---------------- libraries/networking/src/Node.h | 22 ++------ 4 files changed, 116 insertions(+), 66 deletions(-) create mode 100644 libraries/networking/src/NetworkPeer.cpp create mode 100644 libraries/networking/src/NetworkPeer.h diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp new file mode 100644 index 0000000000..bb26b2a119 --- /dev/null +++ b/libraries/networking/src/NetworkPeer.cpp @@ -0,0 +1,66 @@ +// +// NetworkPeer.cpp +// libraries/networking/src +// +// Created by Stephen Birarda on 2014-10-02. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "NetworkPeer.h" + +NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : + _uuid(uuid), + _publicSocket(publicSocket), + _localSocket(localSocket), + _symmetricSocket(), + _activeSocket(NULL) +{ + +} + +void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) { + if (_activeSocket == &_publicSocket) { + // if the active socket was the public socket then reset it to NULL + _activeSocket = NULL; + } + + _publicSocket = publicSocket; +} + +void NetworkPeer::setLocalSocket(const HifiSockAddr& localSocket) { + if (_activeSocket == &_localSocket) { + // if the active socket was the local socket then reset it to NULL + _activeSocket = NULL; + } + + _localSocket = localSocket; +} + +void NetworkPeer::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { + if (_activeSocket == &_symmetricSocket) { + // if the active socket was the symmetric socket then reset it to NULL + _activeSocket = NULL; + } + + _symmetricSocket = symmetricSocket; +} + +void NetworkPeer::activateLocalSocket() { + qDebug() << "Activating local socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_localSocket; +} + +void NetworkPeer::activatePublicSocket() { + qDebug() << "Activating public socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_publicSocket; +} + +void NetworkPeer::activateSymmetricSocket() { + qDebug() << "Activating symmetric socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_symmetricSocket; +} \ No newline at end of file diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h new file mode 100644 index 0000000000..b4e472b80c --- /dev/null +++ b/libraries/networking/src/NetworkPeer.h @@ -0,0 +1,46 @@ +// +// NetworkPeer.h +// libraries/networking/src +// +// Created by Stephen Birarda on 2014-10-02. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_NetworkPeer_h +#define hifi_NetworkPeer_h + +#include +#include + +#include "HifiSockAddr.h" + +class NetworkPeer : public QObject { +public: + NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + + const HifiSockAddr& getPublicSocket() const { return _publicSocket; } + void setPublicSocket(const HifiSockAddr& publicSocket); + const HifiSockAddr& getLocalSocket() const { return _localSocket; } + void setLocalSocket(const HifiSockAddr& localSocket); + const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; } + void setSymmetricSocket(const HifiSockAddr& symmetricSocket); + + const HifiSockAddr* getActiveSocket() const { return _activeSocket; } + + void activatePublicSocket(); + void activateLocalSocket(); + void activateSymmetricSocket(); + +protected: + QUuid _uuid; + + HifiSockAddr _publicSocket; + HifiSockAddr _localSocket; + HifiSockAddr _symmetricSocket; + HifiSockAddr* _activeSocket; +}; + +#endif // hifi_NetworkPeer_h \ No newline at end of file diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 662c827069..942f911f23 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -44,14 +44,10 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { } Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : + NetworkPeer(uuid, publicSocket, localSocket), _type(type), - _uuid(uuid), _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), _lastHeardMicrostamp(usecTimestampNow()), - _publicSocket(publicSocket), - _localSocket(localSocket), - _symmetricSocket(), - _activeSocket(NULL), _connectionSecret(), _bytesReceivedMovingAverage(NULL), _linkedData(NULL), @@ -68,48 +64,6 @@ Node::~Node() { delete _bytesReceivedMovingAverage; } -void Node::setPublicSocket(const HifiSockAddr& publicSocket) { - if (_activeSocket == &_publicSocket) { - // if the active socket was the public socket then reset it to NULL - _activeSocket = NULL; - } - - _publicSocket = publicSocket; -} - -void Node::setLocalSocket(const HifiSockAddr& localSocket) { - if (_activeSocket == &_localSocket) { - // if the active socket was the local socket then reset it to NULL - _activeSocket = NULL; - } - - _localSocket = localSocket; -} - -void Node::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { - if (_activeSocket == &_symmetricSocket) { - // if the active socket was the symmetric socket then reset it to NULL - _activeSocket = NULL; - } - - _symmetricSocket = symmetricSocket; -} - -void Node::activateLocalSocket() { - qDebug() << "Activating local socket for node" << *this; - _activeSocket = &_localSocket; -} - -void Node::activatePublicSocket() { - qDebug() << "Activating public socket for node" << *this; - _activeSocket = &_publicSocket; -} - -void Node::activateSymmetricSocket() { - qDebug() << "Activating symmetric socket for node" << *this; - _activeSocket = &_symmetricSocket; -} - void Node::recordBytesReceived(int bytesReceived) { if (!_bytesReceivedMovingAverage) { _bytesReceivedMovingAverage = new SimpleMovingAverage(100); diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 0d5703b45c..8f276f4e1d 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -21,6 +21,7 @@ #include #include "HifiSockAddr.h" +#include "NetworkPeer.h" #include "NodeData.h" #include "SimpleMovingAverage.h" #include "MovingPercentile.h" @@ -44,7 +45,7 @@ namespace NodeType { const QString& getNodeTypeName(NodeType_t nodeType); } -class Node : public QObject { +class Node : public NetworkPeer { Q_OBJECT public: Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); @@ -64,19 +65,6 @@ public: quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } - - const HifiSockAddr& getPublicSocket() const { return _publicSocket; } - void setPublicSocket(const HifiSockAddr& publicSocket); - const HifiSockAddr& getLocalSocket() const { return _localSocket; } - void setLocalSocket(const HifiSockAddr& localSocket); - const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; } - void setSymmetricSocket(const HifiSockAddr& symmetricSocket); - - const HifiSockAddr* getActiveSocket() const { return _activeSocket; } - - void activatePublicSocket(); - void activateLocalSocket(); - void activateSymmetricSocket(); const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } @@ -107,13 +95,9 @@ private: Node& operator=(Node otherNode); NodeType_t _type; - QUuid _uuid; quint64 _wakeTimestamp; quint64 _lastHeardMicrostamp; - HifiSockAddr _publicSocket; - HifiSockAddr _localSocket; - HifiSockAddr _symmetricSocket; - HifiSockAddr* _activeSocket; + QUuid _connectionSecret; SimpleMovingAverage* _bytesReceivedMovingAverage; NodeData* _linkedData; From cca1c30207d5502a0806e24bdc99b0eab65f3b1b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 13:39:58 -0700 Subject: [PATCH 10/44] build out more of the ice-server, make connect requests from NodeList --- ice-server/src/IceServer.cpp | 54 +++++++++- ice-server/src/IceServer.h | 11 +- libraries/networking/src/DomainHandler.cpp | 2 + libraries/networking/src/DomainHandler.h | 3 + libraries/networking/src/NetworkPeer.cpp | 7 ++ libraries/networking/src/NetworkPeer.h | 9 ++ libraries/networking/src/Node.h | 3 - libraries/networking/src/NodeList.cpp | 115 ++++++++++++--------- libraries/networking/src/NodeList.h | 2 + libraries/networking/src/PacketHeaders.h | 3 +- 10 files changed, 154 insertions(+), 55 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 6543c41c31..cea05ebe30 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -9,10 +9,62 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "IceServer.h" IceServer::IceServer(int argc, char* argv[]) : - QCoreApplication(argc, argv) + QCoreApplication(argc, argv), + _serverSocket() { + // start the ice-server socket + qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; + _serverSocket.bind(QHostAddress::AnyIPv4, ICE_SERVER_DEFAULT_PORT); + // call our process datagrams slot when the UDP socket has packets ready + connect(&_serverSocket, &QUdpSocket::readyRead, this, &IceServer::processDatagrams); +} + +void IceServer::processDatagrams() { + HifiSockAddr sendingSockAddr; + QByteArray incomingPacket; + + while (_serverSocket.hasPendingDatagrams()) { + incomingPacket.resize(_serverSocket.pendingDatagramSize()); + + _serverSocket.readDatagram(incomingPacket.data(), incomingPacket.size(), + sendingSockAddr.getAddressPointer(), sendingSockAddr.getPortPointer()); + + + if (packetTypeForPacket(incomingPacket) == PacketTypeIceServerHeartbeat) { + QUuid senderUUID = uuidFromPacketHeader(incomingPacket); + + // pull the public and private sock addrs for this peer + HifiSockAddr publicSocket, localSocket; + + QDataStream hearbeatStream(incomingPacket); + hearbeatStream.skipRawData(numBytesForPacketHeader(incomingPacket)); + + hearbeatStream >> publicSocket >> localSocket; + + // make sure we have this sender in our peer hash + SharedNetworkPeer matchingPeer = _activePeers.value(senderUUID); + + if (!matchingPeer) { + // if we don't have this sender we need to create them now + matchingPeer = SharedNetworkPeer(new NetworkPeer(senderUUID, publicSocket, localSocket)); + + qDebug() << "Added a new network peer" << *matchingPeer; + + } else { + // we already had the peer so just potentially update their sockets + matchingPeer->setPublicSocket(publicSocket); + matchingPeer->setLocalSocket(localSocket); + } + + // check if this node also included a UUID that they would like to connect to + QUuid connectRequestUUID; + hearbeatStream >> connectRequestUUID; + } + } } diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 7d56737ca1..3db9a6b2e2 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -12,11 +12,20 @@ #ifndef hifi_IceServer_h #define hifi_IceServer_h -#include +#include +#include +#include + +#include class IceServer : public QCoreApplication { public: IceServer(int argc, char* argv[]); +private slots: + void processDatagrams(); +private: + QHash _activePeers; + QUdpSocket _serverSocket; }; #endif // hifi_IceServer_h \ No newline at end of file diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 9c0ae55d7e..b13f598a08 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -25,6 +25,7 @@ DomainHandler::DomainHandler(QObject* parent) : _uuid(), _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), + _requiresICE(true), _isConnected(false), _handshakeTimer(NULL), _settingsObject(), @@ -35,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : void DomainHandler::clearConnectionInfo() { _uuid = QUuid(); + _requiresICE = true; _isConnected = false; emit disconnectedFromDomain(); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index bfdb5d7f38..9733a8bff3 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -54,6 +54,8 @@ public: const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } + bool requiresICE() const { return _requiresICE; } + bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); @@ -85,6 +87,7 @@ private: QString _hostname; HifiSockAddr _sockAddr; QUuid _assignmentUUID; + bool _requiresICE; bool _isConnected; QTimer* _handshakeTimer; QJsonObject _settingsObject; diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index bb26b2a119..57a4a97331 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -63,4 +63,11 @@ void NetworkPeer::activatePublicSocket() { void NetworkPeer::activateSymmetricSocket() { qDebug() << "Activating symmetric socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); _activeSocket = &_symmetricSocket; +} + +QDebug operator<<(QDebug debug, const NetworkPeer &peer) { + debug << uuidStringWithoutCurlyBraces(peer.getUUID()) + << "- public:" << peer.getPublicSocket() + << "- local:" << peer.getLocalSocket(); + return debug; } \ No newline at end of file diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index b4e472b80c..ae1812cf87 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -17,10 +17,16 @@ #include "HifiSockAddr.h" +const QString ICE_SERVER_HOSTNAME = "localhost"; +const int ICE_SERVER_DEFAULT_PORT = 7337; + class NetworkPeer : public QObject { public: NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + const QUuid& getUUID() const { return _uuid; } + void setUUID(const QUuid& uuid) { _uuid = uuid; } + const HifiSockAddr& getPublicSocket() const { return _publicSocket; } void setPublicSocket(const HifiSockAddr& publicSocket); const HifiSockAddr& getLocalSocket() const { return _localSocket; } @@ -43,4 +49,7 @@ protected: HifiSockAddr* _activeSocket; }; +QDebug operator<<(QDebug debug, const NetworkPeer &peer); +typedef QSharedPointer SharedNetworkPeer; + #endif // hifi_NetworkPeer_h \ No newline at end of file diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 8f276f4e1d..f300499add 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -57,9 +57,6 @@ public: char getType() const { return _type; } void setType(char type) { _type = type; } - const QUuid& getUUID() const { return _uuid; } - void setUUID(const QUuid& uuid) { _uuid = uuid; } - quint64 getWakeTimestamp() const { return _wakeTimestamp; } void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 3a1ed79f77..451b30c58b 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -243,61 +243,78 @@ void NodeList::sendDomainServerCheckIn() { // send a STUN request to figure it out sendSTUNRequest(); } else if (!_domainHandler.getIP().isNull()) { - - bool isUsingDTLS = false; - PacketType domainPacketType = !_domainHandler.isConnected() + if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { + sendICERequestForDomainConnection(); + } else { + bool isUsingDTLS = false; + + PacketType domainPacketType = !_domainHandler.isConnected() ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; - - if (!_domainHandler.isConnected()) { - qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); + + if (!_domainHandler.isConnected()) { + qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); + } + + // construct the DS check in packet + QUuid packetUUID = _sessionUUID; + + if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { + // this is a connect request and we're an assigned node + // so set our packetUUID as the assignment UUID + packetUUID = _domainHandler.getAssignmentUUID(); + } + + QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); + QDataStream packetStream(&domainServerPacket, QIODevice::Append); + + // pack our data to send to the domain-server + packetStream << _ownerType << _publicSockAddr + << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) + << (quint8) _nodeTypesOfInterest.size(); + + // copy over the bytes for node types of interest, if required + foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { + packetStream << nodeTypeOfInterest; + } + + if (!isUsingDTLS) { + writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); + } + + const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; + static unsigned int numDomainCheckins = 0; + + // send a STUN request every Nth domain server check in so we update our public socket, if required + if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { + sendSTUNRequest(); + } + + if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS + // so emit our signal that indicates that + emit limitOfSilentDomainCheckInsReached(); + } + + // increment the count of un-replied check-ins + _numNoReplyDomainCheckIns++; } - - // construct the DS check in packet - QUuid packetUUID = _sessionUUID; - - if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { - // this is a connect request and we're an assigned node - // so set our packetUUID as the assignment UUID - packetUUID = _domainHandler.getAssignmentUUID(); - } - - QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); - QDataStream packetStream(&domainServerPacket, QIODevice::Append); - - // pack our data to send to the domain-server - packetStream << _ownerType << _publicSockAddr - << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) - << (quint8) _nodeTypesOfInterest.size(); - - // copy over the bytes for node types of interest, if required - foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { - packetStream << nodeTypeOfInterest; - } - - if (!isUsingDTLS) { - writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); - } - - const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; - static unsigned int numDomainCheckins = 0; - - // send a STUN request every Nth domain server check in so we update our public socket, if required - if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { - sendSTUNRequest(); - } - - if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS - // so emit our signal that indicates that - emit limitOfSilentDomainCheckInsReached(); - } - - // increment the count of un-replied check-ins - _numNoReplyDomainCheckIns++; } } +void NodeList::sendICERequestForDomainConnection() { + QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat); + QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); + + iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); + iceDataStream << _domainHandler.getUUID(); + + qDebug() << "Sending packet to ICE server to request connection info for peer with ID" + << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); + + _nodeSocket.writeDatagram(iceRequestByteArray, QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); +} + int NodeList::processDomainServerList(const QByteArray& packet) { // this is a packet from the domain server, reset the count of un-replied check-ins _numNoReplyDomainCheckIns = 0; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 8293d0a05a..ad0f74e517 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -91,6 +91,8 @@ private: void sendSTUNRequest(); bool processSTUNResponse(const QByteArray& packet); + void sendICERequestForDomainConnection(); + void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); void activateSocketFromNodeCommunication(const QByteArray& packet, const SharedNodePointer& sendingNode); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 207cf680d3..aaab9c2928 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -70,7 +70,8 @@ enum PacketType { PacketTypeVoxelEditNack, PacketTypeParticleEditNack, PacketTypeEntityEditNack, // 48 - PacketTypeSignedTransactionPayment + PacketTypeSignedTransactionPayment, + PacketTypeIceServerHeartbeat }; typedef char PacketVersion; From 11659401ee9281f3b4f7c5daaf8790740104a51b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 13:47:53 -0700 Subject: [PATCH 11/44] add an identifier for repeated requests to the ice server --- ice-server/src/IceServer.cpp | 4 +++- libraries/networking/src/NodeList.cpp | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index cea05ebe30..0877c8591f 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -53,13 +53,15 @@ void IceServer::processDatagrams() { if (!matchingPeer) { // if we don't have this sender we need to create them now matchingPeer = SharedNetworkPeer(new NetworkPeer(senderUUID, publicSocket, localSocket)); + _activePeers.insert(senderUUID, matchingPeer); qDebug() << "Added a new network peer" << *matchingPeer; - } else { // we already had the peer so just potentially update their sockets matchingPeer->setPublicSocket(publicSocket); matchingPeer->setLocalSocket(localSocket); + + qDebug() << "Matched hearbeat to existing network peer" << *matchingPeer; } // check if this node also included a UUID that they would like to connect to diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 451b30c58b..afefd2a5c1 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -250,7 +250,7 @@ void NodeList::sendDomainServerCheckIn() { bool isUsingDTLS = false; PacketType domainPacketType = !_domainHandler.isConnected() - ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; + ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; if (!_domainHandler.isConnected()) { qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); @@ -303,7 +303,10 @@ void NodeList::sendDomainServerCheckIn() { } void NodeList::sendICERequestForDomainConnection() { - QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat); + + static QUuid iceUUID = QUuid::createUuid(); + + QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, iceUUID); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); From 262054d0ebbe30667bf6655d20322e7b2500b9bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 14:18:17 -0700 Subject: [PATCH 12/44] handle ICE requirement in address manager response --- ice-server/src/IceServer.cpp | 4 + interface/src/Application.cpp | 7 +- libraries/networking/src/AddressManager.cpp | 20 +++- libraries/networking/src/AddressManager.h | 3 +- libraries/networking/src/DomainHandler.cpp | 17 +++- libraries/networking/src/DomainHandler.h | 5 +- libraries/networking/src/NodeList.cpp | 106 ++++++++++---------- 7 files changed, 97 insertions(+), 65 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index 0877c8591f..a24abd3a49 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -67,6 +67,10 @@ void IceServer::processDatagrams() { // check if this node also included a UUID that they would like to connect to QUuid connectRequestUUID; hearbeatStream >> connectRequestUUID; + + if (!connectRequestUUID.isNull()) { + qDebug() << "Peer wants to connect to peer with ID" << uuidStringWithoutCurlyBraces(connectRequestUUID); + } } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ec40056299..51b78b6901 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -299,9 +299,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : AddressManager& addressManager = AddressManager::getInstance(); - // connect to the domainChangeRequired signal on AddressManager - connect(&addressManager, &AddressManager::possibleDomainChangeRequired, + // handle domain change signals from AddressManager + connect(&addressManager, &AddressManager::possibleDomainChangeRequiredToHostname, this, &Application::changeDomainHostname); + + connect(&addressManager, &AddressManager::possibleDomainChangeRequiredViaICEForID, + &domainHandler, &DomainHandler::setIceServerHostnameAndID); _settings = new QSettings(this); _numChangedSettings = 0; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 4509a1790c..a78e1e76a4 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -118,9 +118,21 @@ void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) { QJsonObject domainObject = dataObject[ADDRESS_API_DOMAIN_KEY].toObject(); const QString DOMAIN_NETWORK_ADDRESS_KEY = "network_address"; - QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString(); + const QString DOMAIN_ICE_SERVER_ADDRESS_KEY = "ice_server_address"; - emit possibleDomainChangeRequired(domainHostname); + if (domainObject.contains(DOMAIN_NETWORK_ADDRESS_KEY)) { + QString domainHostname = domainObject[DOMAIN_NETWORK_ADDRESS_KEY].toString(); + + emit possibleDomainChangeRequiredToHostname(domainHostname); + } else { + QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString(); + + const QString DOMAIN_ID_KEY = "id"; + QString domainIDString = domainObject[DOMAIN_ID_KEY].toString(); + QUuid domainID(domainIDString); + + emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID); + } // take the path that came back const QString LOCATION_KEY = "location"; @@ -182,7 +194,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) { QRegExp hostnameRegex(HOSTNAME_REGEX_STRING, Qt::CaseInsensitive); if (hostnameRegex.indexIn(lookupString) != -1) { - emit possibleDomainChangeRequired(hostnameRegex.cap(0)); + emit possibleDomainChangeRequiredToHostname(hostnameRegex.cap(0)); emit lookupResultsFinished(); return true; } @@ -190,7 +202,7 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) { QRegExp ipAddressRegex(IP_ADDRESS_REGEX_STRING); if (ipAddressRegex.indexIn(lookupString) != -1) { - emit possibleDomainChangeRequired(ipAddressRegex.cap(0)); + emit possibleDomainChangeRequiredToHostname(ipAddressRegex.cap(0)); emit lookupResultsFinished(); return true; } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index f7cc7c52ee..128c395cb4 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -40,7 +40,8 @@ signals: void lookupResultsFinished(); void lookupResultIsOffline(); void lookupResultIsNotFound(); - void possibleDomainChangeRequired(const QString& newHostname); + void possibleDomainChangeRequiredToHostname(const QString& newHostname); + void possibleDomainChangeRequiredViaICEForID(const QString& iceServerHostname, const QUuid& domainID); void locationChangeRequired(const glm::vec3& newPosition, bool hasOrientationChange, const glm::quat& newOrientation, bool shouldFaceLocation); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index b13f598a08..e5c8abb171 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -25,7 +25,7 @@ DomainHandler::DomainHandler(QObject* parent) : _uuid(), _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), - _requiresICE(true), + _iceServerSockAddr(), _isConnected(false), _handshakeTimer(NULL), _settingsObject(), @@ -36,7 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : void DomainHandler::clearConnectionInfo() { _uuid = QUuid(); - _requiresICE = true; + _iceServerSockAddr = HifiSockAddr(); _isConnected = false; emit disconnectedFromDomain(); @@ -125,6 +125,19 @@ void DomainHandler::setHostname(const QString& hostname) { } } +void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id) { + if (id != _uuid) { + // re-set the domain info to connect to new domain + hardReset(); + + _uuid = id; + _iceServerSockAddr = HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); + + qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid) + << "- ICE required via ice server at" << iceServerHostname; + } +} + void DomainHandler::completedHostnameLookup(const QHostInfo& hostInfo) { for (int i = 0; i < hostInfo.addresses().size(); i++) { if (hostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 9733a8bff3..ffd288d93d 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -54,7 +54,7 @@ public: const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } - bool requiresICE() const { return _requiresICE; } + bool requiresICE() const { return !_iceServerSockAddr.isNull(); } bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); @@ -68,6 +68,7 @@ public: void softReset(); public slots: void setHostname(const QString& hostname); + void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); private slots: void completedHostnameLookup(const QHostInfo& hostInfo); @@ -87,7 +88,7 @@ private: QString _hostname; HifiSockAddr _sockAddr; QUuid _assignmentUUID; - bool _requiresICE; + HifiSockAddr _iceServerSockAddr; bool _isConnected; QTimer* _handshakeTimer; QJsonObject _settingsObject; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index afefd2a5c1..3af71546ce 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -242,63 +242,61 @@ void NodeList::sendDomainServerCheckIn() { // we don't know our public socket and we need to send it to the domain server // send a STUN request to figure it out sendSTUNRequest(); + } else if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { + sendICERequestForDomainConnection(); } else if (!_domainHandler.getIP().isNull()) { - if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { - sendICERequestForDomainConnection(); - } else { - bool isUsingDTLS = false; - - PacketType domainPacketType = !_domainHandler.isConnected() - ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; - - if (!_domainHandler.isConnected()) { - qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); - } - - // construct the DS check in packet - QUuid packetUUID = _sessionUUID; - - if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { - // this is a connect request and we're an assigned node - // so set our packetUUID as the assignment UUID - packetUUID = _domainHandler.getAssignmentUUID(); - } - - QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); - QDataStream packetStream(&domainServerPacket, QIODevice::Append); - - // pack our data to send to the domain-server - packetStream << _ownerType << _publicSockAddr - << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) - << (quint8) _nodeTypesOfInterest.size(); - - // copy over the bytes for node types of interest, if required - foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { - packetStream << nodeTypeOfInterest; - } - - if (!isUsingDTLS) { - writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); - } - - const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; - static unsigned int numDomainCheckins = 0; - - // send a STUN request every Nth domain server check in so we update our public socket, if required - if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { - sendSTUNRequest(); - } - - if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS - // so emit our signal that indicates that - emit limitOfSilentDomainCheckInsReached(); - } - - // increment the count of un-replied check-ins - _numNoReplyDomainCheckIns++; + bool isUsingDTLS = false; + + PacketType domainPacketType = !_domainHandler.isConnected() + ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; + + if (!_domainHandler.isConnected()) { + qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); } + + // construct the DS check in packet + QUuid packetUUID = _sessionUUID; + + if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { + // this is a connect request and we're an assigned node + // so set our packetUUID as the assignment UUID + packetUUID = _domainHandler.getAssignmentUUID(); + } + + QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); + QDataStream packetStream(&domainServerPacket, QIODevice::Append); + + // pack our data to send to the domain-server + packetStream << _ownerType << _publicSockAddr + << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) + << (quint8) _nodeTypesOfInterest.size(); + + // copy over the bytes for node types of interest, if required + foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { + packetStream << nodeTypeOfInterest; + } + + if (!isUsingDTLS) { + writeDatagram(domainServerPacket, _domainHandler.getSockAddr(), QUuid()); + } + + const int NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST = 5; + static unsigned int numDomainCheckins = 0; + + // send a STUN request every Nth domain server check in so we update our public socket, if required + if (numDomainCheckins++ % NUM_DOMAIN_SERVER_CHECKINS_PER_STUN_REQUEST == 0) { + sendSTUNRequest(); + } + + if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { + // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS + // so emit our signal that indicates that + emit limitOfSilentDomainCheckInsReached(); + } + + // increment the count of un-replied check-ins + _numNoReplyDomainCheckIns++; } } From 6425276eb002629085fe8bc84b79d448ecae625f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 14:33:39 -0700 Subject: [PATCH 13/44] have domain-server using full networking heartbeat with ice-server --- domain-server/src/DomainServer.cpp | 31 ++++++++++++++++---- domain-server/src/DomainServer.h | 1 + libraries/networking/src/LimitedNodeList.cpp | 21 +++++++++++++ libraries/networking/src/LimitedNodeList.h | 2 ++ libraries/networking/src/NetworkPeer.h | 1 + libraries/networking/src/NodeList.cpp | 11 +------ 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c4d4e91600..78baf803fa 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -327,24 +327,39 @@ void DomainServer::setupAutomaticNetworking() { QString automaticNetworkValue = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); - if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { + if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || + automaticNetworkValue == FULL_AUTOMATIC_NETWORKING_VALUE) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); const QUuid& domainID = nodeList->getSessionUUID(); if (!domainID.isNull()) { qDebug() << "domain-server" << automaticNetworkValue << "automatic networking enabled for ID" - << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); + << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); const int STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS = 30 * 1000; + const int STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS = 10 * 1000; - // setup our timer to check our IP via stun every 30 seconds + // setup our timer to check our IP via stun every X seconds QTimer* dynamicIPTimer = new QTimer(this); connect(dynamicIPTimer, &QTimer::timeout, this, &DomainServer::requestCurrentPublicSocketViaSTUN); - dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); - // send public socket changes to the data server so nodes can find us at our new IP - connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate); + if (automaticNetworkValue == IP_ONLY_AUTOMATIC_NETWORKING_VALUE) { + dynamicIPTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); + + // send public socket changes to the data server so nodes can find us at our new IP + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::performIPAddressUpdate); + } else { + dynamicIPTimer->start(STUN_REFLEXIVE_KEEPALIVE_INTERVAL_MSECS); + + // setup a timer to heartbeat with the ice-server every so often + QTimer* iceHeartbeatTimer = new QTimer(this); + connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHearbeatToIceServer); + iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); + + // call our sendHeartbeaToIceServer immediately anytime a public address changes + connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); + } // attempt to update our sockets now requestCurrentPublicSocketViaSTUN(); @@ -968,6 +983,10 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, domainUpdateJSON.toUtf8()); } +void DomainServer::sendHearbeatToIceServer() { + LimitedNodeList::getInstance()->sendHeartbeatToIceServer(); +} + void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index d6846fc610..d5e38acf89 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -64,6 +64,7 @@ private slots: void requestCurrentPublicSocketViaSTUN(); void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr); + void sendHearbeatToIceServer(); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 2c8e968375..b32fbe3b37 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -618,3 +618,24 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { return false; } + +void LimitedNodeList::sendHeartbeatToIceServer(QUuid headerID, const QUuid& connectionRequestID) { + + if (headerID.isNull()) { + headerID = _sessionUUID; + } + + QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); + QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); + + iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); + + if (!connectionRequestID.isNull()) { + iceDataStream << connectionRequestID; + + qDebug() << "Sending packet to ICE server to request connection info for peer with ID" + << uuidStringWithoutCurlyBraces(connectionRequestID); + } + + _nodeSocket.writeDatagram(iceRequestByteArray, QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); +} diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index b34845719c..1e97ba8190 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -106,6 +106,8 @@ public: virtual void sendSTUNRequest(); virtual bool processSTUNResponse(const QByteArray& packet); + + void sendHeartbeatToIceServer(QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid()); public slots: void reset(); void eraseAllNodes(); diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index ae1812cf87..da5850576b 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -19,6 +19,7 @@ const QString ICE_SERVER_HOSTNAME = "localhost"; const int ICE_SERVER_DEFAULT_PORT = 7337; +const int ICE_HEARBEAT_INTERVAL_MSECS = 2 * 1000; class NetworkPeer : public QObject { public: diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 3af71546ce..6d7670b077 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -304,16 +304,7 @@ void NodeList::sendICERequestForDomainConnection() { static QUuid iceUUID = QUuid::createUuid(); - QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, iceUUID); - QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); - - iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); - iceDataStream << _domainHandler.getUUID(); - - qDebug() << "Sending packet to ICE server to request connection info for peer with ID" - << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); - - _nodeSocket.writeDatagram(iceRequestByteArray, QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); + LimitedNodeList::sendHeartbeatToIceServer(iceUUID, _domainHandler.getUUID()); } int NodeList::processDomainServerList(const QByteArray& packet) { From 970ba2296ac09266279692780734da5415c37e3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 14:50:48 -0700 Subject: [PATCH 14/44] initial response from ice server to nodes --- ice-server/src/IceServer.cpp | 20 ++++++++++++++++---- ice-server/src/IceServer.h | 1 + libraries/networking/src/AccountManager.cpp | 2 +- libraries/networking/src/NetworkPeer.cpp | 16 ++++++++++++++++ libraries/networking/src/NetworkPeer.h | 2 ++ libraries/networking/src/NodeList.cpp | 4 ++++ libraries/networking/src/PacketHeaders.h | 6 ++++-- 7 files changed, 44 insertions(+), 7 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a24abd3a49..a2e4221bfd 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -15,6 +15,7 @@ IceServer::IceServer(int argc, char* argv[]) : QCoreApplication(argc, argv), + _id(QUuid::createUuid()), _serverSocket() { // start the ice-server socket @@ -65,11 +66,22 @@ void IceServer::processDatagrams() { } // check if this node also included a UUID that they would like to connect to - QUuid connectRequestUUID; - hearbeatStream >> connectRequestUUID; + QUuid connectRequestID; + hearbeatStream >> connectRequestID; - if (!connectRequestUUID.isNull()) { - qDebug() << "Peer wants to connect to peer with ID" << uuidStringWithoutCurlyBraces(connectRequestUUID); + if (!connectRequestID.isNull()) { + qDebug() << "Peer wants to connect to peer with ID" << uuidStringWithoutCurlyBraces(connectRequestID); + + // check if we have that ID - if we do we can respond with their info, otherwise nothing we can do + SharedNetworkPeer matchingConectee = _activePeers.value(connectRequestID); + if (matchingConectee) { + QByteArray heartbeatResponse = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeatResponse, _id); + QDataStream responseStream(&heartbeatResponse, QIODevice::Append); + + responseStream << matchingConectee; + + _serverSocket.writeDatagram(heartbeatResponse, sendingSockAddr.getAddress(), sendingSockAddr.getPort()); + } } } } diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 3db9a6b2e2..a680bafbc3 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -24,6 +24,7 @@ public: private slots: void processDatagrams(); private: + QUuid _id; QHash _activePeers; QUdpSocket _serverSocket; }; diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 595e4cbb60..7d924d02de 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -60,7 +60,7 @@ AccountManager::AccountManager() : _authURL(), _pendingCallbackMap(), _accountInfo(), - _shouldPersistToSettingsFile(false) + _shouldPersistToSettingsFile(true) { qRegisterMetaType("OAuthAccessToken"); qRegisterMetaTypeStreamOperators("OAuthAccessToken"); diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 57a4a97331..2f94825fe5 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -65,6 +65,22 @@ void NetworkPeer::activateSymmetricSocket() { _activeSocket = &_symmetricSocket; } +QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer) { + out << peer._uuid; + out << peer._publicSocket; + out << peer._localSocket; + + return out; +} + +QDataStream& operator>>(QDataStream& in, NetworkPeer& peer) { + in >> peer._uuid; + in >> peer._publicSocket; + in >> peer._localSocket; + + return in; +} + QDebug operator<<(QDebug debug, const NetworkPeer &peer) { debug << uuidStringWithoutCurlyBraces(peer.getUUID()) << "- public:" << peer.getPublicSocket() diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index da5850576b..052040933b 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -41,6 +41,8 @@ public: void activateLocalSocket(); void activateSymmetricSocket(); + friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); + friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); protected: QUuid _uuid; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 6d7670b077..a1b6011032 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -123,6 +123,10 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr _domainHandler.parseDTLSRequirementPacket(packet); break; } + case PacketTypeIceServerHeartbeatResponse: { + + break; + } case PacketTypePing: { // send back a reply SharedNodePointer matchingNode = sendingNodeForPacket(packet); diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index aaab9c2928..dd1707521c 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -71,7 +71,8 @@ enum PacketType { PacketTypeParticleEditNack, PacketTypeEntityEditNack, // 48 PacketTypeSignedTransactionPayment, - PacketTypeIceServerHeartbeat + PacketTypeIceServerHeartbeat, + PacketTypeIceServerHeartbeatResponse }; typedef char PacketVersion; @@ -81,7 +82,8 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainOAuthRequest << PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse << PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeEntityQuery - << PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeParticleEditNack << PacketTypeEntityEditNack; + << PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeParticleEditNack << PacketTypeEntityEditNack + << PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse; const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; From d26a94f84ca10ec2e73e28d3f3eca0af20834c78 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 15:00:59 -0700 Subject: [PATCH 15/44] remove inactive peers from memory in IceServer --- ice-server/src/IceServer.cpp | 31 ++++++++++++++++++++++++ ice-server/src/IceServer.h | 5 +++- libraries/networking/src/NetworkPeer.cpp | 7 +++++- libraries/networking/src/NetworkPeer.h | 9 +++++++ libraries/networking/src/Node.cpp | 3 --- libraries/networking/src/Node.h | 9 +------ 6 files changed, 51 insertions(+), 13 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index a2e4221bfd..be97df37a4 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -9,10 +9,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include +#include #include "IceServer.h" +const int CLEAR_INACTIVE_PEERS_INTERVAL_MSECS = 1 * 1000; +const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000; + IceServer::IceServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _id(QUuid::createUuid()), @@ -24,6 +30,12 @@ IceServer::IceServer(int argc, char* argv[]) : // call our process datagrams slot when the UDP socket has packets ready connect(&_serverSocket, &QUdpSocket::readyRead, this, &IceServer::processDatagrams); + + // setup our timer to clear inactive peers + QTimer* inactivePeerTimer = new QTimer(this); + connect(inactivePeerTimer, &QTimer::timeout, this, &IceServer::clearInactivePeers); + inactivePeerTimer->start(CLEAR_INACTIVE_PEERS_INTERVAL_MSECS); + } void IceServer::processDatagrams() { @@ -65,6 +77,9 @@ void IceServer::processDatagrams() { qDebug() << "Matched hearbeat to existing network peer" << *matchingPeer; } + // update our last heard microstamp for this network peer to now + matchingPeer->setLastHeardMicrostamp(usecTimestampNow()); + // check if this node also included a UUID that they would like to connect to QUuid connectRequestID; hearbeatStream >> connectRequestID; @@ -86,3 +101,19 @@ void IceServer::processDatagrams() { } } } + +void IceServer::clearInactivePeers() { + NetworkPeerHash::iterator peerItem = _activePeers.begin(); + + while (peerItem != _activePeers.end()) { + SharedNetworkPeer peer = peerItem.value(); + + if ((usecTimestampNow() - peer->getLastHeardMicrostamp()) > (PEER_SILENCE_THRESHOLD_MSECS * 1000)) { + qDebug() << "Removing peer from memory for inactivity -" << *peer; + peerItem = _activePeers.erase(peerItem); + } else { + // we didn't kill this peer, push the iterator forwards + ++peerItem; + } + } +} diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index a680bafbc3..9c4c4242dc 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -18,14 +18,17 @@ #include +typedef QHash NetworkPeerHash; + class IceServer : public QCoreApplication { public: IceServer(int argc, char* argv[]); private slots: void processDatagrams(); + void clearInactivePeers(); private: QUuid _id; - QHash _activePeers; + NetworkPeerHash _activePeers; QUdpSocket _serverSocket; }; diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 2f94825fe5..1da6836bf9 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -9,6 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + +#include #include #include "NetworkPeer.h" @@ -18,7 +21,9 @@ NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, co _publicSocket(publicSocket), _localSocket(localSocket), _symmetricSocket(), - _activeSocket(NULL) + _activeSocket(NULL), + _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), + _lastHeardMicrostamp(usecTimestampNow()) { } diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 052040933b..dd32666b62 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -41,6 +41,12 @@ public: void activateLocalSocket(); void activateSymmetricSocket(); + quint64 getWakeTimestamp() const { return _wakeTimestamp; } + void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } + + quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } + void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } + friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); protected: @@ -50,6 +56,9 @@ protected: HifiSockAddr _localSocket; HifiSockAddr _symmetricSocket; HifiSockAddr* _activeSocket; + + quint64 _wakeTimestamp; + quint64 _lastHeardMicrostamp; }; QDebug operator<<(QDebug debug, const NetworkPeer &peer); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 942f911f23..a25350c3f3 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -16,7 +16,6 @@ #include "SharedUtil.h" #include -#include #include const QString UNKNOWN_NodeType_t_NAME = "Unknown"; @@ -46,8 +45,6 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : NetworkPeer(uuid, publicSocket, localSocket), _type(type), - _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), - _lastHeardMicrostamp(usecTimestampNow()), _connectionSecret(), _bytesReceivedMovingAverage(NULL), _linkedData(NULL), diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index f300499add..238331947c 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -56,12 +56,6 @@ public: char getType() const { return _type; } void setType(char type) { _type = type; } - - quint64 getWakeTimestamp() const { return _wakeTimestamp; } - void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } - - quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } - void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } const QUuid& getConnectionSecret() const { return _connectionSecret; } void setConnectionSecret(const QUuid& connectionSecret) { _connectionSecret = connectionSecret; } @@ -92,8 +86,7 @@ private: Node& operator=(Node otherNode); NodeType_t _type; - quint64 _wakeTimestamp; - quint64 _lastHeardMicrostamp; + QUuid _connectionSecret; SimpleMovingAverage* _bytesReceivedMovingAverage; From 956c212db2fbfe6fce454534806533cb8b787856 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 15:24:23 -0700 Subject: [PATCH 16/44] manage sets of potential connections in ice server --- ice-server/src/IceServer.cpp | 67 ++++++++++++++++++++---- ice-server/src/IceServer.h | 6 ++- libraries/networking/src/NetworkPeer.cpp | 9 ++++ libraries/networking/src/NetworkPeer.h | 2 + 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/ice-server/src/IceServer.cpp b/ice-server/src/IceServer.cpp index be97df37a4..e3db679009 100644 --- a/ice-server/src/IceServer.cpp +++ b/ice-server/src/IceServer.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -22,7 +23,8 @@ const int PEER_SILENCE_THRESHOLD_MSECS = 5 * 1000; IceServer::IceServer(int argc, char* argv[]) : QCoreApplication(argc, argv), _id(QUuid::createUuid()), - _serverSocket() + _serverSocket(), + _activePeers() { // start the ice-server socket qDebug() << "ice-server socket is listening on" << ICE_SERVER_DEFAULT_PORT; @@ -84,24 +86,67 @@ void IceServer::processDatagrams() { QUuid connectRequestID; hearbeatStream >> connectRequestID; + // get the peers asking for connections with this peer + QSet& requestingConnections = _currentConnections[senderUUID]; + if (!connectRequestID.isNull()) { qDebug() << "Peer wants to connect to peer with ID" << uuidStringWithoutCurlyBraces(connectRequestID); - // check if we have that ID - if we do we can respond with their info, otherwise nothing we can do - SharedNetworkPeer matchingConectee = _activePeers.value(connectRequestID); - if (matchingConectee) { - QByteArray heartbeatResponse = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeatResponse, _id); - QDataStream responseStream(&heartbeatResponse, QIODevice::Append); - - responseStream << matchingConectee; - - _serverSocket.writeDatagram(heartbeatResponse, sendingSockAddr.getAddress(), sendingSockAddr.getPort()); - } + // ensure this peer is in the set of current connections for the peer with ID it wants to connect with + _currentConnections[connectRequestID].insert(senderUUID); + + // add the ID of the node they have said they would like to connect to + requestingConnections.insert(connectRequestID); + } + + if (requestingConnections.size() > 0) { + // send a heartbeart response based on the set of connections + qDebug() << "Sending a heartbeat response to" << senderUUID << "who has" << requestingConnections.size() + << "potential connections"; + sendHeartbeatResponse(sendingSockAddr, requestingConnections); } } } } +void IceServer::sendHeartbeatResponse(const HifiSockAddr& destinationSockAddr, QSet& connections) { + QSet::iterator peerID = connections.begin(); + + QByteArray outgoingPacket(MAX_PACKET_SIZE, 0); + int currentPacketSize = populatePacketHeader(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); + + // go through the connections, sending packets containing connection information for those nodes + while (peerID != connections.end()) { + SharedNetworkPeer matchingPeer = _activePeers.value(*peerID); + // if this node is inactive we remove it from the set + if (!matchingPeer) { + peerID = connections.erase(peerID); + } else { + // get the byte array for this peer + QByteArray peerBytes = matchingPeer->toByteArray(); + + if (currentPacketSize + peerBytes.size() > MAX_PACKET_SIZE) { + // write the current packet + _serverSocket.writeDatagram(outgoingPacket.data(), currentPacketSize, + destinationSockAddr.getAddress(), destinationSockAddr.getPort()); + + // reset the packet size to our number of header bytes + currentPacketSize = populatePacketHeader(outgoingPacket, PacketTypeIceServerHeartbeatResponse, _id); + } + + // append the current peer bytes + outgoingPacket.insert(currentPacketSize, peerBytes); + currentPacketSize += peerBytes.size(); + + ++peerID; + } + } + + // write the last packet + _serverSocket.writeDatagram(outgoingPacket.data(), currentPacketSize, + destinationSockAddr.getAddress(), destinationSockAddr.getPort()); +} + void IceServer::clearInactivePeers() { NetworkPeerHash::iterator peerItem = _activePeers.begin(); diff --git a/ice-server/src/IceServer.h b/ice-server/src/IceServer.h index 9c4c4242dc..e15bda1211 100644 --- a/ice-server/src/IceServer.h +++ b/ice-server/src/IceServer.h @@ -27,9 +27,13 @@ private slots: void processDatagrams(); void clearInactivePeers(); private: + + void sendHeartbeatResponse(const HifiSockAddr& destinationSockAddr, QSet& connections); + QUuid _id; - NetworkPeerHash _activePeers; QUdpSocket _serverSocket; + NetworkPeerHash _activePeers; + QHash > _currentConnections; }; #endif // hifi_IceServer_h \ No newline at end of file diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 1da6836bf9..79bed4f226 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -70,6 +70,15 @@ void NetworkPeer::activateSymmetricSocket() { _activeSocket = &_symmetricSocket; } +QByteArray NetworkPeer::toByteArray() const { + QByteArray peerByteArray; + + QDataStream peerStream(&peerByteArray, QIODevice::Append); + peerStream << *this; + + return peerByteArray; +} + QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer) { out << peer._uuid; out << peer._publicSocket; diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index dd32666b62..18015bc605 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -47,6 +47,8 @@ public: quint64 getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } void setLastHeardMicrostamp(quint64 lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } + QByteArray toByteArray() const; + friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); protected: From c36774e85da24f3a280d21c7ff582a7f2e20f288 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 16:05:15 -0700 Subject: [PATCH 17/44] handle ice response packet in domain handler --- libraries/networking/src/DomainHandler.cpp | 22 ++++++++ libraries/networking/src/DomainHandler.h | 5 ++ libraries/networking/src/NetworkPeer.cpp | 66 ++++++++++------------ libraries/networking/src/NetworkPeer.h | 23 ++++---- libraries/networking/src/Node.cpp | 46 +++++++++++++++ libraries/networking/src/Node.h | 13 +++++ libraries/networking/src/NodeList.cpp | 2 +- 7 files changed, 127 insertions(+), 50 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index e5c8abb171..2eb11f4922 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -26,6 +26,7 @@ DomainHandler::DomainHandler(QObject* parent) : _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), _iceServerSockAddr(), + _icePeer(), _isConnected(false), _handshakeTimer(NULL), _settingsObject(), @@ -36,8 +37,12 @@ DomainHandler::DomainHandler(QObject* parent) : void DomainHandler::clearConnectionInfo() { _uuid = QUuid(); + _iceServerSockAddr = HifiSockAddr(); + _icePeer = NetworkPeer(); + _isConnected = false; + emit disconnectedFromDomain(); if (_handshakeTimer) { @@ -231,3 +236,20 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement // initializeDTLSSession(); } + +void DomainHandler::processICEResponsePacket(const QByteArray& icePacket) { + QDataStream iceResponseStream(icePacket); + iceResponseStream.skipRawData(numBytesForPacketHeader(icePacket)); + + NetworkPeer packetPeer; + iceResponseStream >> packetPeer; + + if (packetPeer.getUUID() != _uuid) { + qDebug() << "Received a network peer with ID that does not match current domain. Will not attempt connection."; + } else { + qDebug() << "Received network peer object for domain -" << packetPeer; + _icePeer = packetPeer; + + emit requestICEConnectionAttempt(); + } +} diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index ffd288d93d..4c58a2b615 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -20,6 +20,7 @@ #include #include "HifiSockAddr.h" +#include "NetworkPeer.h" const QString DEFAULT_DOMAIN_HOSTNAME = "sandbox.highfidelity.io"; @@ -55,6 +56,7 @@ public: void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } bool requiresICE() const { return !_iceServerSockAddr.isNull(); } + NetworkPeer& getICEPeer() { return _icePeer; } bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); @@ -64,6 +66,7 @@ public: const QJsonObject& getSettingsObject() const { return _settingsObject; } void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); + void processICEResponsePacket(const QByteArray& icePacket); void softReset(); public slots: @@ -77,6 +80,7 @@ signals: void hostnameChanged(const QString& hostname); void connectedToDomain(const QString& hostname); void disconnectedFromDomain(); + void requestICEConnectionAttempt(); void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); @@ -89,6 +93,7 @@ private: HifiSockAddr _sockAddr; QUuid _assignmentUUID; HifiSockAddr _iceServerSockAddr; + NetworkPeer _icePeer; bool _isConnected; QTimer* _handshakeTimer; QJsonObject _settingsObject; diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 79bed4f226..1dda9eb7b1 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -16,58 +16,50 @@ #include "NetworkPeer.h" -NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : - _uuid(uuid), - _publicSocket(publicSocket), - _localSocket(localSocket), - _symmetricSocket(), - _activeSocket(NULL), +NetworkPeer::NetworkPeer() : + _uuid(), + _publicSocket(), + _localSocket(), _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), _lastHeardMicrostamp(usecTimestampNow()) { } -void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) { - if (_activeSocket == &_publicSocket) { - // if the active socket was the public socket then reset it to NULL - _activeSocket = NULL; - } +NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : + _uuid(uuid), + _publicSocket(publicSocket), + _localSocket(localSocket), + _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), + _lastHeardMicrostamp(usecTimestampNow()) +{ - _publicSocket = publicSocket; } -void NetworkPeer::setLocalSocket(const HifiSockAddr& localSocket) { - if (_activeSocket == &_localSocket) { - // if the active socket was the local socket then reset it to NULL - _activeSocket = NULL; - } +NetworkPeer::NetworkPeer(const NetworkPeer& otherPeer) { - _localSocket = localSocket; -} - -void NetworkPeer::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { - if (_activeSocket == &_symmetricSocket) { - // if the active socket was the symmetric socket then reset it to NULL - _activeSocket = NULL; - } + _uuid = otherPeer._uuid; + _publicSocket = otherPeer._publicSocket; + _localSocket = otherPeer._localSocket; - _symmetricSocket = symmetricSocket; + _wakeTimestamp = otherPeer._wakeTimestamp; + _lastHeardMicrostamp = otherPeer._lastHeardMicrostamp; } -void NetworkPeer::activateLocalSocket() { - qDebug() << "Activating local socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); - _activeSocket = &_localSocket; +NetworkPeer& NetworkPeer::operator=(const NetworkPeer& otherPeer) { + NetworkPeer temp(otherPeer); + swap(temp); + return *this; } -void NetworkPeer::activatePublicSocket() { - qDebug() << "Activating public socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); - _activeSocket = &_publicSocket; -} - -void NetworkPeer::activateSymmetricSocket() { - qDebug() << "Activating symmetric socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); - _activeSocket = &_symmetricSocket; +void NetworkPeer::swap(NetworkPeer& otherPeer) { + using std::swap; + + swap(_uuid, otherPeer._uuid); + swap(_publicSocket, otherPeer._publicSocket); + swap(_localSocket, otherPeer._localSocket); + swap(_wakeTimestamp, otherPeer._wakeTimestamp); + swap(_lastHeardMicrostamp, otherPeer._lastHeardMicrostamp); } QByteArray NetworkPeer::toByteArray() const { diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 18015bc605..c590c49cf3 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -23,23 +23,22 @@ const int ICE_HEARBEAT_INTERVAL_MSECS = 2 * 1000; class NetworkPeer : public QObject { public: + NetworkPeer(); NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); + // privatize copy and assignment operator to disallow peer copying + NetworkPeer(const NetworkPeer &otherPeer); + NetworkPeer& operator=(const NetworkPeer& otherPeer); + const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } + void reset(); + const HifiSockAddr& getPublicSocket() const { return _publicSocket; } - void setPublicSocket(const HifiSockAddr& publicSocket); + virtual void setPublicSocket(const HifiSockAddr& publicSocket) { _publicSocket = publicSocket; } const HifiSockAddr& getLocalSocket() const { return _localSocket; } - void setLocalSocket(const HifiSockAddr& localSocket); - const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; } - void setSymmetricSocket(const HifiSockAddr& symmetricSocket); - - const HifiSockAddr* getActiveSocket() const { return _activeSocket; } - - void activatePublicSocket(); - void activateLocalSocket(); - void activateSymmetricSocket(); + virtual void setLocalSocket(const HifiSockAddr& localSocket) { _localSocket = localSocket; } quint64 getWakeTimestamp() const { return _wakeTimestamp; } void setWakeTimestamp(quint64 wakeTimestamp) { _wakeTimestamp = wakeTimestamp; } @@ -56,11 +55,11 @@ protected: HifiSockAddr _publicSocket; HifiSockAddr _localSocket; - HifiSockAddr _symmetricSocket; - HifiSockAddr* _activeSocket; quint64 _wakeTimestamp; quint64 _lastHeardMicrostamp; +private: + void swap(NetworkPeer& otherPeer); }; QDebug operator<<(QDebug debug, const NetworkPeer &peer); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index a25350c3f3..20461cb754 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "Node.h" #include "SharedUtil.h" @@ -45,6 +47,8 @@ const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { Node::Node(const QUuid& uuid, NodeType_t type, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket) : NetworkPeer(uuid, publicSocket, localSocket), _type(type), + _activeSocket(NULL), + _symmetricSocket(), _connectionSecret(), _bytesReceivedMovingAverage(NULL), _linkedData(NULL), @@ -90,6 +94,48 @@ void Node::updateClockSkewUsec(int clockSkewSample) { _clockSkewUsec = (int)_clockSkewMovingPercentile.getValueAtPercentile(); } +void Node::setPublicSocket(const HifiSockAddr& publicSocket) { + if (_activeSocket == &_publicSocket) { + // if the active socket was the public socket then reset it to NULL + _activeSocket = NULL; + } + + _publicSocket = publicSocket; +} + +void Node::setLocalSocket(const HifiSockAddr& localSocket) { + if (_activeSocket == &_localSocket) { + // if the active socket was the local socket then reset it to NULL + _activeSocket = NULL; + } + + _localSocket = localSocket; +} + +void Node::setSymmetricSocket(const HifiSockAddr& symmetricSocket) { + if (_activeSocket == &_symmetricSocket) { + // if the active socket was the symmetric socket then reset it to NULL + _activeSocket = NULL; + } + + _symmetricSocket = symmetricSocket; +} + +void Node::activateLocalSocket() { + qDebug() << "Activating local socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_localSocket; +} + +void Node::activatePublicSocket() { + qDebug() << "Activating public socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_publicSocket; +} + +void Node::activateSymmetricSocket() { + qDebug() << "Activating symmetric socket for network peer with ID" << uuidStringWithoutCurlyBraces(_uuid); + _activeSocket = &_symmetricSocket; +} + QDataStream& operator<<(QDataStream& out, const Node& node) { out << node._type; out << node._uuid; diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 238331947c..994ddd3bec 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -77,6 +77,17 @@ public: void updateClockSkewUsec(int clockSkewSample); QMutex& getMutex() { return _mutex; } + virtual void setPublicSocket(const HifiSockAddr& publicSocket); + virtual void setLocalSocket(const HifiSockAddr& localSocket); + const HifiSockAddr& getSymmetricSocket() const { return _symmetricSocket; } + virtual void setSymmetricSocket(const HifiSockAddr& symmetricSocket); + + const HifiSockAddr* getActiveSocket() const { return _activeSocket; } + + void activatePublicSocket(); + void activateLocalSocket(); + void activateSymmetricSocket(); + friend QDataStream& operator<<(QDataStream& out, const Node& node); friend QDataStream& operator>>(QDataStream& in, Node& node); @@ -87,6 +98,8 @@ private: NodeType_t _type; + HifiSockAddr* _activeSocket; + HifiSockAddr _symmetricSocket; QUuid _connectionSecret; SimpleMovingAverage* _bytesReceivedMovingAverage; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index a1b6011032..0333b4fb34 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -124,7 +124,7 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr break; } case PacketTypeIceServerHeartbeatResponse: { - + _domainHandler.processICEResponsePacket(packet); break; } case PacketTypePing: { From c7aaf0ce4ac6d117bd98a607483f4368c72720bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 16:24:46 -0700 Subject: [PATCH 18/44] handle ping out from node requiring ice connection to domain --- domain-server/src/DomainServer.cpp | 6 +++ libraries/networking/src/DomainHandler.cpp | 2 +- libraries/networking/src/DomainHandler.h | 3 +- libraries/networking/src/LimitedNodeList.cpp | 34 ++++++++++++- libraries/networking/src/LimitedNodeList.h | 14 +++++- libraries/networking/src/NetworkPeer.h | 2 + libraries/networking/src/NodeList.cpp | 53 ++++++++------------ libraries/networking/src/NodeList.h | 13 +---- 8 files changed, 77 insertions(+), 50 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 78baf803fa..28765e0620 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1028,6 +1028,12 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS case PacketTypeStunResponse: nodeList->processSTUNResponse(receivedPacket); break; + case PacketTypePing: { + QByteArray pingReplyPacket = nodeList->constructPingReplyPacket(receivedPacket); + nodeList->writeUnverifiedDatagram(pingReplyPacket, senderSockAddr); + + break; + } default: break; } diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 2eb11f4922..d4da00db2c 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -135,7 +135,7 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, // re-set the domain info to connect to new domain hardReset(); - _uuid = id; + setUUID(id); _iceServerSockAddr = HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid) diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 4c58a2b615..f490fc5e65 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -56,7 +56,8 @@ public: void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } bool requiresICE() const { return !_iceServerSockAddr.isNull(); } - NetworkPeer& getICEPeer() { return _icePeer; } + const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } + const NetworkPeer& getICEPeer() const { return _icePeer; } bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b32fbe3b37..4d603e6929 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -459,6 +459,35 @@ unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeS return n; } +QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType) { + QByteArray pingPacket = byteArrayWithPopulatedHeader(PacketTypePing); + + QDataStream packetStream(&pingPacket, QIODevice::Append); + + packetStream << pingType; + packetStream << usecTimestampNow(); + + return pingPacket; +} + +QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket) { + QDataStream pingPacketStream(pingPacket); + pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); + + PingType_t typeFromOriginalPing; + pingPacketStream >> typeFromOriginalPing; + + quint64 timeFromOriginalPing; + pingPacketStream >> timeFromOriginalPing; + + QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); + QDataStream packetStream(&replyPacket, QIODevice::Append); + + packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); + + return replyPacket; +} + SharedNodePointer LimitedNodeList::soloNodeOfType(char nodeType) { if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES))) { @@ -619,7 +648,8 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { return false; } -void LimitedNodeList::sendHeartbeatToIceServer(QUuid headerID, const QUuid& connectionRequestID) { +void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, + QUuid headerID, const QUuid& connectionRequestID) { if (headerID.isNull()) { headerID = _sessionUUID; @@ -637,5 +667,5 @@ void LimitedNodeList::sendHeartbeatToIceServer(QUuid headerID, const QUuid& conn << uuidStringWithoutCurlyBraces(connectionRequestID); } - _nodeSocket.writeDatagram(iceRequestByteArray, QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); + writeUnverifiedDatagram(iceRequestByteArray, iceServerSockAddr); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 1e97ba8190..6f6c4539b8 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -52,6 +52,14 @@ typedef QSharedPointer SharedNodePointer; typedef QHash NodeHash; Q_DECLARE_METATYPE(SharedNodePointer) +typedef quint8 PingType_t; +namespace PingType { + const PingType_t Agnostic = 0; + const PingType_t Local = 1; + const PingType_t Public = 2; + const PingType_t Symmetric = 3; +} + class LimitedNodeList : public QObject { Q_OBJECT public: @@ -104,10 +112,14 @@ public: void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void resetPacketStats(); + QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic); + QByteArray constructPingReplyPacket(const QByteArray& pingPacket); + virtual void sendSTUNRequest(); virtual bool processSTUNResponse(const QByteArray& packet); - void sendHeartbeatToIceServer(QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid()); + void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, + QUuid headerID = QUuid(), const QUuid& connectRequestID = QUuid()); public slots: void reset(); void eraseAllNodes(); diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index c590c49cf3..1e9b61d9f2 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -30,6 +30,8 @@ public: NetworkPeer(const NetworkPeer &otherPeer); NetworkPeer& operator=(const NetworkPeer& otherPeer); + bool isNull() const { return _uuid.isNull(); } + const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0333b4fb34..25c86a41b8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -64,6 +64,9 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // clear our NodeList when the domain changes connect(&_domainHandler, &DomainHandler::hostnameChanged, this, &NodeList::reset); + // handle ICE signal from DS so connection is attempted immediately + connect(&_domainHandler, &DomainHandler::requestICEConnectionAttempt, this, &NodeList::handleICEConnectionToDomainServer); + // clear our NodeList when logout is requested connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset); } @@ -158,6 +161,8 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr // set the ping time for this node for stat collection timePingReply(packet, sendingNode); + } else if (uuidFromPacketHeader(packet) == _domainHandler.getUUID()) { + qDebug() << "RECEIVED A REPLY FROM DOMAIN"; } break; @@ -247,7 +252,7 @@ void NodeList::sendDomainServerCheckIn() { // send a STUN request to figure it out sendSTUNRequest(); } else if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { - sendICERequestForDomainConnection(); + handleICEConnectionToDomainServer(); } else if (!_domainHandler.getIP().isNull()) { bool isUsingDTLS = false; @@ -304,11 +309,22 @@ void NodeList::sendDomainServerCheckIn() { } } -void NodeList::sendICERequestForDomainConnection() { - +void NodeList::handleICEConnectionToDomainServer() { static QUuid iceUUID = QUuid::createUuid(); - LimitedNodeList::sendHeartbeatToIceServer(iceUUID, _domainHandler.getUUID()); + if (_domainHandler.getICEPeer().isNull()) { + LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), iceUUID, _domainHandler.getUUID()); + } else { + qDebug() << "Sending ping packets to establish connectivity with domain-server with ID" + << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); + + // send the ping packet to the local and public sockets for this node + QByteArray localPingPacket = constructPingPacket(PingType::Local); + writeDatagram(localPingPacket, _domainHandler.getICEPeer().getLocalSocket(), iceUUID); + + QByteArray publicPingPacket = constructPingPacket(PingType::Public); + writeDatagram(publicPingPacket, _domainHandler.getICEPeer().getPublicSocket(), iceUUID); + } } int NodeList::processDomainServerList(const QByteArray& packet) { @@ -382,35 +398,6 @@ void NodeList::sendAssignment(Assignment& assignment) { _nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort()); } -QByteArray NodeList::constructPingPacket(PingType_t pingType) { - QByteArray pingPacket = byteArrayWithPopulatedHeader(PacketTypePing); - - QDataStream packetStream(&pingPacket, QIODevice::Append); - - packetStream << pingType; - packetStream << usecTimestampNow(); - - return pingPacket; -} - -QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) { - QDataStream pingPacketStream(pingPacket); - pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); - - PingType_t typeFromOriginalPing; - pingPacketStream >> typeFromOriginalPing; - - quint64 timeFromOriginalPing; - pingPacketStream >> timeFromOriginalPing; - - QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); - QDataStream packetStream(&replyPacket, QIODevice::Append); - - packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); - - return replyPacket; -} - void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { // send the ping packet to the local and public sockets for this node diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index ad0f74e517..c1e2d12319 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -37,14 +37,6 @@ const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; class Assignment; -typedef quint8 PingType_t; -namespace PingType { - const PingType_t Agnostic = 0; - const PingType_t Local = 1; - const PingType_t Public = 2; - const PingType_t Symmetric = 3; -} - class NodeList : public LimitedNodeList { Q_OBJECT public: @@ -69,9 +61,6 @@ public: void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); - - QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic); - QByteArray constructPingReplyPacket(const QByteArray& pingPacket); void pingPunchForInactiveNode(const SharedNodePointer& node); @@ -91,7 +80,7 @@ private: void sendSTUNRequest(); bool processSTUNResponse(const QByteArray& packet); - void sendICERequestForDomainConnection(); + void handleICEConnectionToDomainServer(); void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); From 63877b0756b0ff0f160e36ec966ad42b3eff45a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 16:51:12 -0700 Subject: [PATCH 19/44] handle domain connection via ICE from NodeList --- domain-server/src/DomainServer.cpp | 6 ++++-- libraries/networking/src/DomainHandler.cpp | 13 ++++++++++-- libraries/networking/src/DomainHandler.h | 2 ++ libraries/networking/src/LimitedNodeList.cpp | 9 +++++--- libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/NodeList.cpp | 22 +++++++++++++++----- libraries/networking/src/PacketHeaders.h | 7 +++++-- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 28765e0620..1bbe61dfcb 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -983,8 +983,10 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, domainUpdateJSON.toUtf8()); } +const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr(QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); + void DomainServer::sendHearbeatToIceServer() { - LimitedNodeList::getInstance()->sendHeartbeatToIceServer(); + LimitedNodeList::getInstance()->sendHeartbeatToIceServer(ICE_SERVER_SOCK_ADDR); } void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { @@ -1028,7 +1030,7 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS case PacketTypeStunResponse: nodeList->processSTUNResponse(receivedPacket); break; - case PacketTypePing: { + case PacketTypeUnverifiedPing: { QByteArray pingReplyPacket = nodeList->constructPingReplyPacket(receivedPacket); nodeList->writeUnverifiedDatagram(pingReplyPacket, senderSockAddr); diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index d4da00db2c..b438d9bdf4 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -138,11 +138,20 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, setUUID(id); _iceServerSockAddr = HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); - qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid) - << "- ICE required via ice server at" << iceServerHostname; + qDebug() << "ICE required to connect to domain via ice server at" << iceServerHostname; } } +void DomainHandler::activateICELocalSocket() { + _sockAddr = _icePeer.getLocalSocket(); + _hostname = _sockAddr.getAddress().toString(); +} + +void DomainHandler::activateICEPublicSocket() { + _sockAddr = _icePeer.getPublicSocket(); + _hostname = _sockAddr.getAddress().toString(); +} + void DomainHandler::completedHostnameLookup(const QHostInfo& hostInfo) { for (int i = 0; i < hostInfo.addresses().size(); i++) { if (hostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) { diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index f490fc5e65..9215bd004d 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -58,6 +58,8 @@ public: bool requiresICE() const { return !_iceServerSockAddr.isNull(); } const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } const NetworkPeer& getICEPeer() const { return _icePeer; } + void activateICELocalSocket(); + void activateICEPublicSocket(); bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 4d603e6929..ddcfcd7d08 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -459,8 +459,8 @@ unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeS return n; } -QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType) { - QByteArray pingPacket = byteArrayWithPopulatedHeader(PacketTypePing); +QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVerified) { + QByteArray pingPacket = byteArrayWithPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing); QDataStream packetStream(&pingPacket, QIODevice::Append); @@ -480,7 +480,10 @@ QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacke quint64 timeFromOriginalPing; pingPacketStream >> timeFromOriginalPing; - QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); + PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing) + ? PacketTypePingReply : PacketTypeUnverifiedPingReply; + + QByteArray replyPacket = byteArrayWithPopulatedHeader(replyType); QDataStream packetStream(&replyPacket, QIODevice::Append); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 6f6c4539b8..dfba7f6c72 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -112,7 +112,7 @@ public: void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void resetPacketStats(); - QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic); + QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true); QByteArray constructPingReplyPacket(const QByteArray& pingPacket); virtual void sendSTUNRequest(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 25c86a41b8..846b5395a8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -161,12 +161,24 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr // set the ping time for this node for stat collection timePingReply(packet, sendingNode); - } else if (uuidFromPacketHeader(packet) == _domainHandler.getUUID()) { - qDebug() << "RECEIVED A REPLY FROM DOMAIN"; } break; } + case PacketTypeUnverifiedPingReply: { + qDebug() << "Received reply from domain-server on" << senderSockAddr; + + // for now we're unsafely assuming this came back from the domain + if (senderSockAddr == _domainHandler.getICEPeer().getLocalSocket()) { + qDebug() << "Connecting to domain using local socket"; + _domainHandler.activateICELocalSocket(); + } else if (senderSockAddr == _domainHandler.getICEPeer().getPublicSocket()) { + qDebug() << "Conecting to domain using public socket"; + _domainHandler.activateICEPublicSocket(); + } else { + qDebug() << "Reply does not match either local or public socket for domain. Will not connect."; + } + } case PacketTypeStunResponse: { // a STUN packet begins with 00, we've checked the second zero with packetVersionMatch // pass it along so it can be processed into our public address and port @@ -251,7 +263,7 @@ void NodeList::sendDomainServerCheckIn() { // we don't know our public socket and we need to send it to the domain server // send a STUN request to figure it out sendSTUNRequest(); - } else if (!_domainHandler.isConnected() && _domainHandler.requiresICE()) { + } else if (_domainHandler.getIP().isNull() && _domainHandler.requiresICE()) { handleICEConnectionToDomainServer(); } else if (!_domainHandler.getIP().isNull()) { @@ -319,10 +331,10 @@ void NodeList::handleICEConnectionToDomainServer() { << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); // send the ping packet to the local and public sockets for this node - QByteArray localPingPacket = constructPingPacket(PingType::Local); + QByteArray localPingPacket = constructPingPacket(PingType::Local, false); writeDatagram(localPingPacket, _domainHandler.getICEPeer().getLocalSocket(), iceUUID); - QByteArray publicPingPacket = constructPingPacket(PingType::Public); + QByteArray publicPingPacket = constructPingPacket(PingType::Public, false); writeDatagram(publicPingPacket, _domainHandler.getICEPeer().getPublicSocket(), iceUUID); } } diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index dd1707521c..2d298d253d 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -72,7 +72,9 @@ enum PacketType { PacketTypeEntityEditNack, // 48 PacketTypeSignedTransactionPayment, PacketTypeIceServerHeartbeat, - PacketTypeIceServerHeartbeatResponse + PacketTypeIceServerHeartbeatResponse, + PacketTypeUnverifiedPing, + PacketTypeUnverifiedPingReply }; typedef char PacketVersion; @@ -83,7 +85,8 @@ const QSet NON_VERIFIED_PACKETS = QSet() << PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse << PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeEntityQuery << PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeParticleEditNack << PacketTypeEntityEditNack - << PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse; + << PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse + << PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply; const int NUM_BYTES_MD5_HASH = 16; const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID; From 0d4ef4aaca44c61e2b6b76ad00c809b90fbc139b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 17:18:05 -0700 Subject: [PATCH 20/44] ping connecting ICE peers from domain-server --- domain-server/src/DomainServer.cpp | 46 ++++++++++++++++++++++++++- domain-server/src/DomainServer.h | 6 ++++ libraries/networking/src/NodeList.cpp | 6 ++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 1bbe61dfcb..c0daa94c77 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -354,7 +354,7 @@ void DomainServer::setupAutomaticNetworking() { // setup a timer to heartbeat with the ice-server every so often QTimer* iceHeartbeatTimer = new QTimer(this); - connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHearbeatToIceServer); + connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates); iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); // call our sendHeartbeaToIceServer immediately anytime a public address changes @@ -985,10 +985,51 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr(QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); +void DomainServer::performICEUpdates() { + sendHearbeatToIceServer(); + sendICEPingPackets(); +} + void DomainServer::sendHearbeatToIceServer() { LimitedNodeList::getInstance()->sendHeartbeatToIceServer(ICE_SERVER_SOCK_ADDR); } +void DomainServer::sendICEPingPackets() { + LimitedNodeList* nodeList = LimitedNodeList::getInstance(); + + foreach(const NetworkPeer& peer, _connectingICEPeers) { + // send ping packets to this peer's interfaces + qDebug() << "Sending ping packets to establish connectivity with ICE peer with ID" + << peer.getUUID(); + + // send the ping packet to the local and public sockets for this node + QByteArray localPingPacket = nodeList->constructPingPacket(PingType::Local, false); + nodeList->writeUnverifiedDatagram(localPingPacket, peer.getLocalSocket()); + + QByteArray publicPingPacket = nodeList->constructPingPacket(PingType::Public, false); + nodeList->writeUnverifiedDatagram(publicPingPacket, peer.getPublicSocket()); + } +} + +void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { + // loop through the packet and pull out network peers + // any peer we don't have we add to the hash, otherwise we update + QDataStream iceResponseStream(packet); + iceResponseStream.skipRawData(numBytesForPacketHeader(packet)); + + NetworkPeer receivedPeer; + + while (!iceResponseStream.atEnd()) { + iceResponseStream >> receivedPeer; + + if (!_connectingICEPeers.contains(receivedPeer.getUUID())) { + qDebug() << "New peer requesting connection being added to hash -" << receivedPeer; + } + + _connectingICEPeers[receivedPeer.getUUID()] = receivedPeer; + } +} + void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); @@ -1036,6 +1077,9 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS break; } + case PacketTypeIceServerHeartbeatResponse: + processICEHeartbeatResponse(receivedPacket); + break; default: break; } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index d5e38acf89..88da561f63 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -64,7 +64,9 @@ private slots: void requestCurrentPublicSocketViaSTUN(); void performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr); + void performICEUpdates(); void sendHearbeatToIceServer(); + void sendICEPingPackets(); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); bool optionallySetupOAuth(); @@ -74,6 +76,7 @@ private: void setupAutomaticNetworking(); void updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress = QString()); + void processICEHeartbeatResponse(const QByteArray& packet); void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); @@ -135,6 +138,9 @@ private: HifiSockAddr _localSockAddr; + QHash _connectingICEPeers; + QHash _connectedICEPeers; + DomainServerSettingsManager _settingsManager; }; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 846b5395a8..395a3d01c9 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -165,6 +165,12 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr break; } + case PacketTypeUnverifiedPing: { + // send back a reply + QByteArray replyPacket = constructPingReplyPacket(packet); + writeUnverifiedDatagram(replyPacket, senderSockAddr); + break; + } case PacketTypeUnverifiedPingReply: { qDebug() << "Received reply from domain-server on" << senderSockAddr; From 15cc08da9705193981d4f27c599358b9826b3940 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 17:21:07 -0700 Subject: [PATCH 21/44] initial handling of ping replies in domain-server --- domain-server/src/DomainServer.cpp | 8 ++++++++ domain-server/src/DomainServer.h | 1 + 2 files changed, 9 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c0daa94c77..b0fdb61ed5 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1030,6 +1030,10 @@ void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { } } +void DomainServer::processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr) { + qDebug() << "looking for a node with ID" << uuidFromPacketHeader(packet) << "in connecting hash"; +} + void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); @@ -1077,6 +1081,10 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS break; } + case PacketTypeUnverifiedPingReply: { + processICEPingReply(receivedPacket, senderSockAddr); + break; + } case PacketTypeIceServerHeartbeatResponse: processICEHeartbeatResponse(receivedPacket); break; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 88da561f63..9f668981f0 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -76,6 +76,7 @@ private: void setupAutomaticNetworking(); void updateNetworkingInfoWithDataServer(const QString& newSetting, const QString& networkAddress = QString()); + void processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr); void processICEHeartbeatResponse(const QByteArray& packet); void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); From 5786d828a0fffef091057dc64fbd50722330b062 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 2 Oct 2014 17:30:48 -0700 Subject: [PATCH 22/44] pass ICE client ID through to domain-server for identification --- libraries/networking/src/DomainHandler.cpp | 4 ++++ libraries/networking/src/DomainHandler.h | 3 +++ libraries/networking/src/LimitedNodeList.cpp | 9 +++++---- libraries/networking/src/LimitedNodeList.h | 5 +++-- libraries/networking/src/NodeList.cpp | 16 ++++++++-------- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index b438d9bdf4..daa9b6eca6 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -25,6 +25,7 @@ DomainHandler::DomainHandler(QObject* parent) : _uuid(), _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), _assignmentUUID(), + _iceClientID(), _iceServerSockAddr(), _icePeer(), _isConnected(false), @@ -138,6 +139,9 @@ void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, setUUID(id); _iceServerSockAddr = HifiSockAddr(iceServerHostname, ICE_SERVER_DEFAULT_PORT); + // refresh our ICE client UUID to something new + _iceClientID = QUuid::createUuid(); + qDebug() << "ICE required to connect to domain via ice server at" << iceServerHostname; } } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 9215bd004d..b41bbd98aa 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -55,6 +55,8 @@ public: const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } + const QUuid& getICEClientID() const { return _iceClientID; } + bool requiresICE() const { return !_iceServerSockAddr.isNull(); } const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } const NetworkPeer& getICEPeer() const { return _icePeer; } @@ -95,6 +97,7 @@ private: QString _hostname; HifiSockAddr _sockAddr; QUuid _assignmentUUID; + QUuid _iceClientID; HifiSockAddr _iceServerSockAddr; NetworkPeer _icePeer; bool _isConnected; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index ddcfcd7d08..507788009a 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -459,8 +459,9 @@ unsigned LimitedNodeList::broadcastToNodes(const QByteArray& packet, const NodeS return n; } -QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVerified) { - QByteArray pingPacket = byteArrayWithPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing); +QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVerified, const QUuid& packetHeaderID) { + QByteArray pingPacket = byteArrayWithPopulatedHeader(isVerified ? PacketTypePing : PacketTypeUnverifiedPing, + packetHeaderID); QDataStream packetStream(&pingPacket, QIODevice::Append); @@ -470,7 +471,7 @@ QByteArray LimitedNodeList::constructPingPacket(PingType_t pingType, bool isVeri return pingPacket; } -QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket) { +QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacket, const QUuid& packetHeaderID) { QDataStream pingPacketStream(pingPacket); pingPacketStream.skipRawData(numBytesForPacketHeader(pingPacket)); @@ -483,7 +484,7 @@ QByteArray LimitedNodeList::constructPingReplyPacket(const QByteArray& pingPacke PacketType replyType = (packetTypeForPacket(pingPacket) == PacketTypePing) ? PacketTypePingReply : PacketTypeUnverifiedPingReply; - QByteArray replyPacket = byteArrayWithPopulatedHeader(replyType); + QByteArray replyPacket = byteArrayWithPopulatedHeader(replyType, packetHeaderID); QDataStream packetStream(&replyPacket, QIODevice::Append); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index dfba7f6c72..a7ffc7ec28 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -112,8 +112,9 @@ public: void getPacketStats(float &packetsPerSecond, float &bytesPerSecond); void resetPacketStats(); - QByteArray constructPingPacket(PingType_t pingType = PingType::Agnostic, bool isVerified = true); - QByteArray constructPingReplyPacket(const QByteArray& pingPacket); + 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); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 395a3d01c9..da11684ada 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -167,7 +167,7 @@ void NodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteAr } case PacketTypeUnverifiedPing: { // send back a reply - QByteArray replyPacket = constructPingReplyPacket(packet); + QByteArray replyPacket = constructPingReplyPacket(packet, _domainHandler.getICEClientID()); writeUnverifiedDatagram(replyPacket, senderSockAddr); break; } @@ -328,20 +328,20 @@ void NodeList::sendDomainServerCheckIn() { } void NodeList::handleICEConnectionToDomainServer() { - static QUuid iceUUID = QUuid::createUuid(); - if (_domainHandler.getICEPeer().isNull()) { - LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), iceUUID, _domainHandler.getUUID()); + LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), + _domainHandler.getICEClientID(), + _domainHandler.getUUID()); } else { qDebug() << "Sending ping packets to establish connectivity with domain-server with ID" << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); // send the ping packet to the local and public sockets for this node - QByteArray localPingPacket = constructPingPacket(PingType::Local, false); - writeDatagram(localPingPacket, _domainHandler.getICEPeer().getLocalSocket(), iceUUID); + QByteArray localPingPacket = constructPingPacket(PingType::Local, false, _domainHandler.getICEClientID()); + writeUnverifiedDatagram(localPingPacket, _domainHandler.getICEPeer().getLocalSocket()); - QByteArray publicPingPacket = constructPingPacket(PingType::Public, false); - writeDatagram(publicPingPacket, _domainHandler.getICEPeer().getPublicSocket(), iceUUID); + QByteArray publicPingPacket = constructPingPacket(PingType::Public, false, _domainHandler.getICEClientID()); + writeUnverifiedDatagram(publicPingPacket, _domainHandler.getICEPeer().getPublicSocket()); } } From 49d081088a2727b8f6898c64a5675e0ab9835903 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 08:58:03 -0700 Subject: [PATCH 23/44] mode nodes to connected hash upon ping reply receipt --- domain-server/src/DomainServer.cpp | 28 +++++++++++++++++++++++---- libraries/networking/src/NodeList.cpp | 19 ++++++++++++------ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b0fdb61ed5..13490b3c7b 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -581,9 +581,17 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock if ((!isAssignment && !STATICALLY_ASSIGNED_NODES.contains(nodeType)) || (isAssignment && matchingQueuedAssignment)) { // this was either not a static assignment or it was and we had a matching one in the queue + + QUuid nodeUUID; - // create a new session UUID for this node - QUuid nodeUUID = QUuid::createUuid(); + if (_connectingICEPeers.contains(packetUUID) || _connectedICEPeers.contains(packetUUID)) { + // this user negotiated a connection with us via ICE, so re-use their ICE client ID + nodeUUID = packetUUID; + } else { + // we got a packetUUID we didn't recognize, just add the node + nodeUUID = QUuid::createUuid(); + } + SharedNodePointer newNode = LimitedNodeList::getInstance()->addOrUpdateNode(nodeUUID, nodeType, publicSockAddr, localSockAddr); @@ -1022,7 +1030,7 @@ void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { while (!iceResponseStream.atEnd()) { iceResponseStream >> receivedPeer; - if (!_connectingICEPeers.contains(receivedPeer.getUUID())) { + if (!_connectingICEPeers.contains(receivedPeer.getUUID()) && _connectedICEPeers.contains(receivedPeer.getUUID())) { qDebug() << "New peer requesting connection being added to hash -" << receivedPeer; } @@ -1031,7 +1039,19 @@ void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { } void DomainServer::processICEPingReply(const QByteArray& packet, const HifiSockAddr& senderSockAddr) { - qDebug() << "looking for a node with ID" << uuidFromPacketHeader(packet) << "in connecting hash"; + QUuid nodeUUID = uuidFromPacketHeader(packet); + NetworkPeer sendingPeer = _connectingICEPeers.take(nodeUUID); + + if (!sendingPeer.isNull()) { + // we had this NetworkPeer in our connecting list - add the right sock addr to our connected list + if (senderSockAddr == sendingPeer.getLocalSocket()) { + qDebug() << "Activating local socket for communication with network peer -" << sendingPeer; + _connectedICEPeers.insert(nodeUUID, sendingPeer.getLocalSocket()); + } else if (senderSockAddr == sendingPeer.getPublicSocket()) { + qDebug() << "Activating public socket for communication with network peer -" << sendingPeer; + _connectedICEPeers.insert(nodeUUID, sendingPeer.getPublicSocket()); + } + } } void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index da11684ada..de586f3d36 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -276,7 +276,7 @@ void NodeList::sendDomainServerCheckIn() { bool isUsingDTLS = false; PacketType domainPacketType = !_domainHandler.isConnected() - ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; + ? PacketTypeDomainConnectRequest : PacketTypeDomainListRequest; if (!_domainHandler.isConnected()) { qDebug() << "Sending connect request to domain-server at" << _domainHandler.getHostname(); @@ -285,10 +285,17 @@ void NodeList::sendDomainServerCheckIn() { // construct the DS check in packet QUuid packetUUID = _sessionUUID; - if (!_domainHandler.getAssignmentUUID().isNull() && domainPacketType == PacketTypeDomainConnectRequest) { - // this is a connect request and we're an assigned node - // so set our packetUUID as the assignment UUID - packetUUID = _domainHandler.getAssignmentUUID(); + if (domainPacketType == PacketTypeDomainConnectRequest) { + if (!_domainHandler.getAssignmentUUID().isNull()) { + // this is a connect request and we're an assigned node + // so set our packetUUID as the assignment UUID + packetUUID = _domainHandler.getAssignmentUUID(); + } else if (_domainHandler.requiresICE()) { + // this is a connect request and we're an interface client + // that used ice to discover the DS + // so send our ICE client UUID with the connect request + packetUUID = _domainHandler.getICEClientID(); + } } QByteArray domainServerPacket = byteArrayWithPopulatedHeader(domainPacketType, packetUUID); @@ -336,7 +343,7 @@ void NodeList::handleICEConnectionToDomainServer() { qDebug() << "Sending ping packets to establish connectivity with domain-server with ID" << uuidStringWithoutCurlyBraces(_domainHandler.getUUID()); - // send the ping packet to the local and public sockets for this node + // send the ping packet to the local and public sockets for this nodfe QByteArray localPingPacket = constructPingPacket(PingType::Local, false, _domainHandler.getICEClientID()); writeUnverifiedDatagram(localPingPacket, _domainHandler.getICEPeer().getLocalSocket()); From 1a1ae43bc75e20f73da7ad0f67f8a6c6c7cd4bc9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:02:18 -0700 Subject: [PATCH 24/44] send back to the network peer on established sock addr if it exists --- domain-server/src/DomainServer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 13490b3c7b..2f74159e25 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -708,6 +708,13 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); LimitedNodeList* nodeList = LimitedNodeList::getInstance(); + + // if we've established a connection via ICE with this peer, use that socket + // otherwise just try to reply back to them on their sending socket (although that may not work) + HifiSockAddr destinationSockAddr = _connectedICEPeers.value(node->getUUID()); + if (destinationSockAddr.isNull()) { + destinationSockAddr = senderSockAddr; + } if (nodeInterestList.size() > 0) { @@ -1811,6 +1818,10 @@ void DomainServer::nodeAdded(SharedNodePointer node) { } void DomainServer::nodeKilled(SharedNodePointer node) { + + // remove this node from the connecting / connected ICE lists (if they exist) + _connectingICEPeers.remove(node->getUUID()); + _connectedICEPeers.remove(node->getUUID()); DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); From 720f8ecae8be56f5f3261e4a048bf0e1fed87239 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:08:27 -0700 Subject: [PATCH 25/44] handle case where access_token is empty --- domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/NodeList.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2f74159e25..d3a08f7eb7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -258,7 +258,7 @@ bool DomainServer::didSetupAccountManagerWithAccessToken() { if (accessToken.isEmpty()) { const QVariant* accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH); - if (accessTokenVariant->canConvert(QMetaType::QString)) { + if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) { accessToken = accessTokenVariant->toString(); } else { qDebug() << "A domain-server feature that requires authentication is enabled but no access token is present." diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index de586f3d36..7b925fa464 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -336,7 +336,7 @@ void NodeList::sendDomainServerCheckIn() { void NodeList::handleICEConnectionToDomainServer() { if (_domainHandler.getICEPeer().isNull()) { - LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), + LimitedNodeList::sendHeartbeatToIceServer(HifiSockAddr("h.dfu.co", 7337), _domainHandler.getICEClientID(), _domainHandler.getUUID()); } else { From bd68126b195988759e5357fe74d4e4dc7e5caced Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:14:23 -0700 Subject: [PATCH 26/44] fix for values without defaults --- domain-server/src/DomainServerSettingsManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 8d866a318c..f99e0bf734 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -92,7 +92,12 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin } } - return *foundValue; + if (foundValue) { + return *foundValue; + } else { + return QVariant(); + } + } const QString SETTINGS_PATH = "/settings.json"; From 05cf0142e908561fa55d79a8a9d030c4cbf310c9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:19:51 -0700 Subject: [PATCH 27/44] fix for default value search --- domain-server/src/DomainServerSettingsManager.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index f99e0bf734..28b1151f2d 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -76,7 +76,7 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin int dotIndex = keyPath.indexOf('.'); QString groupKey = keyPath.mid(0, dotIndex); - QString settingKey = keyPath.mid(dotIndex); + QString settingKey = keyPath.mid(dotIndex + 1); foreach(const QVariant& group, _descriptionArray.toVariantList()) { QVariantMap groupMap = group.toMap(); @@ -88,16 +88,13 @@ QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QStrin return settingMap[SETTING_DEFAULT_KEY]; } } + + return QVariant(); } } } - if (foundValue) { - return *foundValue; - } else { - return QVariant(); - } - + return QVariant(); } const QString SETTINGS_PATH = "/settings.json"; From 5be067cf11c4f6996a3435821c8913403bc3602a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:31:17 -0700 Subject: [PATCH 28/44] disable automatic networking by default --- domain-server/resources/describe-settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 303ca7805b..5521cf1660 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -17,7 +17,7 @@ "name": "automatic_networking", "label": "Automatic Networking", "help": "This defines how other nodes in the High Fidelity metaverse will be able to reach your domain-server.
If you don't want to deal with any network settings, use full automatic networking.", - "default": "full", + "default": "disabled", "type": "select", "options": [ { From c96e7f72f8ba6020cf12ed2bb7be0c87d73ec0d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:31:38 -0700 Subject: [PATCH 29/44] use the ice server sock addr returned for the domain --- libraries/networking/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 7b925fa464..de586f3d36 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -336,7 +336,7 @@ void NodeList::sendDomainServerCheckIn() { void NodeList::handleICEConnectionToDomainServer() { if (_domainHandler.getICEPeer().isNull()) { - LimitedNodeList::sendHeartbeatToIceServer(HifiSockAddr("h.dfu.co", 7337), + LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), _domainHandler.getICEClientID(), _domainHandler.getUUID()); } else { From 63024663b286c775dfcde99fe036544f41aff6b0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:37:13 -0700 Subject: [PATCH 30/44] don't require settings request for agent nodes --- libraries/networking/src/DomainHandler.cpp | 38 +++++++++++++--------- libraries/networking/src/DomainHandler.h | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index daa9b6eca6..fecbd1457f 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -185,21 +185,29 @@ void DomainHandler::setIsConnected(bool isConnected) { } } -void DomainHandler::requestDomainSettings() const { - if (_settingsObject.isEmpty()) { - // setup the URL required to grab settings JSON - QUrl settingsJSONURL; - settingsJSONURL.setScheme("http"); - settingsJSONURL.setHost(_hostname); - settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); - settingsJSONURL.setPath("/settings.json"); - Assignment::Type assignmentType = Assignment::typeForNodeType(NodeList::getInstance()->getOwnerType()); - settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); - - qDebug() << "Requesting domain-server settings at" << settingsJSONURL.toString(); - - QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); - connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); +void DomainHandler::requestDomainSettings() { + NodeType_t owningNodeType = NodeList::getInstance()->getOwnerType(); + if (owningNodeType == NodeType::Agent) { + // for now the agent nodes don't need any settings - this allows local assignment-clients + // to connect to a domain that is using automatic networking (since we don't have TCP hole punch yet) + _settingsObject = QJsonObject(); + emit settingsReceived(_settingsObject); + } else { + if (_settingsObject.isEmpty()) { + // setup the URL required to grab settings JSON + QUrl settingsJSONURL; + settingsJSONURL.setScheme("http"); + settingsJSONURL.setHost(_hostname); + settingsJSONURL.setPort(DOMAIN_SERVER_HTTP_PORT); + settingsJSONURL.setPath("/settings.json"); + Assignment::Type assignmentType = Assignment::typeForNodeType(NodeList::getInstance()->getOwnerType()); + settingsJSONURL.setQuery(QString("type=%1").arg(assignmentType)); + + qDebug() << "Requesting domain-server settings at" << settingsJSONURL.toString(); + + QNetworkReply* reply = NetworkAccessManager::getInstance().get(QNetworkRequest(settingsJSONURL)); + connect(reply, &QNetworkReply::finished, this, &DomainHandler::settingsRequestFinished); + } } } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index b41bbd98aa..515dd92c12 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -67,7 +67,7 @@ public: void setIsConnected(bool isConnected); bool hasSettings() const { return !_settingsObject.isEmpty(); } - void requestDomainSettings() const; + void requestDomainSettings(); const QJsonObject& getSettingsObject() const { return _settingsObject; } void parseDTLSRequirementPacket(const QByteArray& dtlsRequirementPacket); From d9e0c91e02a278af2a3d409755a22296fe35851b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:45:40 -0700 Subject: [PATCH 31/44] remove a peer in domain-server after max connection attempts --- domain-server/src/DomainServer.cpp | 34 +++++++++++++++++------- libraries/networking/src/NetworkPeer.cpp | 6 +++-- libraries/networking/src/NetworkPeer.h | 7 +++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d3a08f7eb7..365e335d32 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1012,17 +1012,31 @@ void DomainServer::sendHearbeatToIceServer() { void DomainServer::sendICEPingPackets() { LimitedNodeList* nodeList = LimitedNodeList::getInstance(); - foreach(const NetworkPeer& peer, _connectingICEPeers) { - // send ping packets to this peer's interfaces - qDebug() << "Sending ping packets to establish connectivity with ICE peer with ID" - << peer.getUUID(); + QHash::iterator peer = _connectingICEPeers.begin(); + + while (peer != _connectingICEPeers.end()) { - // send the ping packet to the local and public sockets for this node - QByteArray localPingPacket = nodeList->constructPingPacket(PingType::Local, false); - nodeList->writeUnverifiedDatagram(localPingPacket, peer.getLocalSocket()); - - QByteArray publicPingPacket = nodeList->constructPingPacket(PingType::Public, false); - nodeList->writeUnverifiedDatagram(publicPingPacket, peer.getPublicSocket()); + if (peer->getConnectionAttempts() >= MAX_ICE_CONNECTION_ATTEMPTS) { + // we've already tried to connect to this peer enough times + // remove it from our list - if it wants to re-connect it'll come back through ice-server + peer = _connectingICEPeers.erase(peer); + } else { + // send ping packets to this peer's interfaces + qDebug() << "Sending ping packets to establish connectivity with ICE peer with ID" + << peer->getUUID(); + + // send the ping packet to the local and public sockets for this node + QByteArray localPingPacket = nodeList->constructPingPacket(PingType::Local, false); + nodeList->writeUnverifiedDatagram(localPingPacket, peer->getLocalSocket()); + + QByteArray publicPingPacket = nodeList->constructPingPacket(PingType::Public, false); + nodeList->writeUnverifiedDatagram(publicPingPacket, peer->getPublicSocket()); + + peer->incrementConnectionAttempts(); + + // go to next peer in hash + ++peer; + } } } diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 1dda9eb7b1..d458f579c1 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -21,7 +21,8 @@ NetworkPeer::NetworkPeer() : _publicSocket(), _localSocket(), _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), - _lastHeardMicrostamp(usecTimestampNow()) + _lastHeardMicrostamp(usecTimestampNow()), + _connectionAttempts(0) { } @@ -31,7 +32,8 @@ NetworkPeer::NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, co _publicSocket(publicSocket), _localSocket(localSocket), _wakeTimestamp(QDateTime::currentMSecsSinceEpoch()), - _lastHeardMicrostamp(usecTimestampNow()) + _lastHeardMicrostamp(usecTimestampNow()), + _connectionAttempts(0) { } diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 1e9b61d9f2..bb92c54eb8 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -20,6 +20,7 @@ const QString ICE_SERVER_HOSTNAME = "localhost"; const int ICE_SERVER_DEFAULT_PORT = 7337; const int ICE_HEARBEAT_INTERVAL_MSECS = 2 * 1000; +const int MAX_ICE_CONNECTION_ATTEMPTS = 5; class NetworkPeer : public QObject { public: @@ -50,6 +51,10 @@ public: QByteArray toByteArray() const; + int getConnectionAttempts() const { return _connectionAttempts; } + void incrementConnectionAttempts() { ++_connectionAttempts; } + void resetConnectionAttemps() { _connectionAttempts = 0; } + friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); protected: @@ -60,6 +65,8 @@ protected: quint64 _wakeTimestamp; quint64 _lastHeardMicrostamp; + + int _connectionAttempts; private: void swap(NetworkPeer& otherPeer); }; From 55a718083820c60a26794e4249f174f838f80b21 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:47:15 -0700 Subject: [PATCH 32/44] re-send heartbeat to ICE server after max connection attempts --- libraries/networking/src/DomainHandler.h | 2 +- libraries/networking/src/NodeList.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 515dd92c12..34eda7b00d 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -59,7 +59,7 @@ public: bool requiresICE() const { return !_iceServerSockAddr.isNull(); } const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } - const NetworkPeer& getICEPeer() const { return _icePeer; } + NetworkPeer& getICEPeer() const { return _icePeer; } void activateICELocalSocket(); void activateICEPublicSocket(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index de586f3d36..580fdb0641 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -335,7 +335,11 @@ void NodeList::sendDomainServerCheckIn() { } void NodeList::handleICEConnectionToDomainServer() { - if (_domainHandler.getICEPeer().isNull()) { + if (_domainHandler.getICEPeer().isNull() + || _domainHandler.getICEPeer().getConnectionAttempts() >= MAX_ICE_CONNECTION_ATTEMPTS) { + + _domainHandler.getICEPeer().resetConnectionAttemps(); + LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), _domainHandler.getICEClientID(), _domainHandler.getUUID()); @@ -349,6 +353,8 @@ void NodeList::handleICEConnectionToDomainServer() { QByteArray publicPingPacket = constructPingPacket(PingType::Public, false, _domainHandler.getICEClientID()); writeUnverifiedDatagram(publicPingPacket, _domainHandler.getICEPeer().getPublicSocket()); + + _domainHandler.getICEPeer().incrementConnectionAttempts(); } } From cb6e4203925627d6cf21f47be7ad5e42690e2d3c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 09:50:58 -0700 Subject: [PATCH 33/44] fix for peer addition from ice-server --- domain-server/src/DomainServer.cpp | 2 +- libraries/networking/src/DomainHandler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 365e335d32..67e05af2c6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1051,7 +1051,7 @@ void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { while (!iceResponseStream.atEnd()) { iceResponseStream >> receivedPeer; - if (!_connectingICEPeers.contains(receivedPeer.getUUID()) && _connectedICEPeers.contains(receivedPeer.getUUID())) { + if (!_connectingICEPeers.contains(receivedPeer.getUUID()) && !_connectedICEPeers.contains(receivedPeer.getUUID())) { qDebug() << "New peer requesting connection being added to hash -" << receivedPeer; } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 34eda7b00d..e9d7fb1725 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -59,7 +59,7 @@ public: bool requiresICE() const { return !_iceServerSockAddr.isNull(); } const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } - NetworkPeer& getICEPeer() const { return _icePeer; } + NetworkPeer& getICEPeer() { return _icePeer; } void activateICELocalSocket(); void activateICEPublicSocket(); From f27105100a8e9c2c3482e93b275226836b18bbe5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 10:29:02 -0700 Subject: [PATCH 34/44] have AddressManager know its current domain and current path --- interface/src/Application.cpp | 8 ++- interface/src/Application.h | 2 + .../scripting/LocationScriptingInterface.cpp | 4 +- libraries/networking/src/AddressManager.cpp | 55 +++++++++++++++---- libraries/networking/src/AddressManager.h | 16 +++++- 5 files changed, 66 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51b78b6901..802648d247 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -299,6 +299,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : AddressManager& addressManager = AddressManager::getInstance(); + // use our MyAvatar position and quat for address manager path + addressManager.setPositionGetter(getPositionForPath); + addressManager.setOrientationGetter(getOrientationForPath); + // handle domain change signals from AddressManager connect(&addressManager, &AddressManager::possibleDomainChangeRequiredToHostname, this, &Application::changeDomainHostname); @@ -3458,9 +3462,7 @@ void Application::updateLocationInServer() { QJsonObject locationObject; - QString pathString = AddressManager::pathForPositionAndOrientation(_myAvatar->getPosition(), - true, - _myAvatar->getOrientation()); + QString pathString = AddressManager::getInstance().currentPath(); const QString LOCATION_KEY_IN_ROOT = "location"; const QString PATH_KEY_IN_LOCATION = "path"; diff --git a/interface/src/Application.h b/interface/src/Application.h index e50039a20e..ca26cffab8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -140,6 +140,8 @@ class Application : public QApplication { public: static Application* getInstance() { return static_cast(QCoreApplication::instance()); } static QString& resourcesPath(); + static const glm::vec3& getPositionForPath() { return getInstance()->_myAvatar->getPosition(); } + static glm::quat getOrientationForPath() { return getInstance()->_myAvatar->getOrientation(); } Application(int& argc, char** argv, QElapsedTimer &startup_time); ~Application(); diff --git a/interface/src/scripting/LocationScriptingInterface.cpp b/interface/src/scripting/LocationScriptingInterface.cpp index bf529fb593..047b76dab6 100644 --- a/interface/src/scripting/LocationScriptingInterface.cpp +++ b/interface/src/scripting/LocationScriptingInterface.cpp @@ -29,9 +29,7 @@ QString LocationScriptingInterface::getHref() { } QString LocationScriptingInterface::getPathname() { - MyAvatar* applicationAvatar = Application::getInstance()->getAvatar(); - return AddressManager::pathForPositionAndOrientation(applicationAvatar->getPosition(), - true, applicationAvatar->getOrientation()); + return AddressManager::getInstance().currentPath(); } QString LocationScriptingInterface::getHostname() { diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index a78e1e76a4..b1efbd3c6f 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -22,17 +22,36 @@ AddressManager& AddressManager::getInstance() { return sharedInstance; } -QString AddressManager::pathForPositionAndOrientation(const glm::vec3& position, bool hasOrientation, - const glm::quat& orientation) { +AddressManager::AddressManager() : + _currentDomain(), + _positionGetter(NULL), + _orientationGetter(NULL) +{ - QString pathString = "/" + createByteArray(position); +} + +const QString AddressManager::currentPath(bool withOrientation) const { - if (hasOrientation) { - QString orientationString = createByteArray(orientation); - pathString += "/" + orientationString; + if (_positionGetter) { + QString pathString = "/" + createByteArray(_positionGetter()); + + if (withOrientation) { + if (_orientationGetter) { + QString orientationString = createByteArray(_orientationGetter()); + pathString += "/" + orientationString; + } else { + qDebug() << "Cannot add orientation to path without a getter for position." + << "Call AdressManager::setOrientationGetter to pass a function that will return a glm::quat"; + } + + } + + return pathString; + } else { + qDebug() << "Cannot create address path without a getter for position." + << "Call AdressManager::setPositionGetter to pass a function that will return a const glm::vec3&"; + return QString(); } - - return pathString; } const JSONCallbackParameters& AddressManager::apiCallbackParameters() { @@ -134,6 +153,11 @@ void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) { emit possibleDomainChangeRequiredViaICEForID(iceServerAddress, domainID); } + // set our current domain to the name that came back + const QString DOMAIN_NAME_KEY = "name"; + + _currentDomain = domainObject[DOMAIN_NAME_KEY].toString(); + // take the path that came back const QString LOCATION_KEY = "location"; const QString LOCATION_PATH_KEY = "path"; @@ -144,7 +168,7 @@ void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) { } else if (domainObject.contains(LOCATION_KEY)) { returnedPath = domainObject[LOCATION_KEY].toObject()[LOCATION_PATH_KEY].toString(); } - + bool shouldFaceViewpoint = dataObject.contains(ADDRESS_API_ONLINE_KEY); if (!returnedPath.isEmpty()) { @@ -194,16 +218,25 @@ bool AddressManager::handleNetworkAddress(const QString& lookupString) { QRegExp hostnameRegex(HOSTNAME_REGEX_STRING, Qt::CaseInsensitive); if (hostnameRegex.indexIn(lookupString) != -1) { - emit possibleDomainChangeRequiredToHostname(hostnameRegex.cap(0)); + QString domainHostname = hostnameRegex.cap(0); + + emit possibleDomainChangeRequiredToHostname(domainHostname); emit lookupResultsFinished(); + + _currentDomain = domainHostname; + return true; } QRegExp ipAddressRegex(IP_ADDRESS_REGEX_STRING); if (ipAddressRegex.indexIn(lookupString) != -1) { - emit possibleDomainChangeRequiredToHostname(ipAddressRegex.cap(0)); + QString domainIPString = ipAddressRegex.cap(0); + + emit possibleDomainChangeRequiredToHostname(domainIPString); emit lookupResultsFinished(); + + _currentDomain = domainIPString; return true; } diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 128c395cb4..09fd6be55e 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -21,15 +21,21 @@ static const QString HIFI_URL_SCHEME = "hifi"; +typedef const glm::vec3& (*PositionGetter)(); +typedef glm::quat (*OrientationGetter)(); + class AddressManager : public QObject { Q_OBJECT public: static AddressManager& getInstance(); - static QString pathForPositionAndOrientation(const glm::vec3& position, bool hasOrientation = false, - const glm::quat& orientation = glm::quat()); + const QString currentPath(bool withOrientation = true) const; void attemptPlaceNameLookup(const QString& lookupString); + + void setPositionGetter(PositionGetter positionGetter) { _positionGetter = positionGetter; } + void setOrientationGetter(OrientationGetter orientationGetter) { _orientationGetter = orientationGetter; } + public slots: void handleLookupString(const QString& lookupString); @@ -46,6 +52,8 @@ signals: bool hasOrientationChange, const glm::quat& newOrientation, bool shouldFaceLocation); private: + AddressManager(); + const JSONCallbackParameters& apiCallbackParameters(); bool handleUrl(const QUrl& lookupUrl); @@ -53,6 +61,10 @@ private: bool handleNetworkAddress(const QString& lookupString); bool handleRelativeViewpoint(const QString& pathSubsection, bool shouldFace = false); bool handleUsername(const QString& lookupString); + + QString _currentDomain; + PositionGetter _positionGetter; + OrientationGetter _orientationGetter; }; #endif // hifi_AddressManager_h \ No newline at end of file From 96aacab8ab84a0926041d7c63c5b024f37a102b2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 10:42:15 -0700 Subject: [PATCH 35/44] load Address from settings to get back to domain and path --- interface/src/Application.cpp | 13 +++++++++++-- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 2 ++ interface/src/avatar/MyAvatar.cpp | 19 ------------------- libraries/networking/src/AddressManager.cpp | 10 ++++++++++ libraries/networking/src/AddressManager.h | 2 ++ 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 802648d247..e367fe3551 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1799,16 +1799,25 @@ void Application::init() { Menu::getInstance()->loadSettings(); _audio.setReceivedAudioStreamSettings(Menu::getInstance()->getReceivedAudioStreamSettings()); - - qDebug() << "Loaded settings"; // when --url in command line, teleport to location const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY); if (urlIndex != -1) { AddressManager::getInstance().handleLookupString(arguments().value(urlIndex + 1)); + } else { + // check if we have a URL in settings to load to jump back to + // we load this separate from the other settings so we don't double lookup a URL + QSettings* interfaceSettings = lockSettings(); + QUrl addressURL = interfaceSettings->value(SETTINGS_ADDRESS_KEY).toUrl(); + + AddressManager::getInstance().handleLookupString(addressURL.toString()); + + unlockSettings(); } + qDebug() << "Loaded settings"; + #ifdef __APPLE__ if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) { // on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 94af1ad80a..5a24c48bc4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -816,6 +816,8 @@ void Menu::saveSettings(QSettings* settings) { scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); NodeList::getInstance()->saveData(settings); + + settings->setValue(SETTINGS_ADDRESS_KEY, AddressManager::getInstance().currentAddress()); if (lockedSettings) { Application::getInstance()->unlockSettings(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 2402090213..f73f4b02a2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -51,6 +51,8 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; +const QString SETTINGS_ADDRESS_KEY = "address"; + enum FrustumDrawMode { FRUSTUM_DRAW_MODE_ALL, FRUSTUM_DRAW_MODE_VECTORS, diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f7aa8a2bd6..aae1907b76 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -740,16 +740,8 @@ AnimationDetails MyAvatar::getAnimationDetails(const QString& url) { void MyAvatar::saveData(QSettings* settings) { settings->beginGroup("Avatar"); - settings->setValue("bodyYaw", _bodyYaw); - settings->setValue("bodyPitch", _bodyPitch); - settings->setValue("bodyRoll", _bodyRoll); - settings->setValue("headPitch", getHead()->getBasePitch()); - settings->setValue("position_x", _position.x); - settings->setValue("position_y", _position.y); - settings->setValue("position_z", _position.z); - settings->setValue("pupilDilation", getHead()->getPupilDilation()); settings->setValue("leanScale", _leanScale); @@ -800,19 +792,8 @@ void MyAvatar::saveData(QSettings* settings) { void MyAvatar::loadData(QSettings* settings) { settings->beginGroup("Avatar"); - // in case settings is corrupt or missing loadSetting() will check for NaN - _bodyYaw = loadSetting(settings, "bodyYaw", 0.0f); - _bodyPitch = loadSetting(settings, "bodyPitch", 0.0f); - _bodyRoll = loadSetting(settings, "bodyRoll", 0.0f); - getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); - glm::vec3 newPosition; - newPosition.x = loadSetting(settings, "position_x", START_LOCATION.x); - newPosition.y = loadSetting(settings, "position_y", START_LOCATION.y); - newPosition.z = loadSetting(settings, "position_z", START_LOCATION.z); - slamPosition(newPosition); - getHead()->setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f)); _leanScale = loadSetting(settings, "leanScale", 0.05f); diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index b1efbd3c6f..3d7617e17b 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -30,6 +30,16 @@ AddressManager::AddressManager() : } +const QUrl AddressManager::currentAddress() { + QUrl hifiURL; + + hifiURL.setScheme(HIFI_URL_SCHEME); + hifiURL.setHost(_currentDomain); + hifiURL.setPath(currentPath()); + + return hifiURL; +} + const QString AddressManager::currentPath(bool withOrientation) const { if (_positionGetter) { diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 09fd6be55e..a4618655bb 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -29,6 +29,8 @@ class AddressManager : public QObject { public: static AddressManager& getInstance(); + const QUrl currentAddress(); + const QString currentPath(bool withOrientation = true) const; void attemptPlaceNameLookup(const QString& lookupString); From ea0a1a4fb67aaca033d1ebf566fb011eee15676a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 10:46:05 -0700 Subject: [PATCH 36/44] don't store domain hostname, leverage AddressManager only --- interface/src/Application.cpp | 2 +- interface/src/Menu.cpp | 2 -- libraries/networking/src/AddressManager.h | 3 ++- libraries/networking/src/NodeList.cpp | 31 ----------------------- libraries/networking/src/NodeList.h | 3 --- 5 files changed, 3 insertions(+), 38 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e367fe3551..c25081852d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3440,7 +3440,7 @@ void Application::updateWindowTitle(){ QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) "; QString username = AccountManager::getInstance().getAccountInfo().getUsername(); QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) - + nodeList->getDomainHandler().getHostname() + connectionStatus + buildVersion; + + AddressManager::getInstance().getCurrentDomain() + connectionStatus + buildVersion; AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.getAccountInfo().hasBalance()) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5a24c48bc4..80f3b7770e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -754,7 +754,6 @@ void Menu::loadSettings(QSettings* settings) { scanMenuBar(&loadAction, settings); Application::getInstance()->getAvatar()->loadData(settings); Application::getInstance()->updateWindowTitle(); - NodeList::getInstance()->loadData(settings); // notify that a settings has changed connect(&NodeList::getInstance()->getDomainHandler(), &DomainHandler::hostnameChanged, this, &Menu::bumpSettings); @@ -815,7 +814,6 @@ void Menu::saveSettings(QSettings* settings) { scanMenuBar(&saveAction, settings); Application::getInstance()->getAvatar()->saveData(settings); - NodeList::getInstance()->saveData(settings); settings->setValue(SETTINGS_ADDRESS_KEY, AddressManager::getInstance().currentAddress()); diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index a4618655bb..fe6219b3f7 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -30,9 +30,10 @@ public: static AddressManager& getInstance(); const QUrl currentAddress(); - const QString currentPath(bool withOrientation = true) const; + const QString& getCurrentDomain() const { return _currentDomain; } + void attemptPlaceNameLookup(const QString& lookupString); void setPositionGetter(PositionGetter positionGetter) { _positionGetter = positionGetter; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 580fdb0641..50539e1196 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -471,34 +471,3 @@ void NodeList::activateSocketFromNodeCommunication(const QByteArray& packet, con sendingNode->activateSymmetricSocket(); } } - -const QString QSETTINGS_GROUP_NAME = "NodeList"; -const QString DOMAIN_SERVER_SETTING_KEY = "domainServerHostname"; - -void NodeList::loadData(QSettings *settings) { - settings->beginGroup(DOMAIN_SERVER_SETTING_KEY); - - QString domainServerHostname = settings->value(DOMAIN_SERVER_SETTING_KEY).toString(); - - if (domainServerHostname.size() > 0) { - _domainHandler.setHostname(domainServerHostname); - } else { - _domainHandler.setHostname(DEFAULT_DOMAIN_HOSTNAME); - } - - settings->endGroup(); -} - -void NodeList::saveData(QSettings* settings) { - settings->beginGroup(DOMAIN_SERVER_SETTING_KEY); - - if (_domainHandler.getHostname() != DEFAULT_DOMAIN_HOSTNAME) { - // the user is using a different hostname, store it - settings->setValue(DOMAIN_SERVER_SETTING_KEY, QVariant(_domainHandler.getHostname())); - } else { - // the user has switched back to default, remove the current setting - settings->remove(DOMAIN_SERVER_SETTING_KEY); - } - - settings->endGroup(); -} diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index c1e2d12319..921f33b454 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -63,9 +63,6 @@ public: void sendAssignment(Assignment& assignment); void pingPunchForInactiveNode(const SharedNodePointer& node); - - void loadData(QSettings* settings); - void saveData(QSettings* settings); public slots: void reset(); void sendDomainServerCheckIn(); From d02795cc85658b4178dbc4cf0de84b5b878c2fce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 10:48:09 -0700 Subject: [PATCH 37/44] have data-web respond with ice server hostname to use for connection --- domain-server/src/DomainServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 67e05af2c6..8aaf30860a 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -998,7 +998,8 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, domainUpdateJSON.toUtf8()); } -const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr(QHostAddress::LocalHost, ICE_SERVER_DEFAULT_PORT); +// todo: have data-web respond with ice-server hostname to use +const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr("ice.highfidelity.io", ICE_SERVER_DEFAULT_PORT); void DomainServer::performICEUpdates() { sendHearbeatToIceServer(); From 1b294443aca4973379c34c86fe1a8f899b67a9f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 11:25:47 -0700 Subject: [PATCH 38/44] remove the jenkins groovy that is no longer used --- jenkins/jobs.groovy | 190 -------------------------------------------- 1 file changed, 190 deletions(-) delete mode 100644 jenkins/jobs.groovy diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy deleted file mode 100644 index 7cab63d42d..0000000000 --- a/jenkins/jobs.groovy +++ /dev/null @@ -1,190 +0,0 @@ -JENKINS_URL = 'https://jenkins.below92.com/' -GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' -GIT_REPO_URL = 'git@github.com:worklist/hifi.git' -HIPCHAT_ROOM = 'High Fidelity' - -def hifiJob(String targetName, Boolean deploy) { - job { - name "hifi-${targetName}" - logRotator(7, -1, -1, -1) - - scm { - git(GIT_REPO_URL, 'master') { node -> - node << { - includedRegions "${targetName}/.*\nlibraries/.*" - useShallowClone true - } - } - } - - configure { project -> - project / 'properties' << { - 'com.coravy.hudson.plugins.github.GithubProjectProperty' { - projectUrl GITHUB_HOOK_URL - } - - 'jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty' { - room HIPCHAT_ROOM - } - - 'hudson.plugins.buildblocker.BuildBlockerProperty' { - useBuildBlocker true - blockingJobs 'hifi--seed' - } - } - - project / 'triggers' << 'com.cloudbees.jenkins.GitHubPushTrigger' { - spec '' - } - } - - configure cmakeBuild(targetName, 'make install') - - if (deploy) { - publishers { - publishScp("${ARTIFACT_DESTINATION}") { - entry("**/build/${targetName}/${targetName}", "deploy/${targetName}") - } - } - } - - configure { project -> - - project / 'publishers' << { - if (deploy) { - 'hudson.plugins.postbuildtask.PostbuildTask' { - 'tasks' { - 'hudson.plugins.postbuildtask.TaskProperties' { - logTexts { - 'hudson.plugins.postbuildtask.LogProperties' { - logText '.' - operator 'AND' - } - } - EscalateStatus true - RunIfJobSuccessful true - script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://${ARTIFACT_DESTINATION}" - } - } - } - } - - 'jenkins.plugins.hipchat.HipChatNotifier' { - jenkinsUrl JENKINS_URL - authToken "${HIPCHAT_AUTH_TOKEN}" - room HIPCHAT_ROOM - } - } - } - } -} - -static Closure cmakeBuild(srcDir, instCommand) { - return { project -> - project / 'builders' / 'hudson.plugins.cmake.CmakeBuilder' { - sourceDir '.' - buildDir 'build' - installDir '' - buildType 'RelWithDebInfo' - generator 'Unix Makefiles' - makeCommand "make ${srcDir}" - installCommand instCommand - preloadScript '' - cmakeArgs '' - projectCmakePath '/usr/local/bin/cmake' - cleanBuild 'false' - cleanInstallDir 'false' - builderImpl '' - } - } -} - -def targets = [ - 'animation-server':true, - 'assignment-server':true, - 'assignment-client':true, - 'domain-server':true, - 'eve':true, - 'pairing-server':true, - 'space-server':true, - 'voxel-server':true, -] - -/* setup all of the target jobs to use the above template */ -for (target in targets) { - queue hifiJob(target.key, target.value) -} - -/* setup the OS X interface builds */ -interfaceOSXJob = hifiJob('interface', false) -interfaceOSXJob.with { - name 'hifi-interface-osx' - - scm { - git(GIT_REPO_URL, 'stable') { node -> - node << { - includedRegions "interface/.*\nlibraries/.*" - useShallowClone true - } - } - } - - configure { project -> - project << { - assignedNode 'interface-mini' - canRoam false - } - } -} - -queue interfaceOSXJob - -/* setup the parametrized build job for builds from jenkins */ -parameterizedJob = hifiJob('$TARGET', true) -parameterizedJob.with { - name 'hifi-branch-deploy' - parameters { - stringParam('GITHUB_USER', '', "Specifies the name of the GitHub user that we're building from.") - stringParam('GIT_BRANCH', '', "Specifies the specific branch to build and deploy.") - stringParam('HOSTNAME', 'devel.highfidelity.io', "Specifies the hostname to deploy against.") - stringParam('TARGET', '', "What server to build specifically") - } - scm { - git('git@github.com:/$GITHUB_USER/hifi.git', '$GIT_BRANCH') { node -> - node << { - wipeOutWorkspace true - useShallowClone true - } - - } - } - configure { project -> - def curlCommand = 'curl -d action=hifidevgrid -d "hostname=$HOSTNAME" ' + - '-d "github_user=$GITHUB_USER" -d "build_branch=$GIT_BRANCH" ' + - "-d \"revision=\$TARGET\" https://${ARTIFACT_DESTINATION}" - - (project / publishers / 'hudson.plugins.postbuildtask.PostbuildTask' / - tasks / 'hudson.plugins.postbuildtask.TaskProperties' / script).setValue(curlCommand) - } -} - -doxygenJob = hifiJob('docs', false) -doxygenJob.with { - scm { - git(GIT_REPO_URL, 'master') { node -> - node << { - useShallowClone true - } - } - } - - configure { project -> - (project / builders).setValue('') - } - - steps { - shell('doxygen') - } -} - -queue doxygenJob From 78825f0c4d92266ef2f3f3e5b480f4b2a64772d5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 3 Oct 2014 13:52:50 -0700 Subject: [PATCH 39/44] Fix for normalization crash. --- interface/src/MetavoxelSystem.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 1e235b6116..f82fba98a0 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1551,6 +1551,11 @@ public: AxisIndex(int x = -1, int y = -1, int z = -1) : x(x), y(y), z(z) { } }; +static glm::vec3 safeNormalize(const glm::vec3& vector) { + float length = glm::length(vector); + return (length > 0.0f) ? (vector / length) : vector; +} + int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return DEFAULT_ORDER; @@ -1879,7 +1884,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { } } } - glm::vec3 normal = glm::normalize(axisNormals[0] + axisNormals[1] + axisNormals[2]); + glm::vec3 normal = safeNormalize(axisNormals[0] + axisNormals[1] + axisNormals[2]); center /= crossingCount; // use a sequence of Givens rotations to perform a QR decomposition @@ -1967,12 +1972,12 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { vertices.append(point); } else { - axisNormals[0] = glm::normalize(axisNormals[0]); - axisNormals[1] = glm::normalize(axisNormals[1]); - axisNormals[2] = glm::normalize(axisNormals[2]); - glm::vec3 normalXY(glm::normalize(axisNormals[0] + axisNormals[1])); - glm::vec3 normalXZ(glm::normalize(axisNormals[0] + axisNormals[2])); - glm::vec3 normalYZ(glm::normalize(axisNormals[1] + axisNormals[2])); + axisNormals[0] = safeNormalize(axisNormals[0]); + axisNormals[1] = safeNormalize(axisNormals[1]); + axisNormals[2] = safeNormalize(axisNormals[2]); + glm::vec3 normalXY(safeNormalize(axisNormals[0] + axisNormals[1])); + glm::vec3 normalXZ(safeNormalize(axisNormals[0] + axisNormals[2])); + glm::vec3 normalYZ(safeNormalize(axisNormals[1] + axisNormals[2])); if (glm::dot(axisNormals[0], normalXY) > CREASE_COS_NORMAL && glm::dot(axisNormals[1], normalXY) > CREASE_COS_NORMAL) { point.setNormal(normalXY); From f673ab316a4b0d765e3483248fa74740b7ecb073 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 15:06:27 -0700 Subject: [PATCH 40/44] tell the data-server about auto networking change to full --- domain-server/src/DomainServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index c950d2f8b6..2a7c818125 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -359,6 +359,9 @@ void DomainServer::setupAutomaticNetworking() { // call our sendHeartbeaToIceServer immediately anytime a public address changes connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); + + // tell the data server which type of automatic networking we are using + updateNetworkingInfoWithDataServer(automaticNetworkValue); } // attempt to update our sockets now From 1d3754551135bcdefff203413dc81d2238dda324 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 3 Oct 2014 15:25:03 -0700 Subject: [PATCH 41/44] Moved attenuation setting to non advanced --- domain-server/resources/describe-settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 24e9a5b63b..1ee52fdf28 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -53,11 +53,11 @@ }, { "name": "attenuation_per_doubling_in_distance", - "label": "Attenuattion per doubling in distance", + "label": "Attenuation per doubling in distance", "help": "Factor between 0.0 and 1.0 (0.0: No attenuation, 1.0: extreme attenuation)", "placeholder": "0.18", "default": "0.18", - "advanced": true + "advanced": false }, { "name": "dynamic_jitter_buffer", From 4e0bb94cdd69f703d38d3ddfc5639042aef9a1b1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 15:25:47 -0700 Subject: [PATCH 42/44] fix for double ICE connect attempts from domain-server --- domain-server/src/DomainServer.cpp | 12 +++++++----- libraries/networking/src/NetworkPeer.cpp | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 2a7c818125..452d9d35b7 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1027,7 +1027,7 @@ void DomainServer::sendICEPingPackets() { } else { // send ping packets to this peer's interfaces qDebug() << "Sending ping packets to establish connectivity with ICE peer with ID" - << peer->getUUID(); + << peer->getUUID(); // send the ping packet to the local and public sockets for this node QByteArray localPingPacket = nodeList->constructPingPacket(PingType::Local, false); @@ -1055,11 +1055,13 @@ void DomainServer::processICEHeartbeatResponse(const QByteArray& packet) { while (!iceResponseStream.atEnd()) { iceResponseStream >> receivedPeer; - if (!_connectingICEPeers.contains(receivedPeer.getUUID()) && !_connectedICEPeers.contains(receivedPeer.getUUID())) { - qDebug() << "New peer requesting connection being added to hash -" << receivedPeer; + if (!_connectedICEPeers.contains(receivedPeer.getUUID())) { + if (!_connectingICEPeers.contains(receivedPeer.getUUID())) { + qDebug() << "New peer requesting connection being added to hash -" << receivedPeer; + } + + _connectingICEPeers[receivedPeer.getUUID()] = receivedPeer; } - - _connectingICEPeers[receivedPeer.getUUID()] = receivedPeer; } } diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index d458f579c1..eaaf57471c 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -46,6 +46,7 @@ NetworkPeer::NetworkPeer(const NetworkPeer& otherPeer) { _wakeTimestamp = otherPeer._wakeTimestamp; _lastHeardMicrostamp = otherPeer._lastHeardMicrostamp; + _connectionAttempts = otherPeer._connectionAttempts; } NetworkPeer& NetworkPeer::operator=(const NetworkPeer& otherPeer) { @@ -62,6 +63,7 @@ void NetworkPeer::swap(NetworkPeer& otherPeer) { swap(_localSocket, otherPeer._localSocket); swap(_wakeTimestamp, otherPeer._wakeTimestamp); swap(_lastHeardMicrostamp, otherPeer._lastHeardMicrostamp); + swap(_connectionAttempts, otherPeer._connectionAttempts); } QByteArray NetworkPeer::toByteArray() const { From 8ce474d3e14aa36b1508c2926cdc5b732202e5cd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 15:29:16 -0700 Subject: [PATCH 43/44] make the ice server const scoped to remove warning --- domain-server/src/DomainServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 452d9d35b7..61310cad75 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1002,7 +1002,6 @@ void DomainServer::updateNetworkingInfoWithDataServer(const QString& newSetting, } // todo: have data-web respond with ice-server hostname to use -const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr("ice.highfidelity.io", ICE_SERVER_DEFAULT_PORT); void DomainServer::performICEUpdates() { sendHearbeatToIceServer(); @@ -1010,6 +1009,7 @@ void DomainServer::performICEUpdates() { } void DomainServer::sendHearbeatToIceServer() { + const HifiSockAddr ICE_SERVER_SOCK_ADDR = HifiSockAddr("ice.highfidelity.io", ICE_SERVER_DEFAULT_PORT); LimitedNodeList::getInstance()->sendHeartbeatToIceServer(ICE_SERVER_SOCK_ADDR); } From 2ce2c9e9536624ec6f842d4e72190b73334a822f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 3 Oct 2014 15:33:51 -0700 Subject: [PATCH 44/44] add a missing slash in path for release hydra support --- interface/src/devices/SixenseManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index f5d838f95b..48ea85214a 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -101,7 +101,7 @@ void SixenseManager::initialize() { _sixenseLibrary = new QLibrary(SIXENSE_LIB_FILENAME); #else const QString SIXENSE_LIBRARY_NAME = "libsixense_x64"; - QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "../Frameworks/" + QString frameworkSixenseLibrary = QCoreApplication::applicationDirPath() + "/../Frameworks/" + SIXENSE_LIBRARY_NAME; _sixenseLibrary = new QLibrary(frameworkSixenseLibrary);