Overte C++ Documentation
DomainHandler.h
1 //
2 // DomainHandler.h
3 // libraries/networking/src
4 //
5 // Created by Stephen Birarda on 2/18/2014.
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2020 Vircadia contributors.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 //
12 
13 #ifndef hifi_DomainHandler_h
14 #define hifi_DomainHandler_h
15 
16 #include <QProcessEnvironment>
17 
18 #include <QtCore/QJsonObject>
19 #include <QtCore/QObject>
20 #include <QtCore/QSharedPointer>
21 #include <QtCore/QTimer>
22 #include <QtCore/QUuid>
23 #include <QtCore/QUrl>
24 #include <QtNetwork/QHostInfo>
25 
26 #include <shared/ReadWriteLockable.h>
27 #include <SettingHandle.h>
28 
29 #include "SockAddr.h"
30 #include "NetworkPeer.h"
31 #include "NLPacket.h"
32 #include "NLPacketList.h"
33 #include "Node.h"
34 #include "ReceivedMessage.h"
35 #include "NetworkingConstants.h"
36 #include "MetaverseAPI.h"
37 
38 const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
39  QProcessEnvironment::systemEnvironment()
40  .contains("HIFI_DOMAIN_SERVER_PORT")
41  ? QProcessEnvironment::systemEnvironment()
42  .value("HIFI_DOMAIN_SERVER_PORT")
43  .toUShort()
44  : 40102; // UDP
45 
46 const unsigned short DEFAULT_DOMAIN_SERVER_WS_PORT =
47  QProcessEnvironment::systemEnvironment()
48  .contains("OVERTE_DOMAIN_SERVER_WS_PORT")
49  ? QProcessEnvironment::systemEnvironment()
50  .value("OVERTE_DOMAIN_SERVER_WS_PORT")
51  .toUShort()
52  : 40102; // TCP
53 
54 const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT =
55  QProcessEnvironment::systemEnvironment()
56  .contains("HIFI_DOMAIN_SERVER_DTLS_PORT")
57  ? QProcessEnvironment::systemEnvironment()
58  .value("HIFI_DOMAIN_SERVER_DTLS_PORT")
59  .toUShort()
60  : 40103;
61 
62 const quint16 DOMAIN_SERVER_HTTP_PORT =
63  QProcessEnvironment::systemEnvironment()
64  .contains("HIFI_DOMAIN_SERVER_HTTP_PORT")
65  ? QProcessEnvironment::systemEnvironment()
66  .value("HIFI_DOMAIN_SERVER_HTTP_PORT")
67  .toUInt()
68  : 40100;
69 
70 const quint16 DOMAIN_SERVER_HTTPS_PORT =
71  QProcessEnvironment::systemEnvironment()
72  .contains("HIFI_DOMAIN_SERVER_HTTPS_PORT")
73  ? QProcessEnvironment::systemEnvironment()
74  .value("HIFI_DOMAIN_SERVER_HTTPS_PORT")
75  .toUInt()
76  : 40101;
77 
78 const quint16 DOMAIN_SERVER_EXPORTER_PORT =
79  QProcessEnvironment::systemEnvironment()
80  .contains("OVERTE_DOMAIN_SERVER_EXPORTER_PORT")
81  ? QProcessEnvironment::systemEnvironment()
82  .value("OVERTE_DOMAIN_SERVER_EXPORTER_PORT")
83  .toUInt()
84  : 9703;
85 
86 const quint16 DOMAIN_SERVER_METADATA_EXPORTER_PORT =
87  QProcessEnvironment::systemEnvironment()
88  .contains("OVERTE_DOMAIN_SERVER_METADATA_EXPORTER_PORT")
89  ? QProcessEnvironment::systemEnvironment()
90  .value("OVERTE_DOMAIN_SERVER_METADATA_EXPORTER_PORT")
91  .toUInt()
92  : 9704;
93 
94 const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
95 
96 class DomainHandler : public QObject {
97  Q_OBJECT
98 public:
99  DomainHandler(QObject* parent = 0);
100 
101  void disconnect(QString reason);
102  void clearSettings();
103 
104  const QUuid& getUUID() const { return _uuid; }
105  void setUUID(const QUuid& uuid);
106 
107  Node::LocalID getLocalID() const { return _localID; }
108  void setLocalID(Node::LocalID localID) { _localID = localID; }
109 
110  QString getScheme() const { return _domainURL.scheme(); }
111  QString getHostname() const { return _domainURL.host(); }
112 
113  QUrl getErrorDomainURL(){ return _errorDomainURL; }
114  void setErrorDomainURL(const QUrl& url);
115 
116  int getLastDomainConnectionError() { return _lastDomainConnectionError; }
117 
118  const QHostAddress& getIP() const { return _sockAddr.getAddress(); }
119  void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); }
120 
121  const SockAddr& getSockAddr() const { return _sockAddr; }
122  void setSockAddr(const SockAddr& sockAddr, const QString& hostname);
123 
124  unsigned short getPort() const { return _sockAddr.getPort(); }
125  void setPort(quint16 port) { _sockAddr.setPort(port); }
126 
127  const QUuid& getConnectionToken() const { return _connectionToken; }
128  void setConnectionToken(const QUuid& connectionToken) { _connectionToken = connectionToken; }
129 
130  const QUuid& getAssignmentUUID() const { return _assignmentUUID; }
131  void setAssignmentUUID(const QUuid& assignmentUUID) { _assignmentUUID = assignmentUUID; }
132 
133  const QUuid& getPendingDomainID() const { return _pendingDomainID; }
134 
135  const QUuid& getICEClientID() const { return _iceClientID; }
136 
137  bool requiresICE() const { return !_iceServerSockAddr.isNull(); }
138  const SockAddr& getICEServerSockAddr() const { return _iceServerSockAddr; }
139  NetworkPeer& getICEPeer() { return _icePeer; }
140  void activateICELocalSocket();
141  void activateICEPublicSocket();
142 
143  bool isConnected() const { return _isConnected; }
144  void setIsConnected(bool isConnected);
145 
146  void setCanConnectWithoutAvatarEntities(bool canConnect);
147  bool canConnectWithoutAvatarEntities();
148 
149  bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_OVERTE; }
150  bool getInterstitialModeEnabled() const;
151  void setInterstitialModeEnabled(bool enableInterstitialMode);
152 
153  void connectedToServerless(std::map<QString, QString> namedPaths);
154 
155  void loadedErrorDomain(std::map<QString, QString> namedPaths);
156 
157  QString getViewPointFromNamedPath(QString namedPath);
158 
159  bool hasSettings() const { return !_settingsObject.isEmpty(); }
160  void requestDomainSettings();
161  const QJsonObject& getSettingsObject() const { return _settingsObject; }
162 
163  void setPendingPath(const QString& pendingPath) { _pendingPath = pendingPath; }
164  const QString& getPendingPath() { return _pendingPath; }
165  void clearPendingPath() { _pendingPath.clear(); }
166 
167  bool isSocketKnown() const { return !_sockAddr.getAddress().isNull(); }
168 
169  void softReset(QString reason);
170 
171  int getCheckInPacketsSinceLastReply() const { return _checkInPacketsSinceLastReply; }
172  bool checkInPacketTimeout();
173  void clearPendingCheckins() { _checkInPacketsSinceLastReply = 0; }
174 
175  void resetConfirmConnectWithoutAvatarEntities() {
176  _haveAskedConnectWithoutAvatarEntities = false;
177  }
178 
179  /*@jsdoc
180  * <p>The reasons that you may be refused connection to a domain are defined by numeric values:</p>
181  * <table>
182  * <thead>
183  * <tr>
184  * <th>Reason</th>
185  * <th>Value</th>
186  * <th>Description</th>
187  * </tr>
188  * </thead>
189  * <tbody>
190  * <tr>
191  * <td><strong>Unknown</strong></td>
192  * <td><code>0</code></td>
193  * <td>Some unknown reason.</td>
194  * </tr>
195  * <tr>
196  * <td><strong>ProtocolMismatch</strong></td>
197  * <td><code>1</code></td>
198  * <td>The communications protocols of the domain and your Interface are not the same.</td>
199  * </tr>
200  * <tr>
201  * <td><strong>LoginErrorMetaverse</strong></td>
202  * <td><code>2</code></td>
203  * <td>You could not be logged into the domain per your Directory Services login.</td>
204  * </tr>
205  * <tr>
206  * <td><strong>NotAuthorizedMetaverse</strong></td>
207  * <td><code>3</code></td>
208  * <td>You are not authorized to connect to the domain per your Directory Services login.</td>
209  * </tr>
210  * <tr>
211  * <td><strong>TooManyUsers</strong></td>
212  * <td><code>4</code></td>
213  * <td>The domain already has its maximum number of users.</td>
214  * </tr>
215  * <tr>
216  * <td><strong>TimedOut</strong></td>
217  * <td><code>5</code></td>
218  * <td>Connecting to the domain timed out.</td>
219  * </tr>
220  * <tr>
221  * <td><strong>LoginErrorDomain</strong></td>
222  * <td><code>2</code></td>
223  * <td>You could not be logged into the domain per your domain login.</td>
224  * </tr>
225  * <tr>
226  * <td><strong>NotAuthorizedDomain</strong></td>
227  * <td><code>6</code></td>
228  * <td>You are not authorized to connect to the domain per your domain login.</td>
229  * </tr>
230  * </tbody>
231  * </table>
232  * @typedef {number} Window.ConnectionRefusedReason
233  */
234  enum class ConnectionRefusedReason : uint8_t {
235  Unknown,
236  ProtocolMismatch,
237  LoginErrorMetaverse,
238  NotAuthorizedMetaverse,
239  TooManyUsers,
240  TimedOut,
241  LoginErrorDomain,
242  NotAuthorizedDomain
243  };
244 
245 public slots:
246  void setURLAndID(QUrl domainURL, QUuid domainID);
247  void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id);
248 
249  void processSettingsPacketList(QSharedPointer<ReceivedMessage> packetList);
250  void processICEPingReplyPacket(QSharedPointer<ReceivedMessage> message);
251  void processDTLSRequirementPacket(QSharedPointer<ReceivedMessage> dtlsRequirementPacket);
252  void processICEResponsePacket(QSharedPointer<ReceivedMessage> icePacket);
253  void processDomainServerConnectionDeniedPacket(QSharedPointer<ReceivedMessage> message);
254 
255  // sets domain handler in error state.
256  void setRedirectErrorState(QUrl errorUrl, QString reasonMessage = "", int reasonCode = -1, const QString& extraInfo = "");
257 
258  bool isInErrorState() { return _isInErrorState; }
259 
260 private slots:
261  void completedHostnameLookup(const QHostInfo& hostInfo);
262  void completedIceServerHostnameLookup();
263 
264 signals:
265  void domainURLChanged(QUrl domainURL);
266 
267  // NOTE: the emission of completedSocketDiscovery does not mean a connection to DS is established
268  // It means that, either from DNS lookup or ICE, we think we have a socket we can talk to DS on
269  void completedSocketDiscovery();
270 
271  void resetting();
272  void confirmConnectWithoutAvatarEntities();
273  void connectedToDomain(QUrl domainURL);
274  void disconnectedFromDomain();
275 
276  void iceSocketAndIDReceived();
277  void icePeerSocketsReceived();
278 
279  void settingsReceived(const QJsonObject& domainSettingsObject);
280  void settingsReceiveFail();
281 
282  void domainConnectionRefused(QString reasonMessage, int reasonCode, const QString& extraInfo);
283  void redirectToErrorDomainURL(QUrl errorDomainURL);
284  void redirectErrorStateChanged(bool isInErrorState);
285 
286  void limitOfSilentDomainCheckInsReached();
287 
288 private:
289  bool reasonSuggestsMetaverseLogin(ConnectionRefusedReason reasonCode);
290  bool reasonSuggestsDomainLogin(ConnectionRefusedReason reasonCode);
291  void sendDisconnectPacket();
292  void hardReset(QString reason);
293 
294  bool isHardRefusal(int reasonCode);
295 
296  QUuid _uuid;
297  Node::LocalID _localID;
298  QUrl _domainURL;
299  QUrl _errorDomainURL;
300  SockAddr _sockAddr;
301  QUuid _assignmentUUID;
302  QUuid _connectionToken;
303  QUuid _pendingDomainID; // ID of domain being connected to, via ICE or direct connection
304  QUuid _iceClientID;
305  SockAddr _iceServerSockAddr;
306  NetworkPeer _icePeer;
307  bool _isConnected { false };
308  bool _haveAskedConnectWithoutAvatarEntities { false };
309  bool _canConnectWithoutAvatarEntities { false };
310  bool _isInErrorState { false };
311  QJsonObject _settingsObject;
312  QString _pendingPath;
313  QTimer _settingsTimer;
314  mutable ReadWriteLockable _interstitialModeSettingLock;
315 #ifdef Q_OS_ANDROID
316  Setting::Handle<bool> _enableInterstitialMode{ "enableInterstitialMode", false };
317 #else
318  Setting::Handle<bool> _enableInterstitialMode { "enableInterstitialMode", false };
319 #endif
320 
321  QSet<QString> _domainConnectionRefusals;
322  bool _hasCheckedForAccessToken { false };
323  bool _hasCheckedForDomainAccessToken { false };
324  int _connectionDenialsSinceKeypairRegen { 0 };
325  int _checkInPacketsSinceLastReply { 0 };
326 
327  QTimer _apiRefreshTimer;
328 
329  std::map<QString, QString> _namedPaths;
330 
331  // domain connection error upon connection refusal.
332  int _lastDomainConnectionError{ -1 };
333 };
334 
335 const QString DOMAIN_SPAWNING_POINT { "/0, -10, 0" };
336 const QString DEFAULT_NAMED_PATH { "/" };
337 
338 #endif // hifi_DomainHandler_h
@ Unknown
Socket type unknown or not set.