diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index b940d46849..ec913b27f5 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -62,10 +62,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetSenderSockAddr(), - DomainHandler::ConnectionRefusedReason::ProtocolMismatch); + sendProtocolMismatchConnectionDenial(message->getSenderSockAddr()); return; } @@ -530,15 +527,24 @@ void DomainGatekeeper::publicKeyJSONCallback(QNetworkReply& requestReply) { } } +void DomainGatekeeper::sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr) { + QString protocolVersionError = "Protocol version mismatch - Domain version: " + QCoreApplication::applicationVersion(); + + qDebug() << "Protocol Version mismatch - denying connection."; + + sendConnectionDeniedPacket(protocolVersionError, senderSockAddr, + DomainHandler::ConnectionRefusedReason::ProtocolMismatch); +} + void DomainGatekeeper::sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr, - DomainHandler::ConnectionRefusedReason reasonCode) { + DomainHandler::ConnectionRefusedReason reasonCode) { // this is an agent and we've decided we won't let them connect - send them a packet to deny connection QByteArray utfString = reason.toUtf8(); quint16 payloadSize = utfString.size(); // setup the DomainConnectionDenied packet auto connectionDeniedPacket = NLPacket::create(PacketType::DomainConnectionDenied, - payloadSize + sizeof(payloadSize) + sizeof(uint8_t)); + payloadSize + sizeof(payloadSize) + sizeof(uint8_t)); // pack in the reason the connection was denied (the client displays this) if (payloadSize > 0) { diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 09e3b04ed7..237f8d3185 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -42,6 +42,8 @@ public: void preloadAllowedUserPublicKeys(); void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); } + + static void sendProtocolMismatchConnectionDenial(const HifiSockAddr& senderSockAddr); public slots: void processConnectRequestPacket(QSharedPointer message); void processICEPingPacket(QSharedPointer message); @@ -76,8 +78,8 @@ private: const HifiSockAddr& senderSockAddr); void sendConnectionTokenPacket(const QString& username, const HifiSockAddr& senderSockAddr); - void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr, - DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown); + static void sendConnectionDeniedPacket(const QString& reason, const HifiSockAddr& senderSockAddr, + DomainHandler::ConnectionRefusedReason reasonCode = DomainHandler::ConnectionRefusedReason::Unknown); void pingPunchForConnectingPeer(const SharedNetworkPeer& peer); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 0f5498a575..7c20817353 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -318,16 +318,11 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { auto nodeList = DependencyManager::get(); - // This implements a special case that handles OLD clients which don't know how to negotiate matching - // protocol versions. We know these clients will sent DomainConnectRequest with older versions. We also - // know these clients will show a warning dialog if they get an EntityData with a protocol version they - // don't understand, so we can send them an empty EntityData with our latest version and they will - // warn the user that the protocol is not compatible - if (headerType == PacketType::DomainConnectRequest && - headerVersion < static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { - auto packetWithBadVersion = NLPacket::create(PacketType::EntityData); - nodeList->sendPacket(std::move(packetWithBadVersion), packet.getSenderSockAddr()); - return false; + // if this is a mismatching connect packet, we can't simply drop it on the floor + // send back a packet to the interface that tells them we refuse connection for a mismatch + if (headerType == PacketType::DomainConnectRequest + && headerVersion != versionForPacketType(PacketType::DomainConnectRequest)) { + DomainGatekeeper::sendProtocolMismatchConnectionDenial(packet.getSenderSockAddr()); } // let the normal nodeList implementation handle all other packets. diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 68e916c29e..504d573678 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -630,7 +630,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); - connect(&domainHandler, &DomainHandler::resetting, nodeList.data(), &NodeList::resetDomainServerCheckInVersion); connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &Application::domainConnectionRefused); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one @@ -654,9 +653,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(nodeList.data(), &NodeList::nodeActivated, this, &Application::nodeActivated); connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID); connect(nodeList.data(), &NodeList::uuidChanged, this, &Application::setSessionUUID); - connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, this, &Application::limitOfSilentDomainCheckInsReached); connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); + // you might think we could just do this in NodeList but we only want this connection for Interface + connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); + // connect to appropriate slots on AccountManager auto accountManager = DependencyManager::get(); @@ -1074,8 +1075,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCode) { switch (static_cast(reasonCode)) { case DomainHandler::ConnectionRefusedReason::ProtocolMismatch: - notifyPacketVersionMismatch(); - break; case DomainHandler::ConnectionRefusedReason::TooManyUsers: case DomainHandler::ConnectionRefusedReason::Unknown: { QString message = "Unable to connect to the location you are visiting.\n"; @@ -4619,17 +4618,6 @@ void Application::setSessionUUID(const QUuid& sessionUUID) const { Physics::setSessionUUID(sessionUUID); } - -// If we're not getting anything back from the domain server checkin, it might be that the domain speaks an -// older version of the DomainConnectRequest protocol. We will attempt to send and older version of DomainConnectRequest. -// We won't actually complete the connection, but if the server responds, we know that it needs to be upgraded (or we -// need to be downgraded to talk to it). -void Application::limitOfSilentDomainCheckInsReached() { - auto nodeList = DependencyManager::get(); - nodeList->downgradeDomainServerCheckInVersion(); // attempt to use an older domain checkin version - nodeList->reset(); -} - bool Application::askToSetAvatarUrl(const QString& url) { QUrl realUrl(url); if (realUrl.isLocalFile()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index f93434f581..6b6148be32 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -318,7 +318,6 @@ private slots: bool displayAvatarAttachmentConfirmationDialog(const QString& name) const; void setSessionUUID(const QUuid& sessionUUID) const; - void limitOfSilentDomainCheckInsReached(); void domainChanged(const QString& domainHostname); void updateWindowTitle() const; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 031564fa7a..4fd5569ebd 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -542,6 +542,9 @@ Menu::Menu() { #if (PR_BUILD || DEV_BUILD) addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongProtocolVersion, 0, false, qApp, SLOT(sendWrongProtocolVersionsSignature(bool))); + + addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::SendWrongDSConnectVersion, 0, false, + nodeList.data(), SLOT(toggleSendNewerDSConnectVersion(bool))); #endif diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8081e27eb8..503cbf51fa 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -166,6 +166,7 @@ namespace MenuOption { const QString RunTimingTests = "Run Timing Tests"; const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; + const QString SendWrongDSConnectVersion = "Send wrong DS connect version"; const QString SendWrongProtocolVersion = "Send wrong protocol version"; const QString SetHomeLocation = "Set Home Location"; const QString ShowDSConnectTable = "Show Domain Connection Timing"; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 1b7ed11cce..80989acd2c 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -144,12 +144,21 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) { // 4. domain network address (IP or dns resolvable hostname) // use our regex'ed helpers to figure out what we're supposed to do with this - if (!handleUsername(lookupUrl.authority())) { + if (handleUsername(lookupUrl.authority())) { + // handled a username for lookup + + // in case we're failing to connect to where we thought this user was + // store their username as previous lookup so we can refresh their location via API + _previousLookup = lookupUrl; + } else { // we're assuming this is either a network address or global place name // check if it is a network address first bool hostChanged; if (handleNetworkAddress(lookupUrl.host() - + (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger, hostChanged)) { + + (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger, hostChanged)) { + + // a network address lookup clears the previous lookup since we don't expect to re-attempt it + _previousLookup.clear(); // If the host changed then we have already saved to history if (hostChanged) { @@ -165,10 +174,16 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) { // we may have a path that defines a relative viewpoint - if so we should jump to that now handlePath(path, trigger); } else if (handleDomainID(lookupUrl.host())){ + // store this domain ID as the previous lookup in case we're failing to connect and want to refresh API info + _previousLookup = lookupUrl; + // no place name - this is probably a domain ID // try to look up the domain ID on the metaverse API attemptDomainIDLookup(lookupUrl.host(), lookupUrl.path(), trigger); } else { + // store this place name as the previous lookup in case we fail to connect and want to refresh API info + _previousLookup = lookupUrl; + // wasn't an address - lookup the place name // we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger); @@ -180,9 +195,13 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) { } else if (lookupUrl.toString().startsWith('/')) { qCDebug(networking) << "Going to relative path" << lookupUrl.path(); + // a path lookup clears the previous lookup since we don't expect to re-attempt it + _previousLookup.clear(); + // if this is a relative path then handle it as a relative viewpoint handlePath(lookupUrl.path(), trigger, true); emit lookupResultsFinished(); + return true; } @@ -276,7 +295,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const qCDebug(networking) << "Possible domain change required to connect to" << domainHostname << "on" << domainPort; - emit possibleDomainChangeRequired(domainHostname, domainPort); + emit possibleDomainChangeRequired(domainHostname, domainPort, domainID); } else { QString iceServerAddress = domainObject[DOMAIN_ICE_SERVER_ADDRESS_KEY].toString(); @@ -315,7 +334,10 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const QString overridePath = reply.property(OVERRIDE_PATH_KEY).toString(); if (!overridePath.isEmpty()) { - handlePath(overridePath, trigger); + // make sure we don't re-handle an overriden path if this was a refresh of info from API + if (trigger != LookupTrigger::AttemptedRefresh) { + handlePath(overridePath, trigger); + } } else { // take the path that came back const QString PLACE_PATH_KEY = "path"; @@ -362,7 +384,7 @@ void AddressManager::handleAPIError(QNetworkReply& errorReply) { if (errorReply.error() == QNetworkReply::ContentNotFoundError) { // if this is a lookup that has no result, don't keep re-trying it - //_previousLookup.clear(); + _previousLookup.clear(); emit lookupResultIsNotFound(); } @@ -598,7 +620,7 @@ bool AddressManager::setDomainInfo(const QString& hostname, quint16 port, Lookup DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress); - emit possibleDomainChangeRequired(hostname, port); + emit possibleDomainChangeRequired(hostname, port, QUuid()); return hostChanged; } @@ -618,6 +640,13 @@ void AddressManager::goToUser(const QString& username) { QByteArray(), nullptr, requestParams); } +void AddressManager::refreshPreviousLookup() { + // if we have a non-empty previous lookup, fire it again now (but don't re-store it in the history) + if (!_previousLookup.isEmpty()) { + handleUrl(_previousLookup, LookupTrigger::AttemptedRefresh); + } +} + void AddressManager::copyAddress() { QApplication::clipboard()->setText(currentAddress().toString()); } @@ -629,7 +658,10 @@ void AddressManager::copyPath() { void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) { // if we're cold starting and this is called for the first address (from settings) we don't do anything - if (trigger != LookupTrigger::StartupFromSettings && trigger != LookupTrigger::DomainPathResponse) { + if (trigger != LookupTrigger::StartupFromSettings + && trigger != LookupTrigger::DomainPathResponse + && trigger != LookupTrigger::AttemptedRefresh) { + if (trigger == LookupTrigger::Back) { // we're about to push to the forward stack // if it's currently empty emit our signal to say that going forward is now possible diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 643924ff5c..a3aaee3ba2 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -48,7 +48,8 @@ public: Forward, StartupFromSettings, DomainPathResponse, - Internal + Internal, + AttemptedRefresh }; bool isConnected(); @@ -89,6 +90,8 @@ public slots: void goToUser(const QString& username); + void refreshPreviousLookup(); + void storeCurrentAddress(); void copyAddress(); @@ -99,7 +102,7 @@ signals: void lookupResultIsOffline(); void lookupResultIsNotFound(); - void possibleDomainChangeRequired(const QString& newHostname, quint16 newPort); + void possibleDomainChangeRequired(const QString& newHostname, quint16 newPort, const QUuid& domainID); void possibleDomainChangeRequiredViaICEForID(const QString& iceServerHostname, const QUuid& domainID); void locationChangeRequired(const glm::vec3& newPosition, @@ -152,6 +155,8 @@ private: quint64 _lastBackPush = 0; QString _newHostLookupPath; + + QUrl _previousLookup; }; #endif // hifi_AddressManager_h diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 4f85296f03..6880b7a329 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -14,6 +14,7 @@ #include #include +#include "AddressManager.h" #include "Assignment.h" #include "HifiSockAddr.h" #include "NodeList.h" @@ -28,17 +29,10 @@ DomainHandler::DomainHandler(QObject* parent) : QObject(parent), - _uuid(), _sockAddr(HifiSockAddr(QHostAddress::Null, DEFAULT_DOMAIN_SERVER_PORT)), - _assignmentUUID(), - _connectionToken(), - _iceDomainID(), - _iceClientID(), - _iceServerSockAddr(), _icePeer(this), - _isConnected(false), - _settingsObject(), - _settingsTimer(this) + _settingsTimer(this), + _apiRefreshTimer(this) { _sockAddr.setObjectName("DomainServer"); @@ -49,6 +43,16 @@ DomainHandler::DomainHandler(QObject* parent) : static const int DOMAIN_SETTINGS_TIMEOUT_MS = 5000; _settingsTimer.setInterval(DOMAIN_SETTINGS_TIMEOUT_MS); connect(&_settingsTimer, &QTimer::timeout, this, &DomainHandler::settingsReceiveFail); + + // setup the API refresh timer for auto connection information refresh from API when failing to connect + const int API_REFRESH_TIMEOUT_MSEC = 2500; + _apiRefreshTimer.setInterval(API_REFRESH_TIMEOUT_MSEC); + + auto addressManager = DependencyManager::get(); + connect(&_apiRefreshTimer, &QTimer::timeout, addressManager.data(), &AddressManager::refreshPreviousLookup); + + // stop the refresh timer if we connect to a domain + connect(this, &DomainHandler::connectedToDomain, &_apiRefreshTimer, &QTimer::stop); } void DomainHandler::disconnect() { @@ -93,10 +97,14 @@ void DomainHandler::softReset() { clearSettings(); + _domainConnectionRefusals.clear(); _connectionDenialsSinceKeypairRegen = 0; // cancel the failure timeout for any pending requests for settings QMetaObject::invokeMethod(&_settingsTimer, "stop"); + + // restart the API refresh timer in case we fail to connect and need to refresh information + QMetaObject::invokeMethod(&_apiRefreshTimer, "start"); } void DomainHandler::hardReset() { @@ -105,7 +113,7 @@ void DomainHandler::hardReset() { softReset(); qCDebug(networking) << "Hard reset in NodeList DomainHandler."; - _iceDomainID = QUuid(); + _pendingDomainID = QUuid(); _iceServerSockAddr = HifiSockAddr(); _hostname = QString(); _sockAddr.clear(); @@ -139,7 +147,9 @@ void DomainHandler::setUUID(const QUuid& uuid) { } } -void DomainHandler::setHostnameAndPort(const QString& hostname, quint16 port) { +void DomainHandler::setSocketAndID(const QString& hostname, quint16 port, const QUuid& domainID) { + + _pendingDomainID = domainID; if (hostname != _hostname || _sockAddr.getPort() != port) { // re-set the domain info so that auth information is reloaded @@ -149,9 +159,6 @@ void DomainHandler::setHostnameAndPort(const QString& hostname, quint16 port) { // set the new hostname _hostname = hostname; - // FIXME - is this the right place??? - _domainConnectionRefusals.clear(); - qCDebug(networking) << "Updated domain hostname to" << _hostname; // re-set the sock addr to null and fire off a lookup of the IP address for this domain-server's hostname @@ -174,14 +181,15 @@ void DomainHandler::setHostnameAndPort(const QString& hostname, quint16 port) { } void DomainHandler::setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id) { - if (id != _uuid) { + + if (_iceServerSockAddr.getAddress().toString() != iceServerHostname || id != _pendingDomainID) { // re-set the domain info to connect to new domain hardReset(); // refresh our ICE client UUID to something new _iceClientID = QUuid::createUuid(); - _iceDomainID = id; + _pendingDomainID = id; HifiSockAddr* replaceableSockAddr = &_iceServerSockAddr; replaceableSockAddr->~HifiSockAddr(); @@ -255,6 +263,7 @@ void DomainHandler::setIsConnected(bool isConnected) { // we've connected to new domain - time to ask it for global settings requestDomainSettings(); + } else { emit disconnectedFromDomain(); } @@ -305,6 +314,9 @@ void DomainHandler::processICEPingReplyPacket(QSharedPointer me qCDebug(networking) << "Received reply from domain-server on" << senderSockAddr; if (getIP().isNull()) { + // we're hearing back from this domain-server, no need to refresh API information + _apiRefreshTimer.stop(); + // for now we're unsafely assuming this came back from the domain if (senderSockAddr == _icePeer.getLocalSocket()) { qCDebug(networking) << "Connecting to domain using local socket"; @@ -333,17 +345,20 @@ void DomainHandler::processDTLSRequirementPacket(QSharedPointer void DomainHandler::processICEResponsePacket(QSharedPointer message) { if (_icePeer.hasSockets()) { qDebug() << "Received an ICE peer packet for domain-server but we already have sockets. Not processing."; - // bail on processing this packet if our ice peer doesn't have sockets + // bail on processing this packet if our ice peer already has sockets return; } + // start or restart the API refresh timer now that we have new information + _apiRefreshTimer.start(); + QDataStream iceResponseStream(message->getMessage()); iceResponseStream >> _icePeer; DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSPeerInformation); - if (_icePeer.getUUID() != _iceDomainID) { + if (_icePeer.getUUID() != _pendingDomainID) { qCDebug(networking) << "Received a network peer with ID that does not match current domain. Will not attempt connection."; _icePeer.reset(); } else { @@ -373,6 +388,9 @@ bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) { } void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer message) { + // we're hearing from this domain-server, don't need to refresh API info + _apiRefreshTimer.stop(); + // Read deny reason from packet uint8_t reasonCodeWire; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index bcee7668d1..1328174e87 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -58,8 +58,8 @@ public: const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } - - const QUuid& getICEDomainID() const { return _iceDomainID; } + + const QUuid& getPendingDomainID() const { return _pendingDomainID; } const QUuid& getICEClientID() const { return _iceClientID; } @@ -75,7 +75,6 @@ public: bool hasSettings() const { return !_settingsObject.isEmpty(); } void requestDomainSettings(); const QJsonObject& getSettingsObject() const { return _settingsObject; } - void setPendingPath(const QString& pendingPath) { _pendingPath = pendingPath; } const QString& getPendingPath() { return _pendingPath; } @@ -94,7 +93,7 @@ public: }; public slots: - void setHostnameAndPort(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT); + void setSocketAndID(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT, const QUuid& id = QUuid()); void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); void processSettingsPacketList(QSharedPointer packetList); @@ -136,11 +135,11 @@ private: HifiSockAddr _sockAddr; QUuid _assignmentUUID; QUuid _connectionToken; - QUuid _iceDomainID; + QUuid _pendingDomainID; // ID of domain being connected to, via ICE or direct connection QUuid _iceClientID; HifiSockAddr _iceServerSockAddr; NetworkPeer _icePeer; - bool _isConnected; + bool _isConnected { false }; QJsonObject _settingsObject; QString _pendingPath; QTimer _settingsTimer; @@ -148,6 +147,8 @@ private: QStringList _domainConnectionRefusals; bool _hasCheckedForAccessToken { false }; int _connectionDenialsSinceKeypairRegen { 0 }; + + QTimer _apiRefreshTimer; }; #endif // hifi_DomainHandler_h diff --git a/libraries/networking/src/NLPacket.cpp b/libraries/networking/src/NLPacket.cpp index 34a159ae6c..a11dd69753 100644 --- a/libraries/networking/src/NLPacket.cpp +++ b/libraries/networking/src/NLPacket.cpp @@ -184,6 +184,11 @@ void NLPacket::setType(PacketType type) { writeTypeAndVersion(); } +void NLPacket::setVersion(PacketVersion version) { + _version = version; + writeTypeAndVersion(); +} + void NLPacket::readType() { _type = NLPacket::typeInHeader(*this); } diff --git a/libraries/networking/src/NLPacket.h b/libraries/networking/src/NLPacket.h index f49f8498a5..33de262dfb 100644 --- a/libraries/networking/src/NLPacket.h +++ b/libraries/networking/src/NLPacket.h @@ -65,6 +65,7 @@ public: void setType(PacketType type); PacketVersion getVersion() const { return _version; } + void setVersion(PacketVersion version); const QUuid& getSourceID() const { return _sourceID; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 16a4083b08..8375cd0b1e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -50,7 +50,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // handle domain change signals from AddressManager connect(addressManager.data(), &AddressManager::possibleDomainChangeRequired, - &_domainHandler, &DomainHandler::setHostnameAndPort); + &_domainHandler, &DomainHandler::setSocketAndID); connect(addressManager.data(), &AddressManager::possibleDomainChangeRequiredViaICEForID, &_domainHandler, &DomainHandler::setIceServerHostnameAndID); @@ -250,7 +250,6 @@ void NodeList::sendDomainServerCheckIn() { qCDebug(networking) << "Waiting for ICE discovered domain-server socket. Will not send domain-server check in."; handleICEConnectionToDomainServer(); } else if (!_domainHandler.getIP().isNull()) { - bool isUsingDTLS = false; PacketType domainPacketType = !_domainHandler.isConnected() ? PacketType::DomainConnectRequest : PacketType::DomainListRequest; @@ -292,12 +291,18 @@ void NodeList::sendDomainServerCheckIn() { return; } - auto packetVersion = (domainPacketType == PacketType::DomainConnectRequest) ? _domainConnectRequestVersion : 0; - auto domainPacket = NLPacket::create(domainPacketType, -1, false, false, packetVersion); + auto domainPacket = NLPacket::create(domainPacketType); QDataStream packetStream(domainPacket.get()); if (domainPacketType == PacketType::DomainConnectRequest) { + +#if (PR_BUILD || DEV_BUILD) + if (_shouldSendNewerVersion) { + domainPacket->setVersion(versionForPacketType(domainPacketType) + 1); + } +#endif + QUuid connectUUID; if (!_domainHandler.getAssignmentUUID().isNull()) { @@ -315,18 +320,14 @@ void NodeList::sendDomainServerCheckIn() { packetStream << connectUUID; // include the protocol version signature in our connect request - if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasProtocolVersions)) { - QByteArray protocolVersionSig = protocolVersionsSignature(); - packetStream.writeBytes(protocolVersionSig.constData(), protocolVersionSig.size()); - } + QByteArray protocolVersionSig = protocolVersionsSignature(); + packetStream.writeBytes(protocolVersionSig.constData(), protocolVersionSig.size()); } // pack our data to send to the domain-server including // the hostname information (so the domain-server can see which place name we came in on) packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList(); - if (_domainConnectRequestVersion >= static_cast(DomainConnectRequestVersion::HasHostname)) { - packetStream << DependencyManager::get()->getPlaceName(); - } + packetStream << DependencyManager::get()->getPlaceName(); if (!_domainHandler.isConnected()) { DataServerAccountInfo& accountInfo = accountManager->getAccountInfo(); @@ -341,9 +342,7 @@ void NodeList::sendDomainServerCheckIn() { flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn); - if (!isUsingDTLS) { - sendPacket(std::move(domainPacket), _domainHandler.getSockAddr()); - } + sendPacket(std::move(domainPacket), _domainHandler.getSockAddr()); if (_numNoReplyDomainCheckIns >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { // we haven't heard back from DS in MAX_SILENT_DOMAIN_SERVER_CHECK_INS @@ -462,7 +461,7 @@ void NodeList::handleICEConnectionToDomainServer() { LimitedNodeList::sendPeerQueryToIceServer(_domainHandler.getICEServerSockAddr(), _domainHandler.getICEClientID(), - _domainHandler.getICEDomainID()); + _domainHandler.getPendingDomainID()); } } @@ -475,7 +474,7 @@ void NodeList::pingPunchForDomainServer() { if (_domainHandler.getICEPeer().getConnectionAttempts() == 0) { qCDebug(networking) << "Sending ping packets to establish connectivity with domain-server with ID" - << uuidStringWithoutCurlyBraces(_domainHandler.getICEDomainID()); + << uuidStringWithoutCurlyBraces(_domainHandler.getPendingDomainID()); } else { if (_domainHandler.getICEPeer().getConnectionAttempts() % NUM_DOMAIN_SERVER_PINGS_BEFORE_RESET == 0) { // if we have then nullify the domain handler's network peer and send a fresh ICE heartbeat diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index b269554e77..3fbc86c736 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -68,9 +68,6 @@ public: void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; } - /// downgrades the DomainConnnectRequest PacketVersion to attempt to probe for older domain servers - void downgradeDomainServerCheckInVersion() { _domainConnectRequestVersion--; } - public slots: void reset(); void sendDomainServerCheckIn(); @@ -88,8 +85,9 @@ public slots: void processICEPingPacket(QSharedPointer message); - void resetDomainServerCheckInVersion() - { _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); } +#if (PR_BUILD || DEV_BUILD) + void toggleSendNewerDSConnectVersion(bool shouldSendNewerVersion) { _shouldSendNewerVersion = shouldSendNewerVersion; } +#endif signals: void limitOfSilentDomainCheckInsReached(); @@ -105,6 +103,7 @@ private slots: void pingPunchForDomainServer(); void sendKeepAlivePings(); + private: NodeList() : LimitedNodeList(0, 0) { assert(false); } // Not implemented, needed for DependencyManager templates compile NodeList(char ownerType, unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); @@ -130,7 +129,9 @@ private: bool _isShuttingDown { false }; QTimer _keepAlivePingTimer; - PacketVersion _domainConnectRequestVersion = versionForPacketType(PacketType::DomainConnectRequest); +#if (PR_BUILD || DEV_BUILD) + bool _shouldSendNewerVersion { false }; +#endif }; #endif // hifi_NodeList_h