From eb6b80133b5299ae8ad174a9e535dea7294f4d90 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 28 May 2015 13:17:48 -0700 Subject: [PATCH] immediately ping the ICE DS every 25ms --- libraries/networking/src/DomainHandler.cpp | 11 +++++-- libraries/networking/src/DomainHandler.h | 2 +- libraries/networking/src/NetworkPeer.cpp | 15 +++++++++- libraries/networking/src/NetworkPeer.h | 11 +++---- libraries/networking/src/NodeList.cpp | 34 ++++++++++++++++++---- libraries/networking/src/NodeList.h | 4 ++- 6 files changed, 60 insertions(+), 17 deletions(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 593f0b1597..e09dcb186b 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -31,12 +31,13 @@ DomainHandler::DomainHandler(QObject* parent) : _iceDomainID(), _iceClientID(), _iceServerSockAddr(), - _icePeer(), + _icePeer(this), _isConnected(false), _settingsObject(), _failedSettingsRequests(0) { - + // if we get a socket that make sure our NetworkPeer ping timer stops + connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer); } void DomainHandler::clearConnectionInfo() { @@ -309,6 +310,10 @@ void DomainHandler::processICEResponsePacket(const QByteArray& icePacket) { qCDebug(networking) << "Received network peer object for domain -" << packetPeer; _icePeer = packetPeer; - emit requestICEConnectionAttempt(); + // ask the peer object to start its ping timer + _icePeer.startPingTimer(); + + // emit our signal so the NodeList knows to send a ping immediately + emit icePeerSocketsReceived(); } } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 794a7793bb..0c1698f5ec 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -99,7 +99,7 @@ signals: void disconnectedFromDomain(); void iceSocketAndIDReceived(); - void requestICEConnectionAttempt(); + void icePeerSocketsReceived(); void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); diff --git a/libraries/networking/src/NetworkPeer.cpp b/libraries/networking/src/NetworkPeer.cpp index 69099c5201..a6ed7e44fb 100644 --- a/libraries/networking/src/NetworkPeer.cpp +++ b/libraries/networking/src/NetworkPeer.cpp @@ -17,7 +17,8 @@ #include "NetworkPeer.h" #include "BandwidthRecorder.h" -NetworkPeer::NetworkPeer() : +NetworkPeer::NetworkPeer(QObject* parent) : + QObject(parent), _uuid(), _publicSocket(), _localSocket(), @@ -66,6 +67,18 @@ void NetworkPeer::swap(NetworkPeer& otherPeer) { swap(_connectionAttempts, otherPeer._connectionAttempts); } +void NetworkPeer::softReset() { + // a soft reset should clear the sockets and reset the number of connection attempts + _localSocket.clear(); + _publicSocket.clear(); + + // stop our ping timer since we don't have sockets to ping anymore anyways + stopPingTimer(); + + _connectionAttempts = 0; +} + + QByteArray NetworkPeer::toByteArray() const { QByteArray peerByteArray; diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 92f271efa4..53b79c0126 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -28,7 +28,7 @@ const int UDP_PUNCH_PING_INTERVAL_MS = 25; class NetworkPeer : public QObject { Q_OBJECT public: - NetworkPeer(); + NetworkPeer(QObject* parent = 0); NetworkPeer(const QUuid& uuid, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket); // privatize copy and assignment operator to disallow peer copying @@ -36,11 +36,12 @@ public: NetworkPeer& operator=(const NetworkPeer& otherPeer); bool isNull() const { return _uuid.isNull(); } + bool hasSockets() const { return !_localSocket.isNull() && !_publicSocket.isNull(); } const QUuid& getUUID() const { return _uuid; } void setUUID(const QUuid& uuid) { _uuid = uuid; } - void reset(); + void softReset(); const HifiSockAddr& getPublicSocket() const { return _publicSocket; } virtual void setPublicSocket(const HifiSockAddr& publicSocket) { _publicSocket = publicSocket; } @@ -65,11 +66,11 @@ public: float getOutboundBandwidth(); // in kbps float getInboundBandwidth(); // in kbps - void startPingTimer(); - void stopPingTimer(); - friend QDataStream& operator<<(QDataStream& out, const NetworkPeer& peer); friend QDataStream& operator>>(QDataStream& in, NetworkPeer& peer); +public slots: + void startPingTimer(); + void stopPingTimer(); signals: void pingTimerTimeout(); protected: diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 0838ec18ec..bfd0c64b96 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -73,8 +73,11 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // send an ICE heartbeat as soon as we get ice server information connect(&_domainHandler, &DomainHandler::iceSocketAndIDReceived, this, &NodeList::handleICEConnectionToDomainServer); - // handle ICE signal from DS so connection is attempted immediately - connect(&_domainHandler, &DomainHandler::requestICEConnectionAttempt, this, &NodeList::handleICEConnectionToDomainServer); + // handle ping timeout from DomainHandler to establish a connection with auto networked domain-server + connect(&_domainHandler.getICEPeer(), &NetworkPeer::pingTimerTimeout, this, &NodeList::pingPunchForDomainServer); + + // send a ping punch immediately + connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer); // clear out NodeList when login is finished connect(&AccountManager::getInstance(), &AccountManager::loginComplete , this, &NodeList::reset); @@ -299,6 +302,7 @@ void NodeList::sendDomainServerCheckIn() { // we don't know our public socket and we need to send it to the domain server qCDebug(networking) << "Waiting for inital public socket from STUN. Will not send domain-server check in."; } else if (_domainHandler.getIP().isNull() && _domainHandler.requiresICE()) { + 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; @@ -472,8 +476,9 @@ void NodeList::handleDSPathQueryResponse(const QByteArray& packet) { } void NodeList::handleICEConnectionToDomainServer() { - if (_domainHandler.getICEPeer().isNull() - || _domainHandler.getICEPeer().getConnectionAttempts() >= MAX_ICE_CONNECTION_ATTEMPTS) { + // if we're still waiting to get sockets we want to ping for the domain-server + // then send another heartbeat now + if (!_domainHandler.getICEPeer().hasSockets()) { _domainHandler.getICEPeer().resetConnectionAttempts(); @@ -482,7 +487,24 @@ void NodeList::handleICEConnectionToDomainServer() { LimitedNodeList::sendHeartbeatToIceServer(_domainHandler.getICEServerSockAddr(), _domainHandler.getICEClientID(), _domainHandler.getICEDomainID()); - } else { + } +} + +void NodeList::pingPunchForDomainServer() { + // make sure if we're here that we actually still need to ping the domain-server + if (_domainHandler.getIP().isNull() && _domainHandler.getICEPeer().hasSockets()) { + + // check if we've hit the number of pings we'll send to the DS before we consider it a fail + const int NUM_DOMAIN_SERVER_PINGS_BEFORE_RESET = 2000 / UDP_PUNCH_PING_INTERVAL_MS; + + if (_domainHandler.getICEPeer().getConnectionAttempts() > 0 + && _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 + + _domainHandler.getICEPeer().softReset(); + handleICEConnectionToDomainServer(); + } + qCDebug(networking) << "Sending ping packets to establish connectivity with domain-server with ID" << uuidStringWithoutCurlyBraces(_domainHandler.getICEDomainID()); @@ -624,7 +646,7 @@ void NodeList::startNodeHolePunch(const SharedNodePointer& node) { void NodeList::handleNodePingTimeout() { SharedNodePointer senderNode = nodeWithUUID(qobject_cast(sender())->getUUID()); - if (senderNode) { + if (senderNode && !senderNode->getActiveSocket()) { pingPunchForInactiveNode(senderNode); } } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index d62715af8b..5e70b45b5f 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -64,7 +64,6 @@ public: void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); - void pingPunchForInactiveNode(const SharedNodePointer& node); public slots: void reset(); void sendDomainServerCheckIn(); @@ -77,6 +76,8 @@ private slots: void startNodeHolePunch(const SharedNodePointer& node); void handleNodePingTimeout(); + + void pingPunchForDomainServer(); 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); @@ -96,6 +97,7 @@ private: void processDomainServerAddedNode(const QByteArray& packet); void parseNodeFromPacketStream(QDataStream& packetStream); + void pingPunchForInactiveNode(const SharedNodePointer& node); NodeType_t _ownerType; NodeSet _nodeTypesOfInterest;