// // DomainHandler.h // libraries/networking/src // // Created by Stephen Birarda on 2/18/2014. // Copyright 2014 High Fidelity, Inc. // Copyright 2020 Vircadia contributors. // // 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_DomainHandler_h #define hifi_DomainHandler_h #include #include #include #include #include #include #include #include #include #include "HifiSockAddr.h" #include "NetworkPeer.h" #include "NLPacket.h" #include "NLPacketList.h" #include "Node.h" #include "ReceivedMessage.h" #include "NetworkingConstants.h" #include "MetaverseAPI.h" const unsigned short DEFAULT_DOMAIN_SERVER_PORT = QProcessEnvironment::systemEnvironment() .contains("HIFI_DOMAIN_SERVER_PORT") ? QProcessEnvironment::systemEnvironment() .value("HIFI_DOMAIN_SERVER_PORT") .toUShort() : 40102; const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = QProcessEnvironment::systemEnvironment() .contains("HIFI_DOMAIN_SERVER_DTLS_PORT") ? QProcessEnvironment::systemEnvironment() .value("HIFI_DOMAIN_SERVER_DTLS_PORT") .toUShort() : 40103; const quint16 DOMAIN_SERVER_HTTP_PORT = QProcessEnvironment::systemEnvironment() .contains("HIFI_DOMAIN_SERVER_HTTP_PORT") ? QProcessEnvironment::systemEnvironment() .value("HIFI_DOMAIN_SERVER_HTTP_PORT") .toUInt() : 40100; const quint16 DOMAIN_SERVER_HTTPS_PORT = QProcessEnvironment::systemEnvironment() .contains("HIFI_DOMAIN_SERVER_HTTPS_PORT") ? QProcessEnvironment::systemEnvironment() .value("HIFI_DOMAIN_SERVER_HTTPS_PORT") .toUInt() : 40101; const quint16 DOMAIN_SERVER_EXPORTER_PORT = QProcessEnvironment::systemEnvironment() .contains("VIRCADIA_DOMAIN_SERVER_EXPORTER_PORT") ? QProcessEnvironment::systemEnvironment() .value("VIRCADIA_DOMAIN_SERVER_EXPORTER_PORT") .toUInt() : 9703; const quint16 DOMAIN_SERVER_METADATA_EXPORTER_PORT = QProcessEnvironment::systemEnvironment() .contains("DOMAIN_SERVER_METADATA_EXPORTER_PORT") ? QProcessEnvironment::systemEnvironment() .value("DOMAIN_SERVER_METADATA_EXPORTER_PORT") .toUInt() : 9704; const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; class DomainHandler : public QObject { Q_OBJECT public: DomainHandler(QObject* parent = 0); void disconnect(QString reason); void clearSettings(); const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid); Node::LocalID getLocalID() const { return _localID; } void setLocalID(Node::LocalID localID) { _localID = localID; } QString getHostname() const { return _domainURL.host(); } QUrl getErrorDomainURL(){ return _errorDomainURL; } void setErrorDomainURL(const QUrl& url); int getLastDomainConnectionError() { return _lastDomainConnectionError; } const QHostAddress& getIP() const { return _sockAddr.getAddress(); } void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); } const HifiSockAddr& getSockAddr() const { return _sockAddr; } void setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname); unsigned short getPort() const { return _sockAddr.getPort(); } void setPort(quint16 port) { _sockAddr.setPort(port); } const QUuid& getConnectionToken() const { return _connectionToken; } void setConnectionToken(const QUuid& connectionToken) { _connectionToken = connectionToken; } const QUuid& getAssignmentUUID() const { return _assignmentUUID; } void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; } const QUuid& getPendingDomainID() const { return _pendingDomainID; } const QUuid& getICEClientID() const { return _iceClientID; } bool requiresICE() const { return !_iceServerSockAddr.isNull(); } const HifiSockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; } NetworkPeer& getICEPeer() { return _icePeer; } void activateICELocalSocket(); void activateICEPublicSocket(); bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; } bool getInterstitialModeEnabled() const; void setInterstitialModeEnabled(bool enableInterstitialMode); void connectedToServerless(std::map namedPaths); void loadedErrorDomain(std::map namedPaths); QString getViewPointFromNamedPath(QString namedPath); 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; } void clearPendingPath() { _pendingPath.clear(); } bool isSocketKnown() const { return !_sockAddr.getAddress().isNull(); } void softReset(QString reason); int getCheckInPacketsSinceLastReply() const { return _checkInPacketsSinceLastReply; } bool checkInPacketTimeout(); void clearPendingCheckins() { _checkInPacketsSinceLastReply = 0; } /**jsdoc *

The reasons that you may be refused connection to a domain are defined by numeric values:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ReasonValueDescription
Unknown0Some unknown reason.
ProtocolMismatch1The communications protocols of the domain and your Interface are not the same.
LoginErrorMetaverse2You could not be logged into the domain per your metaverse login.
NotAuthorizedMetaverse3You are not authorized to connect to the domain per your metaverse login.
TooManyUsers4The domain already has its maximum number of users.
TimedOut5Connecting to the domain timed out.
LoginErrorDomain2You could not be logged into the domain per your domain login.
NotAuthorizedDomain6You are not authorized to connect to the domain per your domain login.
* @typedef {number} Window.ConnectionRefusedReason */ enum class ConnectionRefusedReason : uint8_t { Unknown, ProtocolMismatch, LoginErrorMetaverse, NotAuthorizedMetaverse, TooManyUsers, TimedOut, LoginErrorDomain, NotAuthorizedDomain }; public slots: void setURLAndID(QUrl domainURL, QUuid id); void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); void processSettingsPacketList(QSharedPointer packetList); void processICEPingReplyPacket(QSharedPointer message); void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); void processICEResponsePacket(QSharedPointer icePacket); void processDomainServerConnectionDeniedPacket(QSharedPointer message); // sets domain handler in error state. void setRedirectErrorState(QUrl errorUrl, QString reasonMessage = "", int reason = -1, const QString& extraInfo = ""); bool isInErrorState() { return _isInErrorState; } private slots: void completedHostnameLookup(const QHostInfo& hostInfo); void completedIceServerHostnameLookup(); signals: void domainURLChanged(QUrl domainURL); // NOTE: the emission of completedSocketDiscovery does not mean a connection to DS is established // It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on void completedSocketDiscovery(); void resetting(); void connectedToDomain(QUrl domainURL); void disconnectedFromDomain(); void iceSocketAndIDReceived(); void icePeerSocketsReceived(); void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); void domainConnectionRefused(QString reasonMessage, int reason, const QString& extraInfo); void redirectToErrorDomainURL(QUrl errorDomainURL); void redirectErrorStateChanged(bool isInErrorState); void limitOfSilentDomainCheckInsReached(); private: bool reasonSuggestsMetaverseLogin(ConnectionRefusedReason reasonCode); bool reasonSuggestsDomainLogin(ConnectionRefusedReason reasonCode); void sendDisconnectPacket(); void hardReset(QString reason); bool isHardRefusal(int reasonCode); QUuid _uuid; Node::LocalID _localID; QUrl _domainURL; QUrl _errorDomainURL; HifiSockAddr _sockAddr; QUuid _assignmentUUID; QUuid _connectionToken; QUuid _pendingDomainID; // ID of domain being connected to, via ICE or direct connection QUuid _iceClientID; HifiSockAddr _iceServerSockAddr; NetworkPeer _icePeer; bool _isConnected { false }; bool _isInErrorState { false }; QJsonObject _settingsObject; QString _pendingPath; QTimer _settingsTimer; mutable ReadWriteLockable _interstitialModeSettingLock; #ifdef Q_OS_ANDROID Setting::Handle _enableInterstitialMode{ "enableInterstitialMode", false }; #else Setting::Handle _enableInterstitialMode { "enableInterstitialMode", false }; #endif QSet _domainConnectionRefusals; bool _hasCheckedForAccessToken { false }; bool _hasCheckedForDomainAccessToken { false }; int _connectionDenialsSinceKeypairRegen { 0 }; int _checkInPacketsSinceLastReply { 0 }; QTimer _apiRefreshTimer; std::map _namedPaths; // domain connection error upon connection refusal. int _lastDomainConnectionError{ -1 }; }; const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" }; const QString DEFAULT_NAMED_PATH { "/" }; #endif // hifi_DomainHandler_h