diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index aedf451924..a7fa068868 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -981,7 +981,7 @@ void OctreeServer::readConfiguration() { _settings = settingsSectionObject; // keep this for later if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) { - _statusHost = getLocalAddress().toString(); + _statusHost = getGuessedLocalAddress().toString(); } qDebug("statusHost=%s", qPrintable(_statusHost)); diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index 10dce38fbc..247eb66c99 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -32,7 +32,7 @@ static const uint64_t MAX_LOG_AGE_USECS = USECS_PER_SECOND * 3600; QString getLogRollerFilename() { QString result = FileUtils::standardPath(LOGS_DIRECTORY); - QHostAddress clientAddress = getLocalAddress(); + QHostAddress clientAddress = getGuessedLocalAddress(); QDateTime now = QDateTime::currentDateTime(); result.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); return result; diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index 81a58df730..bc4c1a1599 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -124,7 +124,7 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) { return dataStream; } -QHostAddress getLocalAddress() { +QHostAddress getGuessedLocalAddress() { QHostAddress localAddress; diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index cb5d0acc12..063a41a202 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -92,7 +92,7 @@ namespace std { } -QHostAddress getLocalAddress(); +QHostAddress getGuessedLocalAddress(); Q_DECLARE_METATYPE(HifiSockAddr); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index f236f9d596..4ee8a8bf49 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -77,7 +77,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short // check for local socket updates every so often const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; QTimer* localSocketUpdate = new QTimer(this); - connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr); + connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSocket); localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS); QTimer* silentNodeTimer = new QTimer(this); @@ -85,7 +85,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); // check the local socket right now - updateLocalSockAddr(); + updateLocalSocket(); // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket _nodeSocket.setPacketHandler( @@ -886,17 +886,66 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) { stunOccasionalTimer->start(STUN_IP_ADDRESS_CHECK_INTERVAL_MSECS); } -void LimitedNodeList::updateLocalSockAddr() { - HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort()); - if (newSockAddr != _localSockAddr) { +void LimitedNodeList::updateLocalSocket() { + // when update is called, if the local socket is empty then start with the guessed local socket + if (_localSockAddr.isNull()) { + setLocalSocket(HifiSockAddr { getGuessedLocalAddress(), _nodeSocket.localPort() }); + } - if (_localSockAddr.isNull()) { - qCDebug(networking) << "Local socket is" << newSockAddr; - } else { - qCDebug(networking) << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr; + // attempt to use Google's DNS to confirm that local IP + static const QHostAddress RELIABLE_LOCAL_IP_CHECK_HOST = QHostAddress { "8.8.8.8" }; + static const int RELIABLE_LOCAL_IP_CHECK_PORT = 53; + + QTcpSocket* localIPTestSocket = new QTcpSocket; + + connect(localIPTestSocket, &QTcpSocket::connected, this, &LimitedNodeList::connectedForLocalSocketTest); + connect(localIPTestSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorTestingLocalSocket(QAbstractSocket::SocketError))); + + // attempt to connect to our reliable host + localIPTestSocket->connectToHost(RELIABLE_LOCAL_IP_CHECK_HOST, RELIABLE_LOCAL_IP_CHECK_PORT); +} + +void LimitedNodeList::connectedForLocalSocketTest() { + auto localIPTestSocket = qobject_cast<QTcpSocket*>(sender()); + + if (localIPTestSocket) { + auto localHostAddress = localIPTestSocket->localAddress(); + + if (localHostAddress.protocol() == QAbstractSocket::IPv4Protocol) { + _hasTCPCheckedLocalSocket = true; + setLocalSocket(HifiSockAddr { localHostAddress, _nodeSocket.localPort() }); } - _localSockAddr = newSockAddr; + localIPTestSocket->deleteLater(); + } +} + +void LimitedNodeList::errorTestingLocalSocket(QAbstractSocket::SocketError error) { + auto localIPTestSocket = qobject_cast<QTcpSocket*>(sender()); + qDebug() << sender() << error; + + if (localIPTestSocket) { + + // error connecting to the test socket - if we've never set our local socket using this test socket + // then use our possibly updated guessed local address as fallback + if (!_hasTCPCheckedLocalSocket) { + setLocalSocket(HifiSockAddr { getGuessedLocalAddress(), _nodeSocket.localPort() }); + } + + localIPTestSocket->deleteLater();; + } +} + +void LimitedNodeList::setLocalSocket(const HifiSockAddr& sockAddr) { + if (sockAddr != _localSockAddr) { + + if (_localSockAddr.isNull()) { + qCInfo(networking) << "Local socket is" << sockAddr; + } else { + qCInfo(networking) << "Local socket has changed from" << _localSockAddr << "to" << sockAddr; + } + + _localSockAddr = sockAddr; emit localSockAddrChanged(_localSockAddr); } diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index de110c7e7f..be621647e3 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -225,7 +225,7 @@ public slots: void removeSilentNodes(); - void updateLocalSockAddr(); + void updateLocalSocket(); void startSTUNPublicSocketUpdate(); virtual void sendSTUNRequest(); @@ -247,6 +247,10 @@ signals: void isAllowedEditorChanged(bool isAllowedEditor); void canRezChanged(bool canRez); +protected slots: + void connectedForLocalSocketTest(); + void errorTestingLocalSocket(QAbstractSocket::SocketError error); + protected: LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0); LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton @@ -258,6 +262,8 @@ protected: const QUuid& connectionSecret = QUuid()); void collectPacketStats(const NLPacket& packet); void fillPacketHeader(const NLPacket& packet, const QUuid& connectionSecret = QUuid()); + + void setLocalSocket(const HifiSockAddr& sockAddr); bool isPacketVerified(const udt::Packet& packet); bool packetVersionMatch(const udt::Packet& packet); @@ -271,8 +277,6 @@ protected: void sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerRequestID = QUuid()); - - QUuid _sessionUUID; NodeHash _nodeHash; QReadWriteLock _nodeMutex; @@ -281,6 +285,7 @@ protected: HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; HifiSockAddr _stunSockAddr; + bool _hasTCPCheckedLocalSocket { false }; PacketReceiver* _packetReceiver;