Overte C++ Documentation
LimitedNodeList.h
1 //
2 // LimitedNodeList.h
3 // libraries/networking/src
4 //
5 // Created by Stephen Birarda on 2/15/13.
6 // Copyright 2013 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_LimitedNodeList_h
14 #define hifi_LimitedNodeList_h
15 
16 #include <assert.h>
17 #include <stdint.h>
18 #include <iterator>
19 #include <memory>
20 #include <set>
21 #include <unordered_map>
22 
23 #ifndef _WIN32
24 #include <unistd.h> // not on windows, not needed for mac or windows
25 #endif
26 
27 #include <QtCore/QElapsedTimer>
28 #include <QtCore/QPointer>
29 #include <QtCore/QReadWriteLock>
30 #include <QtCore/QSet>
31 #include <QtCore/QSharedMemory>
32 #include <QtCore/QSharedPointer>
33 #include <QtNetwork/QUdpSocket>
34 #include <QtNetwork/QHostAddress>
35 
36 #include <TBBHelpers.h>
37 
38 #include <DependencyManager.h>
39 #include <SharedUtil.h>
40 
41 #include "NetworkingConstants.h"
42 #include "Node.h"
43 #include "NLPacket.h"
44 #include "NLPacketList.h"
45 #include "PacketReceiver.h"
46 #include "ReceivedMessage.h"
47 #include "udt/ControlPacket.h"
48 #include "udt/PacketHeaders.h"
49 #include "udt/Socket.h"
50 #include "UUIDHasher.h"
51 
52 const int INVALID_PORT = -1;
53 
54 const quint64 NODE_SILENCE_THRESHOLD_MSECS = 10 * 1000;
55 
56 static const size_t DEFAULT_MAX_CONNECTION_RATE { std::numeric_limits<size_t>::max() };
57 
58 const char DEFAULT_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
59 
60 const char STUN_SERVER_HOSTNAME[] = "stun1.l.google.com";
61 const unsigned short STUN_SERVER_PORT = NetworkingConstants::STUN_SERVER_DEFAULT_PORT;
62 
63 const QString DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY = "domain-server.local-port";
64 const QString DOMAIN_SERVER_LOCAL_HTTP_PORT_SMEM_KEY = "domain-server.local-http-port";
65 const QString DOMAIN_SERVER_LOCAL_HTTPS_PORT_SMEM_KEY = "domain-server.local-https-port";
66 
67 const QHostAddress DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME = QHostAddress::LocalHost;
68 
69 const QString USERNAME_UUID_REPLACEMENT_STATS_KEY = "$username";
70 
71 using ConnectionID = int64_t;
72 const ConnectionID NULL_CONNECTION_ID { -1 };
73 const ConnectionID INITIAL_CONNECTION_ID { 0 };
74 
75 typedef std::pair<QUuid, SharedNodePointer> UUIDNodePair;
76 typedef tbb::concurrent_unordered_map<QUuid, SharedNodePointer, UUIDHasher> NodeHash;
77 
78 typedef quint8 PingType_t;
79 namespace PingType {
80  const PingType_t Agnostic = 0;
81  const PingType_t Local = 1;
82  const PingType_t Public = 2;
83  const PingType_t Symmetric = 3;
84 }
85 
86 class LimitedNodeList : public QObject, public Dependency {
87  Q_OBJECT
88  SINGLETON_DEPENDENCY
89 public:
90 
91  enum ConnectionStep {
92  LookupAddress = 1,
93  HandleAddress,
94  SendSTUNRequest,
95  SetPublicSocketFromSTUN,
96  SetICEServerHostname,
97  SetICEServerSocket,
98  SendICEServerQuery,
99  ReceiveDSPeerInformation,
100  SendPingsToDS,
101  SetDomainHostname,
102  SetDomainSocket,
103  SendDSCheckIn,
104  ReceiveDSList,
105  AddedAudioMixer,
106  SendAudioPing,
107  SetAudioMixerSocket,
108  SendAudioPacket,
109  ReceiveFirstAudioPacket
110  };
111 
112  Q_ENUM(ConnectionStep);
113 
114  enum ConnectReason : quint32 {
115  Connect = 0,
116  SilentDomainDisconnect,
117  Awake
118  };
119  Q_ENUM(ConnectReason);
120 
121  QUuid getSessionUUID() const;
122  void setSessionUUID(const QUuid& sessionUUID);
123  Node::LocalID getSessionLocalID() const;
124  void setSessionLocalID(Node::LocalID sessionLocalID);
125 
126  void setPermissions(const NodePermissions& newPermissions);
127  bool isAllowedEditor() const { return _permissions.can(NodePermissions::Permission::canAdjustLocks); }
128  bool getThisNodeCanRez() const { return _permissions.can(NodePermissions::Permission::canRezPermanentEntities); }
129  bool getThisNodeCanRezTmp() const { return _permissions.can(NodePermissions::Permission::canRezTemporaryEntities); }
130  bool getThisNodeCanWriteAssets() const { return _permissions.can(NodePermissions::Permission::canWriteToAssetServer); }
131  bool getThisNodeCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); }
132  bool getThisNodeCanReplaceContent() const { return _permissions.can(NodePermissions::Permission::canReplaceDomainContent); }
133  bool getThisNodeCanGetAndSetPrivateUserData() const { return _permissions.can(NodePermissions::Permission::canGetAndSetPrivateUserData); }
134  bool getThisNodeCanRezAvatarEntities() const { return _permissions.can(NodePermissions::Permission::canRezAvatarEntities); }
135  bool getThisNodeCanViewAssetURLs() const { return _permissions.can(NodePermissions::Permission::canViewAssetURLs); }
136 
137  quint16 getSocketLocalPort(SocketType socketType) const { return _nodeSocket.localPort(socketType); }
138  Q_INVOKABLE void setSocketLocalPort(SocketType socketType, quint16 socketLocalPort);
139 
140  QUdpSocket& getDTLSSocket();
141 #if defined(WEBRTC_DATA_CHANNELS)
142  const WebRTCSocket* getWebRTCSocket();
143 #endif
144 
145 
146  PacketReceiver& getPacketReceiver() { return *_packetReceiver; }
147 
148  virtual bool isDomainServer() const { return true; }
149  virtual QUuid getDomainUUID() const { assert(false); return QUuid(); }
150  virtual Node::LocalID getDomainLocalID() const { assert(false); return Node::NULL_LOCAL_ID; }
151  virtual SockAddr getDomainSockAddr() const { assert(false); return SockAddr(); }
152 
153  // use sendUnreliablePacket to send an unreliable packet (that you do not need to move)
154  // either to a node (via its active socket) or to a manual sockaddr
155  qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode);
156  qint64 sendUnreliablePacket(const NLPacket& packet, const SockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
157 
158  // use sendPacket to send a moved unreliable or reliable NL packet to a node's active socket or manual sockaddr
159  qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode);
160  qint64 sendPacket(std::unique_ptr<NLPacket> packet, const SockAddr& sockAddr, HMACAuth* hmacAuth = nullptr);
161 
162  // use sendUnreliableUnorderedPacketList to unreliably send separate packets from the packet list
163  // either to a node's active socket or to a manual sockaddr
164  qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const Node& destinationNode);
165  qint64 sendUnreliableUnorderedPacketList(NLPacketList& packetList, const SockAddr& sockAddr,
166  HMACAuth* hmacAuth = nullptr);
167 
168  // use sendPacketList to send reliable packet lists (ordered or unordered) to a node's active socket
169  // or to a manual sock addr
170  qint64 sendPacketList(std::unique_ptr<NLPacketList> packetList, const SockAddr& sockAddr);
171  qint64 sendPacketList(std::unique_ptr<NLPacketList> packetList, const Node& destinationNode);
172 
173  std::function<void(Node*)> linkedDataCreateCallback;
174 
175  size_t size() const { QReadLocker readLock(&_nodeMutex); return _nodeHash.size(); }
176 
177  SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
178  SharedNodePointer nodeWithLocalID(Node::LocalID localID) const;
179 
180  SharedNodePointer addOrUpdateNode(const QUuid& uuid, NodeType_t nodeType,
181  const SockAddr& publicSocket, const SockAddr& localSocket,
182  Node::LocalID localID = Node::NULL_LOCAL_ID, bool isReplicated = false,
183  bool isUpstream = false, const QUuid& connectionSecret = QUuid(),
184  const NodePermissions& permissions = DEFAULT_AGENT_PERMISSIONS);
185 
186  static bool parseSTUNResponse(udt::BasePacket* packet, QHostAddress& newPublicAddress, uint16_t& newPublicPort);
187  bool hasCompletedInitialSTUN() const { return _hasCompletedInitialSTUN; }
188 
189  const SockAddr& getLocalSockAddr() const { return _localSockAddr; }
190  const SockAddr& getPublicSockAddr() const { return _publicSockAddr; }
191  const SockAddr& getSTUNSockAddr() const { return _stunSockAddr; }
192 
193  void processKillNode(ReceivedMessage& message);
194 
195  int updateNodeWithDataFromPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer matchingNode);
196  NodeData* getOrCreateLinkedData(SharedNodePointer node);
197 
198  unsigned int broadcastToNodes(std::unique_ptr<NLPacket> packet, const NodeSet& destinationNodeTypes);
199  SharedNodePointer soloNodeOfType(NodeType_t nodeType);
200 
201  std::unique_ptr<NLPacket> constructPingPacket(const QUuid& nodeId, PingType_t pingType = PingType::Agnostic);
202  std::unique_ptr<NLPacket> constructPingReplyPacket(ReceivedMessage& message);
203 
204  static std::unique_ptr<NLPacket> constructICEPingPacket(PingType_t pingType, const QUuid& iceID);
205  static std::unique_ptr<NLPacket> constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID);
206 
207  void sendPeerQueryToIceServer(const SockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID);
208 
209  SharedNodePointer findNodeWithAddr(const SockAddr& addr);
210 
211  using value_type = SharedNodePointer;
212  using const_iterator = std::vector<value_type>::const_iterator;
213 
214  // Cede control of iteration under a single read lock (e.g. for use by thread pools)
215  // Use this for nested loops instead of taking nested read locks!
216  // This allows multiple threads (i.e. a thread pool) to share a lock
217  // without deadlocking when a dying node attempts to acquire a write lock
218  template<typename NestedNodeLambda>
219  void nestedEach(NestedNodeLambda functor,
220  int* lockWaitOut = nullptr,
221  int* nodeTransformOut = nullptr,
222  int* functorOut = nullptr) {
223  quint64 start, endTransform, endFunctor;
224 
225  start = usecTimestampNow();
226  std::vector<SharedNodePointer> nodes;
227  {
228  QReadLocker readLock(&_nodeMutex);
229  auto endLock = usecTimestampNow();
230  if (lockWaitOut) {
231  *lockWaitOut = (endLock - start);
232  }
233 
234  // Size of _nodeHash could change at any time,
235  // so reserve enough memory for the current size
236  // and then back insert all the nodes found
237  nodes.reserve(_nodeHash.size());
238  std::transform(_nodeHash.cbegin(), _nodeHash.cend(), std::back_inserter(nodes), [&](const NodeHash::value_type& it) {
239  return it.second;
240  });
241 
242  endTransform = usecTimestampNow();
243  if (nodeTransformOut) {
244  *nodeTransformOut = (endTransform - endLock);
245  }
246  }
247 
248  functor(nodes.cbegin(), nodes.cend());
249  endFunctor = usecTimestampNow();
250  if (functorOut) {
251  *functorOut = (endFunctor - endTransform);
252  }
253  }
254 
255  template<typename NodeLambda>
256  void eachNode(NodeLambda functor) {
257  QReadLocker readLock(&_nodeMutex);
258 
259  for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
260  functor(it->second);
261  }
262  }
263 
264  template<typename PredLambda, typename NodeLambda>
265  void eachMatchingNode(PredLambda predicate, NodeLambda functor) {
266  QReadLocker readLock(&_nodeMutex);
267 
268  for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
269  if (predicate(it->second)) {
270  functor(it->second);
271  }
272  }
273  }
274 
275  template<typename BreakableNodeLambda>
276  void eachNodeBreakable(BreakableNodeLambda functor) {
277  QReadLocker readLock(&_nodeMutex);
278 
279  for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
280  if (!functor(it->second)) {
281  break;
282  }
283  }
284  }
285 
286  template<typename PredLambda>
287  SharedNodePointer nodeMatchingPredicate(const PredLambda predicate) {
288  QReadLocker readLock(&_nodeMutex);
289 
290  for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
291  if (predicate(it->second)) {
292  return it->second;
293  }
294  }
295 
296  return SharedNodePointer();
297  }
298 
299  // This is unsafe because it does not take a lock
300  // Must only be called when you know that a read lock on the node mutex is held
301  // and will be held for the duration of your iteration
302  template<typename NodeLambda>
303  void unsafeEachNode(NodeLambda functor) {
304  for (NodeHash::const_iterator it = _nodeHash.cbegin(); it != _nodeHash.cend(); ++it) {
305  functor(it->second);
306  }
307  }
308 
309  void putLocalPortIntoSharedMemory(const QString key, QObject* parent, quint16 localPort);
310  bool getLocalServerPortFromSharedMemory(const QString key, quint16& localPort);
311 
312  const QMap<quint64, ConnectionStep> getLastConnectionTimes() const
313  { QReadLocker readLock(&_connectionTimeLock); return _lastConnectionTimes; }
314  void flagTimeForConnectionStep(ConnectionStep connectionStep);
315 
316  udt::Socket::StatsVector sampleStatsForAllConnections() { return _nodeSocket.sampleStatsForAllConnections(); }
317 
318  void setConnectionMaxBandwidth(int maxBandwidth) { _nodeSocket.setConnectionMaxBandwidth(maxBandwidth); }
319 
320  void setPacketFilterOperator(udt::PacketFilterOperator filterOperator) { _nodeSocket.setPacketFilterOperator(filterOperator); }
321  bool packetVersionMatch(const udt::Packet& packet);
322 
323  bool isPacketVerifiedWithSource(const udt::Packet& packet, Node* sourceNode = nullptr);
324  bool isPacketVerified(const udt::Packet& packet) { return isPacketVerifiedWithSource(packet); }
325  void setAuthenticatePackets(bool useAuthentication) { _useAuthentication = useAuthentication; }
326  bool getAuthenticatePackets() const { return _useAuthentication; }
327 
328  void setFlagTimeForConnectionStep(bool flag) { _flagTimeForConnectionStep = flag; }
329  bool isFlagTimeForConnectionStep() { return _flagTimeForConnectionStep; }
330 
331  static void makeSTUNRequestPacket(char* stunRequestPacket);
332 
333 #if (PR_BUILD || DEV_BUILD)
334  void sendFakedHandshakeRequestToNode(SharedNodePointer node);
335 #endif
336 
337  size_t getMaxConnectionRate() const { return _maxConnectionRate; }
338  void setMaxConnectionRate(size_t rate) { _maxConnectionRate = rate; }
339 
340  int getInboundPPS() const { return _inboundPPS; }
341  int getOutboundPPS() const { return _outboundPPS; }
342  float getInboundKbps() const { return _inboundKbps; }
343  float getOutboundKbps() const { return _outboundKbps; }
344 
345  void setDropOutgoingNodeTraffic(bool squelchOutgoingNodeTraffic) { _dropOutgoingNodeTraffic = squelchOutgoingNodeTraffic; }
346 
347  const std::set<NodeType_t> SOLO_NODE_TYPES = {
348  NodeType::AvatarMixer,
349  NodeType::AudioMixer,
350  NodeType::AssetServer,
351  NodeType::EntityServer,
352  NodeType::MessagesMixer,
353  NodeType::EntityScriptServer
354  };
355 
356 public slots:
357  void reset(QString reason);
358  void eraseAllNodes(QString reason);
359 
360  void removeSilentNodes();
361 
362  void updateLocalSocket();
363 
364  void startSTUNPublicSocketUpdate();
365  virtual void sendSTUNRequest();
366 
367  bool killNodeWithUUID(const QUuid& nodeUUID, ConnectionID newConnectionID = NULL_CONNECTION_ID);
368  void noteAwakening() { _connectReason = Awake; }
369 
370 private slots:
371  void sampleConnectionStats();
372 
373 signals:
374  // QUuid might be zero for non-sourced packet types.
375  void packetVersionMismatch(PacketType type, const SockAddr& senderSockAddr, const QUuid& senderUUID);
376 
377  void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
378  void nodeAdded(SharedNodePointer);
379  void nodeSocketUpdated(SharedNodePointer);
380  void nodeKilled(SharedNodePointer);
381  void nodeActivated(SharedNodePointer);
382 
383  void clientConnectionToNodeReset(SharedNodePointer);
384 
385  void localSockAddrChanged(const SockAddr& localSockAddr);
386  void publicSockAddrChanged(const SockAddr& publicSockAddr);
387 
388  void isAllowedEditorChanged(bool isAllowedEditor);
389  void canRezChanged(bool canRez);
390  void canRezTmpChanged(bool canRezTmp);
391  void canWriteAssetsChanged(bool canWriteAssets);
392  void canKickChanged(bool canKick);
393  void canReplaceContentChanged(bool canReplaceContent);
394  void canGetAndSetPrivateUserDataChanged(bool canGetAndSetPrivateUserData);
395  void canRezAvatarEntitiesChanged(bool canRezAvatarEntities);
396  void canViewAssetURLsChanged(bool canViewAssetURLs);
397 
398 protected slots:
399  void connectedForLocalSocketTest();
400  void errorTestingLocalSocket();
401 
402  void clientConnectionToSockAddrReset(const SockAddr& sockAddr);
403 
404  void processDelayedAdds();
405 
406 protected:
407  struct NewNodeInfo {
408  qint8 type;
409  QUuid uuid;
410  SockAddr publicSocket;
411  SockAddr localSocket;
412  NodePermissions permissions;
413  bool isReplicated;
414  Node::LocalID sessionLocalID;
415  QUuid connectionSecretUUID;
416  };
417 
418  LimitedNodeList(int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT);
419  LimitedNodeList(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
420  void operator=(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
421 
422  qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode,
423  const SockAddr& overridenSockAddr);
424 
425  void setLocalSocket(const SockAddr& sockAddr);
426 
427  bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet, Node* sourceNode = nullptr);
428  void processSTUNResponse(std::unique_ptr<udt::BasePacket> packet);
429 
430  void handleNodeKill(const SharedNodePointer& node, ConnectionID newConnectionID = NULL_CONNECTION_ID);
431 
432  void stopInitialSTUNUpdate(bool success);
433 
434  void sendPacketToIceServer(PacketType packetType, const SockAddr& iceServerSockAddr, const QUuid& clientID,
435  const QUuid& peerRequestID = QUuid());
436 
437  bool sockAddrBelongsToNode(const SockAddr& sockAddr);
438 
439  void addNewNode(NewNodeInfo info);
440  void delayNodeAdd(NewNodeInfo info);
441  void removeDelayedAdd(QUuid nodeUUID);
442  bool isDelayedNode(QUuid nodeUUID);
443 
444  NodeHash _nodeHash;
445  mutable QReadWriteLock _nodeMutex { QReadWriteLock::Recursive };
446  udt::Socket _nodeSocket;
447  QUdpSocket* _dtlsSocket { nullptr };
448  SockAddr _localSockAddr;
449  SockAddr _publicSockAddr;
450  SockAddr _stunSockAddr { SocketType::UDP, STUN_SERVER_HOSTNAME, STUN_SERVER_PORT };
451  bool _hasTCPCheckedLocalSocket { false };
452  bool _useAuthentication { true };
453 
454  PacketReceiver* _packetReceiver;
455 
456  NodePermissions _permissions;
457 
458  QPointer<QTimer> _initialSTUNTimer;
459 
460  int _numInitialSTUNRequests = 0;
461  bool _hasCompletedInitialSTUN = false;
462  quint64 _firstSTUNTime = 0;
463  quint64 _publicSocketUpdateTime = 0;
464 
465  mutable QReadWriteLock _connectionTimeLock { };
466  QMap<quint64, ConnectionStep> _lastConnectionTimes;
467  bool _areConnectionTimesComplete = false;
468 
469  template<typename IteratorLambda>
470  void eachNodeHashIterator(IteratorLambda functor) {
471  QWriteLocker writeLock(&_nodeMutex);
472  NodeHash::iterator it = _nodeHash.begin();
473 
474  while (it != _nodeHash.end()) {
475  functor(it);
476  }
477  }
478 
479  std::unordered_map<QUuid, ConnectionID> _connectionIDs;
480  quint64 _nodeConnectTimestamp{ 0 };
481  quint64 _nodeDisconnectTimestamp{ 0 };
482  ConnectReason _connectReason { Connect };
483 
484 private slots:
485  void flagTimeForConnectionStep(ConnectionStep connectionStep, quint64 timestamp);
486  void possiblyTimeoutSTUNAddressLookup();
487  void addSTUNHandlerToUnfiltered(); // called once STUN socket known
488 
489 private:
490  void fillPacketHeader(const NLPacket& packet, HMACAuth* hmacAuth = nullptr);
491 
492  mutable QReadWriteLock _sessionUUIDLock;
493  QUuid _sessionUUID;
494  using LocalIDMapping = tbb::concurrent_unordered_map<Node::LocalID, SharedNodePointer>;
495  LocalIDMapping _localIDMap;
496  Node::LocalID _sessionLocalID { 0 };
497  bool _flagTimeForConnectionStep { false }; // only keep track in interface
498 
499  size_t _maxConnectionRate { DEFAULT_MAX_CONNECTION_RATE };
500  size_t _nodesAddedInCurrentTimeSlice { 0 };
501  std::vector<NewNodeInfo> _delayedNodeAdds;
502 
503  int _inboundPPS { 0 };
504  int _outboundPPS { 0 };
505  float _inboundKbps { 0.0f };
506  float _outboundKbps { 0.0f };
507 
508  bool _dropOutgoingNodeTraffic { false };
509 
510  quint64 _sendErrorStatsTime { (quint64)0 };
511  static const quint64 ERROR_STATS_PERIOD_US { 1 * USECS_PER_SECOND };
512 };
513 
514 #endif // hifi_LimitedNodeList_h
quint8 NodeType_t
An 8-bit value identifying the type of a node - domain server, audio mixer, etc.
Definition: NodeType.h:22
Provides a QUdpSocket-style interface for using WebRTCDataChannels.
Definition: WebRTCSocket.h:31
SocketType
The types of network socket.
Definition: SocketType.h:22
@ UDP
UDP socket.