diff --git a/src/comm/UDPLink.cc b/src/comm/UDPLink.cc index 36b2a1ab27f732ec7c378de4274af87759d4dbbe..58c32faf338fc2805931db2e5339d4d76281779e 100644 --- a/src/comm/UDPLink.cc +++ b/src/comm/UDPLink.cc @@ -68,27 +68,6 @@ static QString get_ip_address(const QString& address) return QString(""); } -static bool is_ip_local(const QHostAddress& add) -{ - // In simulation and testing setups the vehicle and the GCS can be - // running on the same host. This leads to packets arriving through - // the local network or the loopback adapter, which makes it look - // like the vehicle is connected through two different links, - // complicating routing. - // - // We detect this case and force all traffic to a simulated instance - // onto the local loopback interface. - // Run through all IPv4 interfaces and check if their canonical - // IP address in string representation matches the source IP address - foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) { - if (address == add) { - // This is a local address of the same host - return true; - } - } - return false; -} - static bool contains_target(const QList list, const QHostAddress& address, quint16 port) { foreach(UDPCLient* target, list) { @@ -112,6 +91,9 @@ UDPLink::UDPLink(SharedLinkConfigurationPointer& config) if (!_udpConfig) { qWarning() << "Internal error"; } + foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) { + _localAddress.append(QHostAddress(address)); + } moveToThread(this); } @@ -158,10 +140,36 @@ QString UDPLink::getName() const return _udpConfig->name(); } +bool UDPLink::_isIpLocal(const QHostAddress& add) +{ + // In simulation and testing setups the vehicle and the GCS can be + // running on the same host. This leads to packets arriving through + // the local network or the loopback adapter, which makes it look + // like the vehicle is connected through two different links, + // complicating routing. + // + // We detect this case and force all traffic to a simulated instance + // onto the local loopback interface. + // Run through all IPv4 interfaces and check if their canonical + // IP address in string representation matches the source IP address + // + // On Windows, this is a very expensive call only Redmond would know + // why. As such, we make it once and keep the list locally. If a new + // interface shows up after we start, it won't be on this list. + foreach (const QHostAddress &address, _localAddress) { + if (address == add) { + // This is a local address of the same host + return true; + } + } + return false; +} + void UDPLink::_writeBytes(const QByteArray data) { - if (!_socket) + if (!_socket) { return; + } // Send to all manually targeted systems foreach(UDPCLient* target, _udpConfig->targetHosts()) { // Skip it if it's part of the session clients below @@ -177,6 +185,7 @@ void UDPLink::_writeBytes(const QByteArray data) void UDPLink::_writeDataGram(const QByteArray data, const UDPCLient* target) { + //qDebug() << "UDP Out" << target->address << target->port; if(_socket->writeDatagram(data, target->address, target->port) < 0) { qWarning() << "Error writing to" << target->address << target->port; } else { @@ -193,10 +202,9 @@ void UDPLink::_writeDataGram(const QByteArray data, const UDPCLient* target) **/ void UDPLink::readBytes() { - if (_socket) { + if (!_socket) { return; } - QByteArray databuffer; while (_socket->hasPendingDatagrams()) { @@ -204,6 +212,7 @@ void UDPLink::readBytes() datagram.resize(_socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; + //-- Note: This call is broken in Qt 5.9.3 on Windows. It always returns a blank sender and 0 for the port. _socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); databuffer.append(datagram); //-- Wait a bit before sending it over @@ -217,7 +226,7 @@ void UDPLink::readBytes() // would trigger this. // Add host to broadcast list if not yet present, or update its port QHostAddress asender = sender; - if(is_ip_local(sender)) { + if(_isIpLocal(sender)) { asender = QHostAddress(QString("127.0.0.1")); } if(!contains_target(_sessionTargets, asender, senderPort)) { diff --git a/src/comm/UDPLink.h b/src/comm/UDPLink.h index 6e12c6af7bdef0ad4b2a951cc1ee2f5d1ef94e4e..e88782e04c884fcca9c2746bad1972f2b7eb4da8 100644 --- a/src/comm/UDPLink.h +++ b/src/comm/UDPLink.h @@ -184,6 +184,7 @@ private: bool _connect (void) override; void _disconnect (void) override; + bool _isIpLocal (const QHostAddress& add); bool _hardwareConnect (); void _restartConnection (); void _registerZeroconf (uint16_t port, const std::string& regType); @@ -194,11 +195,12 @@ private: DNSServiceRef _dnssServiceRef; #endif - bool _running; - QUdpSocket* _socket; - UDPConfiguration* _udpConfig; - bool _connectState; - QList _sessionTargets; + bool _running; + QUdpSocket* _socket; + UDPConfiguration* _udpConfig; + bool _connectState; + QList _sessionTargets; + QList _localAddress; };